前言
上一篇文章服务器端渲染基础,介绍了各种渲染模式的优缺点,并在最后利用vue.js
的Nuxt.js
,通过一个小案例,体验了现代服务器渲染模式。
Nuxt.js定义
Nuxt.js
是一个基于Vue.js
的服务端渲染应用框架,通过对客户端/服务端基础架构的抽象组织,Nuxt.js
主要关注的是应用的UI渲染,可以轻松的实现同构应用- 作为客户端/服务端框架,提供了很多有用的特性:
- 基于
Vue.js
- 自动代码分层
- 服务端渲染
- 强大的路由功能,支持异步数据
- 静态文件服务
ES2015+
语法支持- 打包和压缩
JS
和CSS
- HTML 头部标签管理
- 本地开发支持热加载
- 集成
ESLint
- 支持各种样式预处理器:
SASS
、LESS
、Stylus
等等 - 支持
HTTP/2
推送
- 基于
Nuxt.js使用范围
Nuxt.js
主要在以下几种情况下使用:
- 使用
Nuxt.js
初始化一个全新的项目 - 对于已有的
node.js
服务端项目,直接把Nuxt
当做一个中间件集成到Node Web Server
中 - 解决现有
Vue.js
项目的首屏加载慢、不利于SEO
的缺陷,这种情况下要求开发人员对Nuxt
掌握程度高,且代码的改动量大,至少改动10%。
创建Nuxt项目
Nuxt.js
提供了两种方式用来创建项目:
- 使用 create-nuxt-app 脚手架工具
- 开发者手动创建,必须遵循Nuxt.js目录结构规则
手动创建项目,进入项目目录
# 初始化 package.json 文件
yarn init
# 安装 nuxt
yarn add nuxt
在package.json
文件的scripts
中新增:
"scripts": {
"dev": "nuxt" //可以通过运行npm run dev来运行nuxt
},
新建pages
目录,创建第一个页面pages/index.vue
<template>
<div>
<h1>Hello Nuxt.js</h1>
</div>
</template>
<script>
export default {
name: 'home'
}
</script>
<style>
</style>
启动项目
yarn dev
应用在http://localhost:3000
上运行,查看在浏览器上是否能正产访问。
注意:Nuxt.js 会监听pages目录中的文件更改,因此在添加新页面时无需重新启动应用程序。
路由
普通路由
与Vue.js
不同的是,Nuxt.js
不需要开发者在项目中显式地定义vue-router
的路由规则,Nuxt.js
会依据pages
目录中的所有*.vue
文件自动生成vue-router
模块的路由配置,找到文件夹下的index.vue
并将它作为此文件夹根路径的组件。
pages
的目录结构如下:
pages/
--| user/
-----| index.vue
-----| info.vue
--| index.vue
Nuxt.js
自动生成的路由配置如下:
router: {
routes: [
{
name: 'index',
path: '/',
component: 'pages/index.vue'
},
{
name: 'user',
path: '/user',
component: 'pages/user/index.vue'
},
{
name: 'user-one',
path: '/user/info',
component: 'pages/user/info.vue'
}
]
}
路由导航
Nuxt.js
提供了路由组件nuxt-link
用于页面之间的跳转,它的作用和 router-link 一致, 通过 to
属性指定目标地址,默认渲染成带有正确链接的a标签,可以通过配置 tag
属性生成别的标签。
<nuxt-link to="/">跳转到首页</nuxt-link>
同样也支持编程式路由导航,使用方法也和Vue.js
的编程式导航一致
<button @click="onClick">跳转到首页</button>
methods: {
onClick() {
this.$router.push('/');
}
}
还支持支持使用<a></a>
标签进行页面跳转,但这种方式会刷新页面,向服务器端发送请求,故不推荐。
嵌套路由
Nuxt.js
提供了三种实现嵌套路由的方式。
- 通过
vue-router
的子路由创建Nuxt.js
应用的嵌套路由 - 在
nuxt.config.js
中通过extendRoutes
自定义路由规则 - 使用
Nuxt.js
依据pages
目录中的所有*.vue
文件自动生成vue-router
模块的路由配置规则,但需要满足以下两个条件:- 添加一个
.vue
文件,同时添加一个与该文件同名的目录用来存放它的子视图组件 - 在父组件(
.vue
文件) 内增加用于显示子视图内容(相当于vue.js
的router-view
)
- 添加一个
如下图中的父组件students.vue
,它的子组件都存放在与它同名的students
目录下
动态路由
通过extendRoutes
设置的自定义路由规则,动态路由匹配规则同vue的动态路由匹配,而在 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'
},
{
name: 'slug',
path: '/:slug',
component: 'pages/_slug/index.vue'
},
{
name: 'slug-comments',
path: '/:slug/comments',
component: 'pages/_slug/comments.vue'
}
]
}
自定义路由配置
base用于在nuxt.config.js
配置应用的根路径,例如:
//nuxt.config.js
module.exports = {
router: {
base: '/app' //默认路由改为http://localhost:3000/app/
}
}
extendRoutes扩展Nuxt.js创建的路由或自定义路由配置规则,下面的例子配置自定义路由表规则
//nuxt.config.js
module.exports = {
router: {
extendRoutes(routes, resolve) {
routes.splice(0);//清除nuxtjs根据Pages目录生成的默认路由
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/')
}
]
}
]);
}
}
}
视图
Nuxt.js
视图的组成部分如下图所示:
模板
Nuxt.js
默认模板为:
<!DOCTYPE html>
<html {
{
HTML_ATTRS }}>
<head {
{
HEAD_ATTRS }}>
{
{
HEAD }}
</head>
<body {
{
BODY_ATTRS }}>
{
{
APP }}
</body>
</html>
在 src
文件夹下(默认是应用根目录)创建一个 app.html
的文件就可以定制化默认的 html 模板。
布局
根据Nuxt.js
的目录规则,在一个应用中若无额外的配置项,布局组件必须写在布局目录layouts
中。
- 默认布局
通过 layouts/default.vue
文件来扩展应用的默认布局,此文件必须添加 <nuxt/>
组件用于显示页面的主体内容。
<template>
<div>
<ul>
<li>
<!--相当于router-link-->
<nuxt-link to="/">首页</nuxt-link>
</li>
<li>
<nuxt-link to="/about">关于</nuxt-link>
</li>
</ul>
<!--页面路由视图,相当于router-view-->
<nuxt></nuxt>
</div>
</template>
- 自定义布局
layouts
目录中的每个文件 (顶级) 都将创建一个可通过页面组件中的 layout 属性访问的自定义布局。
例如创建一个 博客布局layouts/blog.vue
:
<template>
<div>
<div>我的博客导航栏在这里</div>
<nuxt />
</div>
</template>
然后必须在相应的页面中通过layout
指定此页面引用的自定义布局:
<template>
···
</template>
<script>
export default {
layout: 'blog'
}
</script>
- 错误页面
Nuxt.js
规定 layouts
根目录下的所有文件都属于个性化布局文件,除了layouts/error.vue
(不需要包含 <nuxt/>
标签),此文件放在 layouts
文件夹中, 但它是一个 页面,用于定制化错误页面(404、500页面)。
例如一个定制化的404
页面:
template>
<div class="container">
<h1 v-if="error.statusCode === 404">页面不存在</h1>
<h1 v-else>应用发生错误异常</h1>
<nuxt-link to="/">首 页</nuxt-link>
</div>
</template>
<script>
export default {
props: ['error'],
layout: 'blog' // 为错误页面指定自定义的布局
}
</script>
页面
Nuxt.js
的页面实际上是Vue
组件,并在这些组件基础上添加了一些特殊的配置项。
<template>
<div>
<h1>{
{
title1 }}</h1>
<ul>
<li v-for="item in list" :key="item.id">
{
{
item.title }}: {
{
item.content }}
</li>
</ul>
</div>
</template>
<script>
export default {
name: "Home",
//Nuxt.js中的钩子函数,专门用于获取页面服务端渲染的数据
async asyncData() {
...
}
};
</script>
数据
Nuxt.js
增加了一个 asyncData 方法,可以在设置组件的数据之前能异步获取或处理数据。
只能在页面组件中使用,不能用于页面组件的子组件
asyncData方法内不能使用this,因为它是在页面组件初始化之前调用
调用时机:
asyncData
方法会在页面组件加载之前被调用- 服务端渲染期间、客户端路由更新之前都会调用
asyncData
参数及返回值:
asyncData
的第一个参数被设定为当前页面的上下文对象(包括request / response / params / query / store)Nuxt.js
会将asyncData
返回的数据和组件data
方法返回数据融合到一起给组件使用
Nuxt.js
提供了几种不同的方法来使用 asyncData 方法:
- 使用
async
、await
<template>
...
</template>
<script>
export default {
async asyncData({
params }) {
const {
data } = await axios.get(`https://my-api/posts/${
params.id}`)
return {
title: data.title }
}
}
</script>
- 返回一个
Promise
,nuxt.js
会等待该Promise
被解析之后才会设置组件的数据,从而渲染组件
<template>
...
</template>
<script>
export default {
asyncData({
params }) {
return axios.get(`https://my-api/posts/${
params.id}`).then(res => {
return {
title: res.data.title }
})
}
}
</script>
文章列表
服务器端渲染基础
服务器端渲染-Nuxt.js基础
服务器端渲染-Nuxt.js综合案例
服务器端渲染-Nuxt.js综合案例发布部署
服务器端渲染-Vue SSR搭建