app.use(express.static(path.resolve(process.cwd(), 'dist')));看起来大功告成,点击say hello也弹出了消息,细心的同学会发现根节点有一个data-server-rendered属性,这个属性有什么作用呢?
由于服务器已经渲染好了 HTML,我们显然无需将其丢弃再重新创建所有的 DOM 元素 。相反,我们需要"激活"这些静态的 HTML,然后使他们成为动态的(能够响应后续的数据变化) 。
如果检查服务器渲染的输出结果,应用程序的根元素上添加了一个特殊的属性:
<div id="app" data-server-rendered="true">data-server-rendered是特殊属性,让客户端 Vue 知道这部分 HTML 是由 Vue 在服务端渲染的,并且应该以激活模式进行挂载 。
路由的共享和同步完成了模板组件的共享之后,下面完成路由的共享,我们前面服务器使用的路由是*,接受任意URL,这允许所有URL请求交给Vue路由处理,进而完成客户端路由与服务端路由的复用 。
第一步:创建ROUTER实例为了实现复用,与createApp一样,我们创建一个createRouter.js
import Vue from 'vue';import Router from 'vue-router';import Home from './views/Home';import About from './views/About';Vue.use(Router)const routes = [{path: '/',name: 'Home',component: Home}, {path: '/about',name: 'About',component: About}];export default function createRouter() {return new Router({mode: 'history',routes})}在createApp.js中创建router
import Vue from 'vue';import App from './App';import createRouter from './createRouter';export default function createApp(context) {const router = createRouter(); // 创建 router 实例const app = new Vue({router, // 注入 router 到根 Vue 实例render: h => h(App)});return { router, app };};第二步:路由匹配router准备好了之后,修改server-entry.js,将请求的URL传递给router,使得在创建app的时候可以根据URL匹配到对应的路由,进而可知道需要渲染哪些组件
import createApp from './createApp';export default context => {// 因为有可能会是异步路由钩子函数或组件,所以我们将返回一个 Promise,// 以便服务器能够等待所有的内容在渲染前就已经准备就绪 。return new Promise((resolve, reject) => {const { app, router } = createApp();// 设置服务器端 router 的位置router.push(context.url)// onReady 等到 router 将可能的异步组件和钩子函数解析完router.onReady(() => {const matchedComponents = router.getMatchedComponents();// 匹配不到的路由,执行 reject 函数,并返回 404if (!matchedComponents.length) {return reject({code: 404});}// Promise 应该 resolve 应用程序实例,以便它可以渲染resolve(app)}, reject)})}修改server.js的路由,把url传递给renderer
app.get('*', function(req, res) {const context = {url: req.url};renderer.renderToString(context, (err, html) => {if (err) {console.log(err);res.send('500 server error');return;}res.send(html);})});为了测试,我们将App.vue修改为router-view
<template><div id="app"><router-link to="/">Home</router-link><router-link to="/about">About</router-link><router-view /></div></template>Home.vue
<template><div>Home Page</div></template>About.vue
<template><div>About Page</div></template>编译,运行,查看源代码

文章插图
点击路由并没有刷新页面,而是客户端路由跳转的,一切符合预期 。
数据模型的共享与状态同步前面我们简单的实现了服务端渲染,但是实际情况下,我们在访问页面的时候,还需要获取需要渲染的数据,并且渲染成HTML,也就是说,在渲染HTML之前,我们需要将所有数据都准备好,然后传递给renderer 。
一般情况下,在Vue中,我们将状态数据交给Vuex进行管理,当然,状态也可以保存在组件内部,只不过需要组件实例化的时候自己去同步数据 。
第一步:创建STORE实例首先第一步,与createApp类似,创建一个createStore.js,用来实例化store,同时提供给客户端和服务端使用
import Vue from 'vue';import Vuex from 'vuex';import {fetchItem} from './api';Vue.use(Vuex);export default function createStore() {return new Vuex.Store({state: {item: {}},actions: {fetchItem({ commit }, id) {return fetchItem(id).then(item => {commit('setItem', item);})}},mutations: {setItem(state, item) {Vue.set(state.item, item);}}})}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 又是槐花飘香时阅读启示,槐花飘香阅读理解-
- 4s店|好的服务必定是超前的(4):预见性行动
- 什么人适合学法学?
- 服务器|《糖豆人》免费后匹配系统崩了 E宝自嘲变土豆人
- 服务器|理想L9预订多火爆?网友:第一次见抢46万的车把服务器抢崩溃
- 高通|曝高通骁龙8+下放中端:性能彻底甩开对手
- 服务器|理想L9预定太火爆!服务器直接挤爆了
- 割韭菜是什么意思通俗,割韭菜的韭菜怎么理解-
- 一文理解SpringBean生命周期之PostConstruct、PreDestroy详解
- Mac下的nginx服务器安装本地的https环境
