vue服务端渲染之nuxtjs
前言
本篇主要针对nuxtjs中的一些重要概念整理和代码实现!
在学习vue服务端渲染之前,先搞清楚几个概念:
- 什么是客户端渲染(CSR)
- 什么是服务端渲染(SSR)
- CSR和SSR有什么异同
客户端渲染(CSR):当用户在浏览器中输入网址,打开网页,此时的页面只有样式和一些html代码构成的空壳页面,并没有数据。这就需要我们通过执行js代码,请求相关数据,请求到数据之后,通过模板(vue),将这些数据渲染到页面,最终呈现给用户完整的页面。
服务端渲染(SSR):当用户在浏览器中输入网址,打开网页,此时的后端会根据请求的网址,拿到相关页面并将数据填入到页面,完成页面的渲染,最后将完整的页面返回给客户端(浏览器),呈现到用户面前。
利弊:客户端渲染,就是现在非常流行的前后分离的开发模式,极大程度的减轻后端压力,但是对SEO不友好;服务端渲染对SEO友好,但是对后端以及服务器的性能要求较高。
正文:
先用node实现简易的服务端渲染:
const Vue = require('vue');
const server = require('express')();server.get('/',(req,res)=>{//创建 Vue 实例const app = new Vue({template:`<div>hello vue SSR!</div>`})// 创建 renderer 没下载的需要手动下载 npm i vue-server-renderer --save改包用于vue的服务端渲染const renderer = require('vue-server-renderer').createRenderer(); renderer.renderToString(app).then(html=>{res.send(`<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title></head><body>${html}</body></html>`)}).catch(err=>{console.log(err)})
})server.listen(8001)
检查源代码:
下面使用nuxjs来构建项目!
首先,使用nuxt提供的脚手架( create-nuxt-app)构建项目,根据提示一步一步操作。
主要注意俩点:1.Choose custom server framework,选择服务端渲染的框架,我们这里选择的是express
2.Choose rendering mode 这个选项可以选择SSR和Single Page APP,因为我们需要构建服务端渲染多页面项目,所以这里选择SSR
下面就是项目创建完成后的目录结构:
目录结构:
- assets::资源目录,用于组织未编译的静态资源(css文件、图标等)
- components: 组件目录,用于组织应用的vue组件,这些组件不会像页面组件(pages中的组件)那样有 asyncData 方法的特性
- layouts:布局目录,用于组织应用的布局组件,若无额外配置,该目录不能被重命名
- middleware:中间件目录,用于存放应用的中间件
- pages: 页面目录,用于组织应用的路由及视图,Nuxt.js 框架读取该目录下所有的 .vue文件并自动生成对应的路由配置,若无额外配置,该目录不能被重命名
- plugins:插件目录,用于组织那些需要在 根vue.js应用实例化之前需要运行的JavaScript插件
- server:服务器目录,用于服务端渲染
- static:静态文件目录,用于存放应用的静态文件,此类文件不会被 Nuxt.js 调用 Webpack 进行构建编译处理。服务器启动的时候,该目录下的文件会映射至应用的根路径 / 下(/static/robots.txt 映射至 /robots.txt),若无额外配置,该目录不能被重命名
- store:store目录,用于组织应用的 Vuex状态树 文件,若无额外配置,该目录不能被重命名
- nuxt.config.js:用于组织 Nuxt.js 应用的个性化配置,以便覆盖默认配置,若无额外配置,该目录不能被重命名
- package.json:用于描述应用的依赖关系和对外暴露的脚本接口,该文件不能被重命名
项目跑起来:
检查源码,页面的所有数据都能够看到。
接下来正式学习nuxt,主要分为3部分:
- 生命周期
- 路由
- vuex状态树
一、生命周期(钩子函数)
- nuxtServerInit => 服务器初始化
- middleware => 中间件
- validate() => 参数校验
- asyncData()和fetch() => 异步数据处理
- render => 客户端渲染
- beforeCreate和created => 这俩个钩子服务端和客户端都存在,可以拿到服务端的上下文以及组件本身
下面具体使用这些生命周期:
1.nuxtServerInit
在store目录中新建index.js:
export const actions = {nuxtServerInit(store, context){console.log('我是nuxtServerInit生命周期!', store, context)}
}
项目跑起来后,在终端会打印相关信息:
2.middleware
middleware中间件可以在配置文件中、布局页面、页面组件中使用。
在nuxt.config.js配置文件中,将middleware写进router配置中,可以进行全局的导航守卫:
module.exports = {mode: 'universal',router: {middleware: 'isLogin'},...
接下来在middleware目录中新建isLogin.js文件:
export default (context) => {console.log('我是全局守卫')
}
打印:
在布局页面中使用中间件,在layout目录下的default.vue中:
<script>export default {// middleware: 'isLogin',middleware(){console.log('我是布局页面的中间件!')},}
</script>
在页面组件内中间件可以直接写外部之前定义的中间件,也可以用中间件钩子!
同样,在页面组件中,pages目录下的index.vue中:
<script>export default {// middleware: 'isLogin',middleware(){console.log('我是页面组件的中间件!')},}
</script>
通过打印的顺序可以看出,中间件的执行顺序是:nuxt.config.js文件 => 布局文件 => 页面文件,所有中间件函数的参数中,都能拿到服务端的上下文信息context。
3.validate()
validate()需要定义在页面组件内,即pages目录下的页面,可以用来进行参数校验,拦截是否可以进入该页面。具体实现,在pages/index.vue中:
//js 代码
export default {// middleware: 'isLogin',middleware(){console.log('我是页面组件的中间件!')},validate(context){const {params, query} = context;//对传过来的params和query进行校验//...console.log('我是页面validate参数校验')return true; // 校验通过,校验失败返回false,进入到404页面},components: {Logo}
}
4.asyncData()和fetch()
这俩个钩子也是在页面组件中使用,pages/index.vue中:
asyncData(context){// 异步读取数据,处理相关业务逻辑console.log('我是asyncData')//最后返回数据return {a: 1};},fetch(context){// 异步读取数据,处理相关业务逻辑,将数据提交给vuexconsole.log('我是fetch')},
5.beforeCreate()和created()
在pages/index.vue中:
...
fetch(context){// 异步读取数据,处理相关业务逻辑,将数据提交给vuexconsole.log('我是fetch')},beforeCreate() {console.log('我是beforeCreate')},created() {console.log('我是create')},
...
客户端:
服务端:
二、路由(约定式、自定义)
1.约定式路由:依据pages目录结构自动生成 vue-router模块的路由配置。
1>基础路由:
在layouts目录中的default.vue:
<template><div><!-- 声明式跳转:nuxt-link跟vue中的router-link一样,负责路由跳转 --><nuxt-link to="/">首页</nuxt-link><nuxt-link to="/tabA">tabA</nuxt-link><nuxt-link to="/tabB">tabB</nuxt-link><!-- 展示区,跟vue中的router-view一样 --><nuxt/></div>
</template>
效果:
nuxt自动生成的路由为:
router: {routes: [{name: 'index',path: '/',component: 'pages/index.vue'},{name: 'tabA',path: '/tabA',component: 'pages/tabA.vue'},{name: 'tabB',path: '/tabB',component: 'pages/tabB.vue'}]
}
2>动态路由
在 Nuxt.js 里面定义带参数的动态路由,需要创建对应的以下划线“_”作为前缀的 Vue 文件 或 目录。
pages/tabA.vue:
<template><div><h3>tabA</h3><!-- 俩种路由传参方式 --><nuxt-link to="/tabA/1?a=tabA1">tabA动态路由1</nuxt-link><!-- name: 'tabA-id',这里-id必须是tabA目录下的_id.vue的名称,且将 _ 改为 - --><nuxt-link :to="{name: 'tabA-id', params:{id: 2}, query:{a: 'tabA2'}}">tabA动态路由2</nuxt-link><!-- 子路由的展示区 --><nuxt/></div>
</template>
pages/tabA/_id.vue:
<template><div><h3>我是tabA的动态路由页</h3></div>
</template>
效果:
这里会发现一个问题,路由为/tabA的时候,也打开了动态路由页,这是因为当路由为tabA时,会发现它下面还有子路由,由于没有指定默认的页面,因此会找到一个子路由进行渲染。为了解决这个问题,可以在tabA目录下新建一个index.vue。
tabA/index.vue:
<template><h3>我是动态子路由默认页</h3>
</template>
此时nuxt自动生成的路由信息为:
router: {routes: [{name: 'index',path: '/',component: 'pages/index.vue'},{name: 'tabA-id',path: '/tabA/:id',component: 'pages/tabA/_id.vue'},... ]
}
3>嵌套路由
创建内嵌子路由,你需要添加一个 Vue 文件,同时添加一个与该文件同名的目录用来存放子视图组件。
在tabA目录下新建tabC目录和tabC.vue
tabA/tabC.vue:
<template><div><!-- 子路由展示区 --><nuxt></nuxt></div>
</template>
tabA/tabC/index.vue:
<template><div><h3>我是tabC</h3></div>
</template>
从上图可以看到俩种颜色的区域,是俩级展示区,通常我们一个页面只需要一个展示区,因此需要改一下项目的目录结构:
在pages目录下的页面为一级展示区,其中有tabA、tabB,接下来将tabA目录下的页面也设置成一级展示区。将tabA.vue内容拷贝至tabA目录下的index.vue中,并删除tabA.vue。
2、扩展路由
nuxt中支持声明式路由,同样也支持自定义路由,根据路由渲染指定的视图,需要在nuxt.config.js中配置:
router: {extendRoutes(routes, resolve){routes.push({name: 'tabD',path: '/tabD',component: resolve(__dirname, 'pages/extendTabD.vue')})}},
在pages中新建extendTabD.vue:
pages/extendTabD.vue:
<template><div><h3>我是扩展路由tabD</h3></div>
</template>
在layouts/default.vue中增加链接:
<nuxt-link to="/tabD">tabD</nuxt-link>
3、路由过渡动画
1>全局过渡动画:
transition.css:
/* 路由统一动效 *//* 动画形式 */
.page-enter-active, .page-leave-active{transition: opacity .5s;
}/* 入 退 */
.page-enter, .page-leave-active{opacity: 0;
}
nuxt.config.js:
/*** Global CSS*/css: ['assets/css/transition.css'],
2>局部过渡动画
extendTabD.vue:
<template><div><h3>我是扩展路由tabD</h3></div>
</template><script>export default {name: "extendTabD",transition: 'tabd'}
</script><style scoped>.tabd-enter-active, .tabd-leave-active{transition: .5s ease all;}.tabd-enter, .tabd-leave-active{margin-left: -1000px;}
</style>
4、路由守卫
- 前置
- 后置
- 组件内部
1>前置:
全局守卫:
- 在nuxt.config.js的router内引入middleware
- 在layouts文件中定义middleware
- 在插件中定义前置全局守卫,beforeEach()
组件独享守卫:
- 在页面中引入middleware或middleware()
- 跟vue-router一样的组件内部钩子函数,比如:beforeRouteEnter
2>后置:
在插件中定义后置全局守卫,afterEach()
具体实现:
全局守卫:
a.借助middleware实现前置的路由守卫,在生命周期的middleware中已经基本实现。
middleware/isLogin.js:
export default (context) => {console.log('我是全局守卫')const {redirect} = contextredirect('/tabD') // 利用redirect()页面重定向
}
b.借助插件实现前置、后置全局守卫:
plugins/router.js
export default ({app, redirect})=>{//app == vue实例//全局前置守卫,进入的页面不是tabA的页面,都会重定向到tabAapp.router.beforeEach((to, from, next)=>{if(to.name == 'tabA'){next()}else{redirect({name: 'tabA'})}});//全局后置守卫app.router.afterEach((to, from)=>{console.log('我是后置守卫')})
}
nuxt.config.js中配置plugins:
plugins: ['~/plugins/router.js'],
组件内守卫:
extendTabD.vue:
<template><div><h3>我是扩展路由tabD</h3></div>
</template><script>export default {name: "extendTabD",transition: 'tabd',beforeRouteEnter(to, from, next){alert('haha');}}
</script>
三、vuex状态树
nuxt中集成了vuex,因此我们在项目中不需要下载引入,而是按照约定使用:
nuxt会尝试找到 src 目录(默认是应用根目录)下的 store
目录,如果该目录存在,它将做以下的事情:
- 引入vuex模块
- 将vuex模块加到vendors构建配置中
- 设置vue根实例的store配置项
nuxt中的vuex使用方式跟vue中大同小异,除了不需要手动引入之外,在模块化中,store目录下的每个子模块(除了根模块index.js),都会被转换成为状态树指定命名的子模块,其它使用方式跟vue项目中的vuex基本相同。
store/index.js:
const state = ()=>({})
const mutations = {}const actions = {}
export default {state,mutations,actions
}
store/user.js:
const state = () => ({isLogin: false
})const mutations = {change_Login(state, isLogin) {state.isLogin = isLogin}
}const actions = {changeLogin({commit},isLogin) {commit('change_Login', isLogin)}
}
export default {namespaced: true,state,mutations,actions
}
pages/tabB.vue:
<template><div><h3>tabB</h3><h4>登录状态:{{isLogin ? '已登录' : '未登录'}}</h4></div>
</template><script>import { mapState } from 'vuex';export default {name: "TabB",computed:{...mapState({isLogin: state => state.user.isLogin})},created() {setTimeout(()=>{this.$store.dispatch('user/changeLogin', true)}, 1000)}}
</script>
效果:一秒后,登录状态从“未登录”变为“已登录”。
以上就是我对nuxt学习过程中一些重要概念的理解和实践,有什么不足欢迎评论指正!
脚踏实地行,海阔天空飞
vue服务端渲染之nuxtjs相关推荐
- Vue 服务端渲染(SSR)、Nuxt.js - 从入门到实践
前言 10月初有幸接到公司官网改版需求,要求采用服务端渲染模式对原网站进行seo优化. 由于团队一直使用的vue技术栈,所以我第一时间想到的就是采用vue 服务端渲染(SSR)来实现该需求,即能减少团 ...
- vue服务端渲染——基础
文章目录 vue服务端渲染(基础) Nuxt框架 文件目录结构 项目启动.打包 生命周期 SSR nuxtserverInit middleware 中间件 全局中间件 页面级中间件 validate ...
- 手把手教你 Vue 服务端渲染
写在前面 在写这篇文章之前,我有写一篇 Vue 预渲染的教程 以及 在线示例,有需要的可以看一下~ [下面开始 Vue 服务端渲染] 服务端渲染 = SSR = Server-Side Renderi ...
- egg html模板,egg+vue服务端渲染模板项目介绍
egg-vue-webpack-boilerplate 基于 Egg + Vue + Webpack SSR 服务端渲染和 CSR 前端渲染工程骨架项目,包括前台系统(SSR MPA)和后台管理系统( ...
- Vue 服务端渲染 预渲染
文章目录 简介 那么 什么是服务端渲染 为什么使用服务端渲染 服务端渲染 or 预渲染 区别 如何使用预渲染 如何搭建一个预渲染开发环境 Tip 写在最后 简介 关于 Vue 的 SPA 说的已经太多 ...
- java vue 服务端渲染_vue服务端渲染缓存应用详解
服务端渲染简介 服务端渲染不是一个新的技术:在 Web 最初的时候,页面就是通过服务端渲染来返回的,用 PHP 来说,通常是使用 Smarty 等模板写模板文件,然后 PHP 服务端框架将数据和模板渲 ...
- Vue 服务端渲染原理 拆分成三步个步骤简单的实现一个案例
前言 可能我们平常接触比较多的是使用 vue + vue全家桶来搭建起一个单页(SPA)应用.用 服务端渲染 搭建项目比较少,本文是记录我在学习 服务端渲染 过程中的一些见解,如有出错或疏漏,麻烦帮忙 ...
- vue服务端渲染 MySQL_vue服务端渲染简单入门实例
想到要学习vue-ssr的同学,自不必多说,一定是熟悉了vue,并且多多少少做过几个项目.然后学习vue服务端渲染无非解决首屏渲染的白屏问题以及SEO友好. 话不多说,笔者也是研究多日才搞明白这个服务 ...
- java vue 服务端渲染_vue ssr服务端渲染小白解惑
vue ssr服务端渲染小白解惑 >初学ssr入坑 初学vue服务端渲染疑惑非常多,我们大部分前端都是半路出家,上手都是前后端分离,对服务端并不了解,不说java.php语言了,连node服务都 ...
最新文章
- P1155 双栈排序(二分图的染色判断+链式前向星)
- live555工程建立与调试
- Oracle CBO 与 RBO
- Java黑皮书课后题第10章:*10.18(大素数)编写程序找出五个大于Long.Max_VALUE的素数
- cdatabase读取excel第一行数据_pandas读取excel数据并对重复数据进行标记或者删除
- ySQL挑战搭建一个简易的成绩管理系统的数据库
- Taro+react开发(90):列表渲染key值
- 反汇编基础-加法的求值过程(各种类型)
- 使用U盘引导安装CentOS操作系统
- mongodb服务安装及部署配置
- android gradle时间长,Android Studio gradle需要很长时间才能构建
- 工作十年,分享看过的优质 Java 书籍
- pyside2 镜像安装_简单安装Pyside2
- Mina中的支付交易snark
- 软件测试--软件测试执行管理
- Icon图标制作(转化)工具
- DAVSE VCC-H10004K超高清会议摄像机
- 软件测试 | 白盒的测试方法
- 电脑端口被占用怎么解决?
- 信息系统项目管理师10大管理47个过程域输入输出工具(项目质量管理)