前言

本篇主要针对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 目录,如果该目录存在,它将做以下的事情:

  1. 引入vuex模块
  2. 将vuex模块加到vendors构建配置中
  3. 设置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相关推荐

  1. Vue 服务端渲染(SSR)、Nuxt.js - 从入门到实践

    前言 10月初有幸接到公司官网改版需求,要求采用服务端渲染模式对原网站进行seo优化. 由于团队一直使用的vue技术栈,所以我第一时间想到的就是采用vue 服务端渲染(SSR)来实现该需求,即能减少团 ...

  2. vue服务端渲染——基础

    文章目录 vue服务端渲染(基础) Nuxt框架 文件目录结构 项目启动.打包 生命周期 SSR nuxtserverInit middleware 中间件 全局中间件 页面级中间件 validate ...

  3. 手把手教你 Vue 服务端渲染

    写在前面 在写这篇文章之前,我有写一篇 Vue 预渲染的教程 以及 在线示例,有需要的可以看一下~ [下面开始 Vue 服务端渲染] 服务端渲染 = SSR = Server-Side Renderi ...

  4. egg html模板,egg+vue服务端渲染模板项目介绍

    egg-vue-webpack-boilerplate 基于 Egg + Vue + Webpack SSR 服务端渲染和 CSR 前端渲染工程骨架项目,包括前台系统(SSR MPA)和后台管理系统( ...

  5. Vue 服务端渲染 预渲染

    文章目录 简介 那么 什么是服务端渲染 为什么使用服务端渲染 服务端渲染 or 预渲染 区别 如何使用预渲染 如何搭建一个预渲染开发环境 Tip 写在最后 简介 关于 Vue 的 SPA 说的已经太多 ...

  6. java vue 服务端渲染_vue服务端渲染缓存应用详解

    服务端渲染简介 服务端渲染不是一个新的技术:在 Web 最初的时候,页面就是通过服务端渲染来返回的,用 PHP 来说,通常是使用 Smarty 等模板写模板文件,然后 PHP 服务端框架将数据和模板渲 ...

  7. Vue 服务端渲染原理 拆分成三步个步骤简单的实现一个案例

    前言 可能我们平常接触比较多的是使用 vue + vue全家桶来搭建起一个单页(SPA)应用.用 服务端渲染 搭建项目比较少,本文是记录我在学习 服务端渲染 过程中的一些见解,如有出错或疏漏,麻烦帮忙 ...

  8. vue服务端渲染 MySQL_vue服务端渲染简单入门实例

    想到要学习vue-ssr的同学,自不必多说,一定是熟悉了vue,并且多多少少做过几个项目.然后学习vue服务端渲染无非解决首屏渲染的白屏问题以及SEO友好. 话不多说,笔者也是研究多日才搞明白这个服务 ...

  9. java vue 服务端渲染_vue ssr服务端渲染小白解惑

    vue ssr服务端渲染小白解惑 >初学ssr入坑 初学vue服务端渲染疑惑非常多,我们大部分前端都是半路出家,上手都是前后端分离,对服务端并不了解,不说java.php语言了,连node服务都 ...

最新文章

  1. P1155 双栈排序(二分图的染色判断+链式前向星)
  2. live555工程建立与调试
  3. Oracle CBO 与 RBO
  4. Java黑皮书课后题第10章:*10.18(大素数)编写程序找出五个大于Long.Max_VALUE的素数
  5. cdatabase读取excel第一行数据_pandas读取excel数据并对重复数据进行标记或者删除
  6. ySQL挑战搭建一个简易的成绩管理系统的数据库
  7. Taro+react开发(90):列表渲染key值
  8. 反汇编基础-加法的求值过程(各种类型)
  9. 使用U盘引导安装CentOS操作系统
  10. mongodb服务安装及部署配置
  11. android gradle时间长,Android Studio gradle需要很长时间才能构建
  12. 工作十年,分享看过的优质 Java 书籍
  13. pyside2 镜像安装_简单安装Pyside2
  14. Mina中的支付交易snark
  15. 软件测试--软件测试执行管理
  16. Icon图标制作(转化)工具
  17. DAVSE VCC-H10004K超高清会议摄像机
  18. 软件测试 | 白盒的测试方法
  19. 电脑端口被占用怎么解决?
  20. 信息系统项目管理师10大管理47个过程域输入输出工具(项目质量管理)

热门文章

  1. 淘宝商家怎么采集同行淘宝店的技巧?
  2. 要直接,不要怂,谈钱才不伤感情
  3. STM32F103的PA15脚作为PWM输出使用
  4. 栅格区域人口分布数据获取及坐标系转换
  5. 珍爱网退费流程?珍爱网怎么退费
  6. 教你快速推广微信公总号
  7. import numpy as np\n, import pandas as pd\n, import matplotlib.pyplot as plt
  8. 软件发明专利实例_计算机软件发明专利技术经验交底资料范例
  9. 艾默生流量计在流量测量上显出巨大的潜力
  10. 常规信息系统集成技术