传统的服务端渲染
传统的服务端渲染是路由在服务端,请求的页面都是服务端拼接好数据后,写入响应体中返回给客户端,每次路由的改变都会重新请求页面,刷新数据。
vue的SSR
专业名词:同构渲染
工作原理:首屏渲染由服务端完成需要的数据拼接返回给客户端一个html文件,html是通过webpack打包生成的,包括其余的资源(不需要在首次渲染的时候立刻请求的,目的是尽量缩短首屏的渲染时间)
客户端渲染
服务器返回的html文件中不会有body的内容,是一个空的ID为app的节点,搜索引擎就是在第一次解析页面的时候分析文档的内容,这里面什么都没有,肯定不利于SEO.
使用nuxt进行同构渲染
nuxt有自带路由,但是这次它的路由满足不要我们的需求,所以我们自己写路由
插件也需要在这里注册哦!
// nuxt.config.js
/**
* Nuxt.js 配置文件
*/
module.exports = {
router: {
linkActiveClass: 'active',
// 自定义路由表规则
extendRoutes (routes, resolve) {
// 清除 Nuxt.js 基于 pages 目录默认生成的路由表规则
routes.splice(0)
routes.push(...[
{
path: '/',
component: resolve(__dirname, 'pages/layout/'),
children: [
{
path: '', // 默认子路由
name: 'home',
component: resolve(__dirname, 'pages/home/')
},
{
path: '/login',
name: 'login',
component: resolve(__dirname, 'pages/login/')
}
]
}
])
}
},
server: {
host: '0.0.0.0',
port: 3000
},
// 注册插件
plugins: [
'~/plugins/request.js',
'~/plugins/dayjs.js'
]
}
nuxtServerInt 在store的action中使用
export const actions = {
// nuxtServerInit 是一个特殊的 action 方法
// 这个 action 会在服务端渲染期间自动调用
// 作用:初始化容器数据,传递数据给客户端使用
nuxtServerInit ({ commit }, { req }) {
let user = null
// 如果请求头中有 Cookie
if (req.headers.cookie) {
// 使用 cookieparser 把 cookie 字符串转为 JavaScript 对象
const parsed = cookieparser.parse(req.headers.cookie)
try {
user = JSON.parse(parsed.user)
} catch (err) {
// No valid cookie found
}
}
// 提交 mutation 修改 state 状态
commit('setUser', user)
}
}
middleware在在创建文件之后,直接在.vue中使用
在.vue 的 asyncData 中书写获取数据的代码
async asyncData ({ query }) {
const page = Number.parseInt(query.page|| 1)
const limit = 20
const tab = query.tab || 'global_feed'
const tag = query.tag
const loadArticles = tab === 'global_feed'
? getArticles
: getYourFeedArticles
const [ articleRes, tagRes ] = await Promise.all([
loadArticles({
limit,
offset: (page - 1) * limit,
tag
}),
getTags()
])
const { articles, articlesCount } = articleRes.data
const { tags } = tagRes.data
articles.forEach(article => article.favoriteDisabled = false)
return {
articles, // 文章列表
articlesCount, // 文章总数
tags, // 标签列表
limit, // 每页大小
page, // 页码
tab, // 选项卡
tag // 数据标签
}
},
在.vue 的 watchQuery 中书写监听变量变化的代码
watchQuery: ['page', 'tag', 'tab'],
点赞功能要限制次数
article.favoriteDisabled = true
客户端持久化用户信息
// 仅在客户端加载 js-cookie 包
const Cookie = process.client ? require('js-cookie') : undefined
methods: {
async onSubmit () {
try {
// 提交表单请求登录
const { data } = this.isLogin
? await login({
user: this.user
})
: await register({
user: this.user
})
// console.log(data)
// TODO: 保存用户的登录状态
this.$store.commit('setUser', data.user)
// 为了防止刷新页面数据丢失,我们需要把数据持久化
Cookie.set('user', data.user)
// 跳转到首页
this.$router.push('/')
} catch (err) {
// console.log('请求失败', err)
this.errors = err.response.data.errors
}
}
}
在store中做好服务端的持久化
const cookieparser = process.server ? require('cookieparser') : undefined
export const actions = {
// nuxtServerInit 是一个特殊的 action 方法
// 这个 action 会在服务端渲染期间自动调用
// 作用:初始化容器数据,传递数据给客户端使用
nuxtServerInit ({ commit }, { req }) {
let user = null
// 如果请求头中有 Cookie
if (req.headers.cookie) {
// 使用 cookieparser 把 cookie 字符串转为 JavaScript 对象
const parsed = cookieparser.parse(req.headers.cookie)
try {
user = JSON.parse(parsed.user)
} catch (err) {
// No valid cookie found
}
}
// 提交 mutation 修改 state 状态
commit('setUser', user)
}
}
相当于客户端和服务端都要持久化一份数据