文章目录
一、NuxtJS 介绍
1.1 NuxtJS 是什么
Nuxt.js 是一个基于 Vue.js 的服务端渲染应用框架,它可以帮我们轻松的实现同构应用
- 通过对客户端/服务端基础架构的抽象组织,Nuxt.js 主要关注的是应用的 UI 渲染
- 我们的目标是创建一个灵活的应用框架,你可以基于它初始化新项目的基础结构代码,或者在已有 Node.js 项目中使用 Nuxt.js
- Nuxt.js 预设了利用 Vue.js 开发服务端渲染的应用所需要的各种配置
- 除此之外,我们还提供了一种命令叫:
nuxt generate
,为基于 Vue.js 的应用提供生成对应的静态站点的功能 - 我们相信这个命令所提供的功能,是向开发集成各种微服务(Microservices)的 Web 应用迈开的新一步
- 作为框架,Nuxt.js 为 客户端/服务端 这种典型的应用架构模式提供了许多有用的特性,例如异步数据加载、中间件支持、布局支持等非常实用的功能
1.2 NuxtJS 特性
- 基于 Vue.js
- Vue、Vue Router、Vuex、Vue SSR
- 自动代码分层
- 服务端渲染
- 强大的路由功能,支持异步数据
- 静态文件服务
- ES2015+ 语法支持
- 打包和压缩 JS 和 CSS
- HTML 头部标签管理
- 本地开发支持热加载
- 集成 ESLint
- 支持各种样式预处理器: SASS、LESS、 Stylus 等等
- 支持 HTTP/2 推送
1.3 NuxtJS 框架是如何运作的
- Nuxt.js 集成了以下组件/框架,用于开发完整而强大的 Web 应用:
- Vue.js
- Vue Router
- Vuex
- Vue Server Renderer
- 压缩并 gzip 后,总代码大小为:57kb (如果使用了 Vuex 特性的话为 60kb)
- 另外,Nuxt.js 使用 Webpack 和 vue-loader、 babel-loader 来处理代码的自动化构建工作(如打包、代码分层、压缩等等)
1.4 NuxtJS 渲染流程
下图阐述了 Nuxt.js 应用一个完整的服务器请求到渲染(或用户通过 切换路由渲染页面)的流程:
1.5 NuxtJS 使用方式
- 初始项目
- 已有的 Node.js 服务端项目
- 直接把 Nuxt 当作一个中间件集成到 Node Web Server 中
- 现有的 Vue.js 项目
- 非常熟悉 Nuxt.js
- 至少百分之 10 的代码改动
二、初始化 NuxtJS
Nuxt 提供了两种方式用来创建项目:
- 使用 create-nuxt-app 脚手架工具
- 手动创建
为了让大家有一个更好的学习效果,这里我们建议先通过手动创建的方式来学习 Nuxt,熟悉了 Nuxt 的基本能使用之后,我们会在后面的综合案例中学习如何使用 create-nuxt-app 创建项目
2.1 准备
# 初始化 package.json 文件
npm init -y
# 安装 nuxt
npm install nuxt
- 在 package.json 文件的 scripts 中新增
"scripts": {
"dev": "nuxt"
}
上面的配置使得我们可以通过运行 npm run dev
来运行 nuxt
2.2 创建页面并启动项目
- 创建 pages 目录
- 创建我们的第一个页面
pages/index.vue
<template>
<h1>Hello world!</h1>
</template>
- 启动项目
npm run dev
或
yarn dev
- 现在我们的应用运行在
http://localhost:3000
上运行
注意:Nuxt.js 会监听 pages 目录中的文件更改,因此在添加新页面时无需重新启动应用程序
三、 Nuxt 中的路由
3.1 基础路由
- 官方文档
- Nuxt.js 会依据 pages 目录中的所有 *.vue 文件生成应用的路由配置
- 要在页面之间使用路由,我们建议使用
<nuxt-link>
标签 - 假设 pages 的目录结构如下:
pages/
--| user/
-----| index.vue
-----| one.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/one',
component: 'pages/user/one.vue'
}
]
}
3.2 路由导航
- a 标签
- 它会刷新整个页面,不建议使用
<nuxt-link>
组件- 编程式导航
<template>
<div>
<h1>About page</h1>
<!-- a 链接,刷新导航,走服务端渲染 -->
<h2>a 链接</h2>
<a href="/">首页</a>
<!-- nuxt-link 导航链接组件 -->
<h2>router-link</h2>
<nuxt-link to="/">首页</nuxt-link>
<!-- 编程式导航 -->
<h2>编程式导航</h2>
<button @click="onClick">首页</button>
</div>
</template>
<script>
export default {
name: 'AboutPage',
methods: {
onClick () {
this.$router.push('/')
}
}
}
</script>
3.3 动态路由
在 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'
}
]
}
pages/user/_id.vue
<template>
<div>
<h1>User Pages</h1>
<p>{{ $route.params.id }}</p>
</div>
</template>
<script>
export default {
name: "UserPage",
};
</script>
你会发现名称为 users-id 的路由路径带有 :id? 参数,表示该路由是可选的。如果你想将它设置为必选的路由,需要在 users/_id 目录内创建一个 index.vue 文件
3.4 路由参数校验
pages/users/_id.vue
export default {
validate({ params }) {
// 必须是number类型
return /^\d+$/.test(params.id)
}
}
如果校验方法返回的值不为 true 或 Promise 中 resolve 解析为 false 或抛出 Error , Nuxt.js 将自动加载显示 404 错误页面或 500 错误页面。
3.5 嵌套路由
- 你可以通过 vue-router 的子路由创建 Nuxt.js 应用的嵌套路由
- 创建内嵌子路由,你需要添加一个 Vue 文件,同时添加一个与该文件同名的目录用来存放子视图组件。注意: 别忘了在父组件(.vue文件) 内增加
<nuxt-child/>
用于显示子视图内容
假设文件结构如:
pages/
--| users/
-----| _id.vue
-----| index.vue
--| users.vue
Nuxt.js 自动生成的路由配置如下:
router: {
routes: [
{
path: '/users',
component: 'pages/users.vue',
children: [
{
path: '',
component: 'pages/users/index.vue',
name: 'users'
},
{
path: ':id',
component: 'pages/users/_id.vue',
name: 'users-id'
}
]
}
]
}
3.6 自定义路由配置
四、NuxtJS 视图
4.1 概述
- 在 NuxtJS 中页面结构一般由三部分组成
- 第一部分是最外层的文档页面,也就是单页面或者说服务端渲染的HTML页面
- 在 HTML 页面里面包裹着 Layout 布局组件(可选),相当于所有页面的父路由
- 再往里面是页面组件,每个页面组件有自己额外的成员方法,包括页面的子组件之类的可选内容
4.2 模板
- 你可以定制化 Nuxt.js 默认的应用模板
- 定制化默认的 html 模板,只需要在 src 文件夹下(默认是应用根目录)创建一个
app.html
的文件
默认模板为:
<!DOCTYPE html>
<html {{ HTML_ATTRS }}>
<head {{ HEAD_ATTRS }}>
{{ HEAD }}
</head>
<body {{ BODY_ATTRS }}>
{{ APP }}
</body>
</html>
可修改为:
<!DOCTYPE html>
<html {{ HTML_ATTRS }}>
<head {{ HEAD_ATTRS }}>
{{ HEAD }}
</head>
<body {{ BODY_ATTRS }}>
<!-- 渲染的内容最终会注入到这里 -->
<h1>app.html</h1>
{{ APP }}
</body>
</html>
4.3 布局
- Nuxt.js 允许你扩展默认的布局,或在 layout 目录下创建自定义的布局
- 可通过添加
layouts/default.vue
文件来扩展应用的默认布局
提示:别忘了在布局文件中添加
<nuxt/>
组件用于显示页面的主体内容。
默认布局的源码如下:
<template>
<nuxt />
</template>
layouts/default.vue
<!-- 一旦使用,默认所有页面都会作用,不能取消,只能更改 -->
<template>
<div>
<h1>layouts/default.vue 组件</h1>
<!-- 页面出口,类似于子路由出口 -->
<nuxt />
</div>
</template>
<script>
export default {
name: 'LayoutDefault'
}
</script>
然后我们必须告诉页面 (即 pages/index.vue
) 使用您的自定义布局:
<template>
<h1>Hello world!</h1>
</template>
<script>
export default {
name: 'HomePage',
// 默认 default 可修改
layout: 'default'
}
</script>
五、NuxtJS 异步数据
5.1 asyncData
Nuxt.js 扩展了 Vue.js,增加了一个叫
asyncData
的方法,使得我们可以在设置组件的数据之前能异步获取或处理数据
- 它会将 asyncData 返回的数据融合组件 data 方法返回的数据一并给组件
- 调用时机:服务端渲染期间和客户端路由更新之前
static/data.json
{
"posts": [
{
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
},
{
"id": 2,
"title": "qui est esse",
"body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla"
},
{
"id": 3,
"title": "ea molestias quasi exercitationem repellat qui ipsa sit aut",
"body": "et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut ad\nvoluptatem doloribus vel accusantium quis pariatur\nmolestiae porro eius odio et labore et velit aut"
},
{
"id": 4,
"title": "eum et est occaecati",
"body": "ullam et saepe reiciendis voluptatem adipisci\nsit amet autem assumenda provident rerum culpa\nquis hic commodi nesciunt rem tenetur doloremque ipsam iure\nquis sunt voluptatem rerum illo velit"
},
{
"id": 5,
"title": "nesciunt quas odio",
"body": "repudiandae veniam quaerat sunt sed\nalias aut fugiat sit autem sed est\nvoluptatem omnis possimus esse voluptatibus quis\nest aut tenetur dolor neque"
}
],
"title": "测试用例"
}
- NuxtJS 默认在 Web 服务中将数据暴露出来,可以直接通过 …/data.json 获取数据
- 假设想在首页直接获取数据(服务端获取异步数据):
npm i axios
pages/index.vue
<template>
<div>
<h1>Hello world!</h1>
<nuxt></nuxt>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'HomePage',
layout: 'default',
async asyncData () {
console.log('asyncData')
console.log(this)
const res = await axios({
method: 'GET',
url: 'http://localhost:3000/abc/data.json'
})
return res.data
},
data () {
return {
foo: 'bar'
}
}
}
</script>
asyncData 返回的数据融合组件 data 方法返回的数据一并给组件
注意:由于 asyncData 方法是在组件 初始化 前被调用的,所以在方法内是没有办法通过 this 来引用组件的实例对象
当你想要动态页面内容有利于 SEO ,或者是提升首屏渲染速度的时候,就在 asyncData 中发请求拿数据。如果是非异步数据或者普通数据,则正常的初始化到 data 中即可
服务端首屏渲染既能确保异步数据能在渲染到客户端之前已经被渲染好(提高首屏渲染速度,有利于SEO)。达到页面后又变成SPA客户端应用,同样可以被调用从而更新数据
5.2 上下文对象
六、NuxtJS 生命周期
七、Nuxt 项目发布部署流程
7.1 打包
- Nuxt 命令列表:https://www.nuxtjs.cn/guide/commands
- package.json
{
"scripts": {
"dev": "nuxt",
"build": "nuxt build",
"start": "nuxt start"
}
}
- 执行打包命令,打包文件存储在
.nuxt/dist
- 建议将
.nuxt
加入.npmignore
和.gitignore
文件中
- 建议将
npm run build
- 启动打包项目
npm run start
7.2 最简单的部署方式
- 配置 Host + Port
nuxt.config.js
server: {
// 此设置可监听所有的网卡地址
host: '0.0.0.0', // 默认localhost
port: 3000
}
- 压缩发布包
.nuxt
:Nuxt 打包生成的资源文件static
:项目静态资源nuxt.config.js
:提供给 Nuxt 服务package.json
:用于服务端第三方包的安装package-lock.json
:用于服务端第三方包的安装
- 把发布包传到服务端