vue.js数据预取问题

时间:2018-03-11 14:36:24

标签: vue.js vue-component vue-router vuex vue-ssr

我正按照指南https://ssr.vuejs.org/en/data.html构建应用。

所以我有结构:

server.js

    const express = require('express');
    const server = express();
    const fs = require('fs');
    const path = require('path');
    const bundle = require('./dist/server.bundle.js');
    const renderer = require('vue-server-renderer').createRenderer({
        template: fs.readFileSync('./index.html', 'utf-8')
    });
server.get('*', (req, res) => {

    bundle.default({url: req.url}).then((app) => {

        const context = {
            title: app.$options.router.history.current.meta.title
        };

        renderer.renderToString(app, context, function (err, html) {
            console.log(html)
            if (err) {
                if (err.code === 404) {
                    res.status(404).end('Page not found')
                } else {
                    res.status(500).end('Internal Server Error')
                }
            } else if (context.title === '404') {
                res.status(404).end(html)
            } else {
                res.end(html)
            }
        });
    }, (err) => {
        res.status(404).end('Page not found')
    });

});
server.listen(8080);

store.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex);

import axios from 'axios';
export function createStore() {
        return new Vuex.Store({
            state: {
                articles: [

                ]
            },
            actions: {
                fetchArticlesList({commit}, params) {
                    return axios({
                        method: 'post',
                        url: 'http://test.local/api/get-articles',
                        data: {
                            start: params.start,
                            limit: params.limit,
                            language: params.language
                        }
                    })
                        .then((res) => {
                            commit('setArticles', res.data.articles);
                        });
                },
            },
            mutations: {
                setArticles(state, articles) {
                    state.articles = articles;
                }
            }
        })
    }

router.js

import BlogEn from '../components/pages/BlogEn.vue';
import Vue from 'vue';
import Router from 'vue-router';
export function createRouter() {
    return new Router({
        mode: 'history',
        routes: [
            {
                path: '/en/blog',
                name: 'blogEn',
                component: BlogEn,
                meta: {
                    title: 'Blog',
                    language: 'en'
                }
            },
    });
}

main.js

import Vue from 'vue'
import App from './App.vue'
import {createRouter} from './router/router.js'
import {createStore} from './store/store.js'
import {sync} from 'vuex-router-sync'

export function createApp() {
    const router = createRouter();
    const store = createStore();

    sync(store, router);

    const app = new Vue({
        router,
        store,
        render: h => h(App)
    });

    return {app, router, store};
}

入门server.js

import {createApp} from './main.js';

export default context => {
    return new Promise((resolve, reject) => {
        const { app, router, store } = createApp()

        router.push(context.url)

        router.onReady(() => {
            const matchedComponents = router.getMatchedComponents()
            if (!matchedComponents.length) {
                return reject({ code: 404 })
            }
            Promise.all(matchedComponents.map(Component => {
                // This code not from manual because i want load this in my content-component
                if (Component.components['content-component'].asyncData) {
                    return Component.components['content-component'].asyncData({
                        store,
                        route: router.currentRoute
                    })
                }
                // This code from manual
                // if (Component.asyncData) {
                //     return Component.asyncData({
                //         store,
                //         route: router.currentRoute
                //     })
                // }
            })).then(() => {
                context.state = store.state
                resolve(app)
            }).catch(reject)
        }, reject)
    })
}

入门client.js

import Vue from 'vue'
import {createApp} from './main.js';

const {app, router, store} = createApp();
if (window.__INITIAL_STATE__) {
    store.replaceState(window.__INITIAL_STATE__)
}
router.onReady(() => {

    router.beforeResolve((to, from, next) => {
        const matched = router.getMatchedComponents(to)
        const prevMatched = router.getMatchedComponents(from)
        let diffed = false
        const activated = matched.filter((c, i) => {
            return diffed || (diffed = (prevMatched[i] !== c))
        })

        if (!activated.length) {
            return next()
        }

        Promise.all(activated.map(c => {
            if (c.asyncData) {
                return c.asyncData({ store, route: to })
            }
        })).then(() => {


            next()
        }).catch(next)
    })

    app.$mount('#app')
});

零件

BlogEn.vue

<template>
    <div>
        <header-component></header-component>
        <div class="content" id="content">
            <content-component></content-component>
            <div class="buffer"></div>
        </div>
        <footer-component></footer-component>
    </div>
</template>
<script>
    import Header from '../blanks/Header.vue';
    import Content from '../pages/content/blog/Content.vue';
    import Footer from '../blanks/Footer.vue';
    export default {
        data() {
            return {

            };
        },
        components: {
            'header-component': Header,
            'breadcrumbs-component' : Breadcrumbs,
            'content-component' : Content,
            'footer-component': Footer
        },
    };
</script>

Content.vue

<template>
    <section class="blog">
        <div v-for="item in articles">
            <p>{{ item.title }}</p>
        </div>
    </section>
</template>
<script>
    export default {
        data() {
            let obj = {
            };
            return obj;
        },
        asyncData({store, route}) {
            let params = {
                start: 0,
                limit: 2,
                language: 'ru'
            };
            return store.dispatch('fetchArticlesList', params);
        },
        computed: {
            articles () {
                return this.$store.state.articles;
            }
        }
    };
</script>

当我加载page / en / blog时 浏览器中的我的DOM看起来像

<div id="app">
<div id="content" class="content">
    <!-- There is should be loop content -->
    <div class="buffer"></div>
</div>
<footer></footer>
</div>

但是!当我查看服务器发送给我的源代码页和html时,可以。

<div id="app">
<div id="content" class="content">
    <section class="blog">
        <div><p>Article Title</p></div>
        <div><p>Article Title 2</p></div>
    </section>
    <div class="buffer"></div>
</div>
<footer></footer>
</div>

不是全部。我的应用程序中有其他页面,我不在这里显示。当我移动任何页面并在DOM完成后转到“/ en / blog”。

这里有什么问题?

0 个答案:

没有答案