同时,需要在entry-server.js中实现服务器端路由逻辑,使用router.getMatchedComponents方法获取到当前路由匹配的组件,如果当前路由没有匹配到相应的组件,则reject到404页面,否则resolve整个app,用于Vue渲染虚拟DOM,并使用对应模板生成对应的HTML字符串。
- const createApp = require('./app');
- module.exports = context => {
- return new Promise((resolve, reject) => {
- // ...
- // 设置服务器端 router 的位置
- router.push(context.url);
- // 等到 router 将可能的异步组件和钩子函数解析完
- router.onReady(() => {
- const matchedComponents = router.getMatchedComponents();
- // 匹配不到的路由,执行 reject 函数,并返回 404
- if (!matchedComponents.length) {
- return reject('匹配不到的路由,执行 reject 函数,并返回 404');
- }
- // Promise 应该 resolve 应用程序实例,以便它可以渲染
- resolve(app);
- }, reject);
- });
- }
在服务端预拉取数据
在Vue服务端渲染,本质上是在渲染我们应用程序的"快照",所以如果应用程序依赖于一些异步数据,那么在开始渲染过程之前,需要先预取和解析好这些数据。服务端Web Server Frame作为代理服务器,在服务端对接口服务发起请求,并将数据拼装到全局Vuex状态中。
另一个需要关注的问题是在客户端,在挂载到客户端应用程序之前,需要获取到与服务器端应用程序完全相同的数据 - 否则,客户端应用程序会因为使用与服务器端应用程序不同的状态,然后导致混合失败。
目前较好的解决方案是,给路由匹配的一级子组件一个asyncData,在asyncData方法中,dispatch对应的action。asyncData是我们约定的函数名,表示渲染组件需要预先执行它获取初始数据,它返回一个Promise,以便我们在后端渲染的时候可以知道什么时候该操作完成。注意,由于此函数会在组件实例化之前调用,所以它无法访问this。需要将store和路由信息作为参数传递进去:
举个例子:
- <!-- Lung.vue -->
- <template>
- <div></div>
- </template>
- <script>
- export default {
- // ...
- async asyncData({ store, route }) {
- return Promise.all([
- store.dispatch('getA'),
- store.dispatch('myModule/getB', { root:true }),
- store.dispatch('myModule/getC', { root:true }),
- store.dispatch('myModule/getD', { root:true }),
- ]);
- },
- // ...
- }
- </script>
(编辑:ASP站长网)
|