上期回顾

说接上文《二九║ Nuxt实战:异步实现数据双端渲染》,昨天咱们通过项目二的首页数据处理,简单了解到了 nuxt 异步数据获取的作用,以及亲身体验了几个重要文件夹的意义,整篇文章也一直在往如何实现服务端渲染的方向讲解,因为我个人感觉这个是一个重点,如果是只会如何使用的话,大家就可以走马观花的看看就行了,昨天呢,遗留了几个问题,我也想了想,还没有想好如何通过浅显的话来概括,如果要是搬出来教科书似的讲解,感觉又不是很清晰,我就在以后的领悟中补充吧,这里就先说下其中的三个问题:

1、我们通过 dev 编译,生成的 .nuxt 临时文件夹(我个人感觉他就像我们 .net core 中的 bin 文件夹),.nuxt 目录为 npm run dev或者是npm run build 后才生成,两个操作都执行了 build() 方法,用于存放 Nuxt.js 的核心库文件,如果你将一个老项目的 .nuxt 文件夹覆盖一个新项目的 .nuxt 文件夹,新项目正常运行,按照老的项目路由规则之类的都可以正常访问。例如,你可以在这个目录下找到 server.js 文件,描述了 Nuxt.js 进行服务端渲染的逻辑,流程是:调用 nuxtServerInit 方法,当请求打入时,最先调用的即是 nuxtServerInit 方法,可以通过这个方法预先将服务器的数据保存,如已登录的用户信息等。另外,这个方法中也可以执行异步操作,并等待数据解析后返回。Middleware 层,经过第一步后,请求会进入 Middleware 层,在该层中有三步操作:读取 nuxt.config.js 中全局 middleware 字段的配置,并调用相应的中间件方法 匹配并加载与请求相对应的 layout 调用 layout 和 page 的中间件方法。调用 validate 方法,在这一步可以对请求参数进行校验,或是对第一步中服务器下发的数据进行校验,如果校验失败,将抛出 404 页面。

调用 fetch 及 asyncData 方法,这两个方法都会在组件加载之前被调用,它们的职责各有不同, asyncData 用来异步的进行组件数据的初始化工作,而 fetch 方法偏重于异步获取数据后修改 Vuex 中的状态。


2、每次修改文件,都会触发热 webpack 的[HMR] 热加载,因为 Nuxt.js集成了如下模块: Vue-Router, Vue-Meta 和 Vuex (仅在使用 Vuex 状态树配置项 时引入)。 这样的好处在于,不需要手工配置依赖,每次当我们修改文件,webpack 就会自动保存,Nuxt.js 使用 Webpack 和 vue-loader 、 babel-loader 来处理代码的自动化构建工作(如打包、代码分层、压缩等等)。


4、在 network 中,当有一个请求过来时,服务器会新建一个vue实例,渲染(render)出需要显示的页面的html,把得到的页面以字符串的形式返回给客户端。同时把相关的js文件也返回(首次请求时返回vue的runtime、webpack的runtime和app.js等文件,非首次请求返回按需加载的js文件),返回的js文件和单页面应用(SPA)返回的差不多

app.js:基本就是你实际编写的那个app.vue(.vue或.js),没这个页面跑不起来,该页面应该提供了跟app应用相关的公共方法,脚本里也明确配置了跟路由相关的信息

vendor.js:vue-cli全家桶默认配置里面这个chunk就是将所有从node_modules/里require(import)的依赖都打包到这里,所以这个就是所有node_modules/下的被require(import)的js文件

manifest.js: 最后一个chunk,被注入了webpackJsonp的定义及异步加载相关的定义(webpack调用CommonsChunkPlugin处理后模块管理的核心,因为是核心,所以要第一个进行加载,不然会报错),该文件确定是跟路由相关的配置信息,其中明确包含了路由的路径,和版本号,但是暂时不明白为何前端输出会保留该配置(大概是做一些页面动态切换效果或者是预加载的时候使用,但是页面的预加载已经在ssr 输出的html 已经包含了)

然后还有一些 pages_index.js文件,布局 layouts_blog.js文件等:default.js(跟dis/layout/default.js一致,是载入了使用的layout)

。浏览器接收到这些文件后,通过js文件把静态页面的字符串hydrate成可以交互的应用。和SPA相比,SSR返回的数据就是多了个静态页面(字符串形式)。


我又一次老生常谈的说了一遍,还是感觉不是很清晰,看来自己的功底还是不行呀,如果有爱好 nuxt 或者 做过 SSR 的小伙伴,欢迎联系,咱们一起讨论下,今天呢,接着昨天的工作,把详情页渲染出来吧~~~

零、今天要完成紫色的部分

一、动态路由实现详情页布局设计

经过昨天的首页渲染,大家不知道使用起来怎么样,不仅可以配置每一页的 head 信息( TDK head),还可以对整体进行配置,虽然中间引入了 plugins 插件机制,不过也是很好的做了封装,特别是路由这一块,大家是不是发现已经完全不用配置了,Nuxt.js 依据 pages 目录结构自动生成 vue-router 模块的路由配置,为我们减少了很大的工作量,今天咱们就继续对详情页进行配置。

1、什么是动态路由

昨天呢,咱们开发了首页,通过地址直接可以访问,但是在开发过程中,肯定会有这样的页面:通过不同的 id 加载不同的详情页面,这些页面虽然是一个,但是 URL 地址却是多个,所以我们就说这个路由是动态的,还记得咱们在第一个项目中的时候,是怎么配置的么?我们通过页面接收参数来实现动态路由

    {
path: "/Content/:id",
name: "Content",
component: Content
},

在 Nuxt.js 里面定义带参数的动态路由,需要创建对应的以下划线作为前缀的 Vue 文件 或 目录。

以下目录结构:

pages/
--| _slug/
-----| comments.vue
-----| index.vue
--| users/
-----| _id.vue
--| index.vue

Nuxt.js 生成对应的路由配置表为:

router: {
routes: [
{
name: 'index',
path: '/',
component: 'pages/index.vue'
},
{
name: 'users-id',
path: '/users/:id?',
component: 'pages/users/_id.vue'
}
]
}

你会发现名称为 users-id 的路由路径带有 :id? 参数,表示该路由是可选的。如果你想将它设置为必选的路由,需要在 users/_id 目录内创建一个 index.vue 文件。

2、添加博客详情页

1、在 pages 文件夹中,添加 blog 文件夹,然后添加 _id.vue 页面

这个时候,我们看我们的临时编译文件 .nuxt 中 router.js 已经动态的增加上了上边添加的路由

 return new Router({
mode: 'history',
base: '/',
linkActiveClass: 'nuxt-link-active',
linkExactActiveClass: 'nuxt-link-exact-active',
scrollBehavior,
routes: [
{
path: "/blog/:id?",
component: _66cb1a63,
name: "blog-id"
},
{
path: "/",
component: _70e72bdd,
name: "index"
}
],

2、编辑 _id.vue 文件,实现数据获取

<template>
<div class="post-page">
<h1 class="title">{{data.btitle}}</h1>
<p class="createTime">{{data.bCreateTime }}</p>
<div v-html="data.bcontent" ></div>
</div>
</template> <script>
import Vue from "vue";
export default {
layout: "blog",
validate ({ params }) {
// 校验文章id是否为数字
return /^\d+$/.test(params.id);
},
async asyncData ({ params, error }) {
// 获取文章详情
let data = {};
try {
data = await Vue.http.get(`blog/${params.id}`);
return {
data: data
};
} catch (e) {
//error({ statusCode: 404, message: "出错啦" });
}
},
fetch ({ store, params }) {},
data () {
return {
comments: []
};
},
head () {//设置页面 head 信息
return {
title: `${this.data.btitle}`,
meta: [
{
name: "description",
content: this.data.btitle
}
]
};
},
filters: {
timeFormat: function (time) {
if (!time) return "";
return time;
}
},
mounted () {},
components: {
}
};
</script>
//导入样式
<style lang="css">
@import "../../static/vue-blog-sq.css";
</style>

是不是很简单,直接添加页面内容,就可以实现路由渲染,直接就可以访问了,不过这里可能会有一个坑,如果你运气好的话,会碰上,运气不好,就过去了。

3、刷新页面查看结果

苍天呀,不是吧,报错了?!如果你看到这个错误,恭喜你比较幸运,可能你会进一步的了解到 nuxt 是如何渲染的。

4、点击 浏览器后退 ,返回到首页,发现更加崩溃

不仅刚刚的详情页不见了,就连我们的首页数据也出错了!虽然这上面有数据,但是这个是浏览器缓存的,而不是我们真实的数据,这个时候着急的小伙伴,一定会很着急,稳住,我们能赢!

3、首次运行服务端渲染,然后开始客户端渲染

这个时候,如果你刷新首页,发现一切正常,不仅如何,如果你刷新详情页,数据也能出现,不信你可以试试,那这是为什么呢?

原因就在于我们刷新页面,或者新窗口打开等等,都是新开了一个服务,我们的页面为了实现 SEO 先进行的是服务端渲染,讲整个页面的字符串发送过来,然后点击链接去详情页的时候,我们就开始走客户端渲染了,之所以页面会报错,就是我们存在跨域的问题。

你可能会问,问什么第一次不存在,因为第一次是服务端渲染呀,服务端是不存在跨域问题的,只有 js 请求才会存在跨域的问题,到这里,通过这个错误你是不是了解到了一点儿,这个错误也是我故意放出来的,就是为了让大家更清楚的了解到 nuxt 是如何进行渲染的。这也能说的通,为什么第一次刷新首页有数据,从详情页返回过来,报错的原因了,因为第二次渲染已经交给客户端了。

解决办法很简单,还是在我们 .net core api 中 CORS 跨域配置我们的端口就行,然后一切正常了。

相信这个时候你对 nuxt 的渲染有了一点理解了吧,如果还不是很清晰,请往下看

二、SSR 同构知多少

SSR 用通过同构的方法解决了上面问题。我们先说一下 SSR 的具体表现,比如我们现在有一个列表页,列表中每一行对应一个详情页,那么如果直接用浏览器访问列表页时,服务器返回数据和 html 融合后的页面,浏览器拿到页面直接渲染,这就省去了先请求 js 再由 js 发起数据请求的过程,页面渲染的同时请求js,js加载完成后绑定事件;从列表页中点击某一条到详情页的时候,和普通的全栈 Ajax 一样,先请求 js 再由 js 发起数据请求,然后填充数据渲染页面。如果将详情页的链接复制出来,直接在新浏览中访问,那么详情页会直接返回数据和 html 融合后的页面(服务端渲染),渲染的同时请求详情页 js,最后再绑定事件。这个“服务器端拼接 html 和 html 是由同样的页面和组件完成的,这种前后端采用同样的结构在不同的环境中产出同样的 html 的方案称之为“同构”。

1、什么叫前后端同构?

为了解决某些问题(比如SEO、提升渲染速度等)vue 提供了2个方法在服务端生成一个HTML文本格式的字符串。在得到了这个HTML格式的字符串之后,通常会将其组装成一个页面直接返回给用户的浏览器。

到这里,服务端的活已经干完了,然后就是浏览器这边干活。

浏览器拿到HTML文本后,立刻进行渲染将内容呈现给用户。然后加载页面所需的 .js 文件,然后执行 JavaScript 脚本,然后开始初始化 vue 组件

到这里问题就来了。vue 初始化组件后会执行组件内所有 render () 方法,然后生成虚拟DOM的树形结构,然后在适当的时候将虚拟dom写到浏览器的真实 dom 中。因为 vue 总是根据虚拟 dom 来生成真实dom,所以最后会把服务器端渲染好的HTML全部替换掉。

上面这个事情说不是问题确实也不是问题,无非就是用户看到页面然后“闪现”一下。说是问题还真是个问题,产品会拿着这毛病从用户体验的角度在各种场合和你死磕半个月。磕累了你索性把服务端渲染关了,然后运营又拿着SEO的问题准备和你开始撕逼了。

为了解决这些问题,他们在 .renderToString(element) 方法中提供了一个 checksum 机制。前后端同构就是保证前端和后端的dom结构一致,不会发生重复渲染。

2、什么叫 首屏渲染?

简单的说就是 vue 在浏览器内存中第一次生成的虚拟 dom 树。切记是虚拟 dom ,而不是浏览器的dom。

了解 vue 的应该知道,所有 vue组件都有一个 render() 方法(如果使用function方式编写的组件会把function里的所有代码都塞到 render() 方法中去)。当 render( element, container, [callback] )方法执行时,会执行以下步骤:

1. 所有组件的会先进行初始化(es6执行构造函数)。
2. 所有组件的 render () 方法会被调用一次,完成这个过程后会得到一颗虚拟的 dom 树。
3. vue 会将虚拟dom转换成浏览器dom,完成后调用组件的 componentDidMount() 方法告诉你已经装载到浏览器上了。

在上面这个过程成中,步骤2完成后即为完成 vue 的首屏渲染。结合 checksum 机制步骤3有可能不会执行。

当组件状态发生变更时( setState() 生命周期函数被调用)或者 父组件渲染时(父组件的 render() 方法被调用),当前组件的 render() 方法都会被执行,都有可能会导致虚拟dom变更,但是这些变更和首屏渲染没任何关系了。

3、查看是如何渲染的

1、在我们的首页中,首次加载,在 network 中,查看我们都加载了那些文件

这些文件咱们在文章顶部都讲到了,这里说下 初始页面,它是直接将 html 返回给我们的前端渲染,这个很好理解

2、点击到详情页

我们发现这个我们的网络请求,并没有继续打包 build 走服务端渲染,而是仅仅请求了一个接口,返回了 json 数据,从这里大家应该就能看的处理,这就是所谓的双端渲染模式。

三、总结

好啦,今天就暂时说到这里了,通过详情页的添加,大家会切身体会到 nuxt 的渲染模式,是如何在服务端和客户端之间来回切换渲染的,这三篇文章大家要多看看,才能了解其中的内涵,加油鸭~~

四、Github

https://github.com/anjoy8/Blog.Vue.Nuxt

从壹开始前后端分离 [ vue + .netcore 补充教程 ] 三十║ Nuxt实战:动态路由+同构的更多相关文章

  1. 从壹开始前后端分离 [ vue + .netcore 补充教程 ] 二九║ Nuxt实战:异步实现数据双端渲染

    回顾 哈喽大家好!又是元气满满的周~~~二哈哈,不知道大家中秋节过的如何,马上又是国庆节了,博主我将通过三天的时间,给大家把项目二的数据添上(这里强调下,填充数据不是最重要的,最重要的是要配合着让大家 ...

  2. 从壹开始前后端分离 [ vue + .netcore 补程 ] 三十一║ Nuxt终篇:基于Vuex的权限验证探究

    缘起 哈喽大家好,今天周四啦,楼主明天要正式放假了,这里先祝大家节日快乐咯,希望在家里能继续研究点儿东西吧,今天呢是 nuxt 的最后一篇,主要是对权限登录进行研究,这一块咱们之前在说第一个项目的时候 ...

  3. 从壹开始前后端分离 [ vue + .netcore 补充教程 ] 二七║ Nuxt 基础:框架初探

    缘起 哈喽大家好,又是周四了,俗话说周四来了,周末还远么哈哈,老张我也想下周请假,来个16天的大长假哟,不知道大家是怎么请假的,近来发现文章下边已经没有人评论了,赶脚比较凄凉了,大家看到的麻烦点个赞呀 ...

  4. 从壹开始前后端分离 [ vue + .netcore 补充教程 ] 二八║ Nuxt 基础:面向源码研究Nuxt.js

    前言 哈喽大家周五好,又是一个开开心心的周五了,接下来就是三天小团圆啦,这里先祝大家节日快乐咯,希望都没有加班哈哈,今天公司发了月饼,嗯~时间来不及了,上周应该搞个活动抽中几个粉丝发月饼的,下次吧,这 ...

  5. 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十五 ║Vue基础:JS面向对象&字面量& this字

    缘起 书接上文<从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十四 ║ VUE 计划书 & 我的前后端开发简史>,昨天咱们说到了以我的经历说明的web开发经历的 ...

  6. 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十六 ║Vue基础:ES6初体验 & 模块化编程

    缘起 昨天说到了<从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十五 ║ Vue前篇:JS对象&字面量&this>,通过总体来看,好像大家对这一块不是很 ...

  7. 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十八║Vue基础: 指令(下)+计算属性+watch

    回顾 今天来晚辣,给公司做了一个小项目,一个瀑布流+动态视频控制的DEMO,有需要的可以联系我,公司的项目就不对外展示了(一个后端程序员真的要干前端了哈哈哈). 书接上文,昨天正式的开始了Vue的代码 ...

  8. 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十四 ║ VUE 计划书 & 我的前后端开发简史

    ---新内容开始--- 番外 大家周一好呀,又是元气满满的一个周一呀!感谢大家在周一这个着急改Bug的黄金时期,抽出时间来看我的博文哈哈哈,时间真快,已经到第十四篇博文了,也很顺顺(跌跌)利利 (撞撞 ...

  9. 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十九║Vue基础: 样式动态绑定+生命周期

    回顾 哈喽大家好,前后端分离系列文章又开始了,今天周一,还是感谢大家花时间来观看我写的博客,周末呢,没有写文章,但是也没有闲着,主要是研究了下遗留问题,看过之前文章的应该知道,之前的在AOP使用Red ...

随机推荐

  1. spring boot整合shiro

    安全框架Shiro和Spring Security比较,本文主要围绕Shiro进行学习 一 Shiro 是一个强大而灵活的开源安全框架,能够清晰的处理认证 授权 管理会话以及,密码加密 01 .认证与 ...

  2. Python集合set

    集合 set 集合是无序的 集合的值是唯一的 求两个集合的关系: list1 = [1,4,5,7,3,6,7,9] list2 = set([2,6,0,66,22,8,4]) list3 = se ...

  3. 开机出现loading (hd0)/ntldr。。。

    电脑一开机就出现ntldr is missing的原因:1.操作系统文件损坏.2.MBR表损坏.3.硬盘数据线松了.4.硬盘坏了.解决方法:1.重新安装操作系统.2.用U盘或光盘引导,进入PE系统,用 ...

  4. MySQL 大数据量快速插入方法和语句优化

    MySQL大数据量快速插入方法和语句优化是本文我们主要要介绍的内容,接下来我们就来一一介绍,希望能够让您有所收获! INSERT语句的速度 插入一个记录需要的时间由下列因素组成,其中的数字表示大约比例 ...

  5. forwardport--源码笔记--注释

    failed:", err.Error())             }         }()     }     //     log.Println("forwardPort ...

  6. 【BZOJ 3924】[Zjoi2015]幻想乡战略游戏

    题目: 题解: 对点分树理解加深了233,膜拜zzh干翻紫荆花. 感谢zzh的讲解. 首先优化基于传统DP,假设树不发生变化,我们就可以利用DP求出带权重心. 考虑修改,我们思路不变,还是从root开 ...

  7. 正则表达式(Regular expressions)使用笔记

    Regular expressions are a powerful language for matching text patterns. This page gives a basic intr ...

  8. appium----【已解决】【Mac】环境配置提示“Xcode Command Line Tools are NOT installed!"

    报错问题提示截图如下: 报错原因 :根据给出的信息很明显可以看到是"Xcode Command Line Tools"此工具没有安装 解决措施: 打开终端直接执行:xcode-se ...

  9. 重磅!!!微软发布ASP.NET Core 2.2,先睹为快。

    我很高兴地宣布ASP.NET Core 2.2现在作为.NET Core 2.2的一部分提供! 如何获取? 您可以从.NET Core 2.2下载页面下载适用于您的开发机器和构建服务器的新.NET C ...

  10. 从一亿个ip找出出现次数最多的IP(分治法)

    /* 1,hash散列 2,找到每个块出现次数最多的(默认出现均匀)—–>可以用字典树 3,在每个块出现最多的数据中挑选出最大的为结果 */ 问题一: 怎么在海量数据中找出重复次数最多的一个 算 ...