我们把自己,用终将灰飞烟灭的纸币,寂寞地捆绑起来
我搜寻着记忆
给我留下长久回味的时刻
让我难以忘怀的分分秒秒,他们统统不是来自金钱或者财富
Nuxt 提供了两种方式用来创建项目: 使用 create-nuxt-app 脚手架工具、手动创建,下面以手动创建为例:
# 创建项目
mkdir nuxt-app-demo
# 进入项目
cd nuxt-app-demo
# 初始化 package.json 文件
npm init -y
# 安装 nuxt
npm install nuxt
在 package.json
文件的 scripts
中新增:
"scripts": {
"dev": "nuxt"
}
根路径创建 pages
目录:
mkdir pages
创建第一个页面的 pages/index.vue
:
<template>
<h1>Hello world!h1>
template>
npm run dev
新建 .gitignore
文件:
# 排除不需要用git托管的文件
node_modules
.nuxt
git branch
# 看本地当前所在分支,并且在当前分支前面加“*”号标记
git branch -r
# 查看远程分支,r是remote的简写
git branch _分支名
# 创建一个新的本地分支
git checkout 分支名
# 切换分支
git checkout -b 分支名
# 创建并切换分支
Nuxt.JS 官方文档
新建 pages/user/one
文件:
<template>
<h1>oneh1>
template>
主页
this.$router.push
编辑 pages/user/one
文件:
<template>
<div>
<h1>About pageh1>
<h2>a 链接h2>
<a href="/">首页a>
<h2>router-linkh2>
<router-link to="/">首页router-link>
<h2>编程式导航h2>
<button @click="onClick">首页button>
div>
template>
<script>
export default {
name: 'AboutPage',
methods: {
onClick () {
this.$router.push('/')
}
}
}
script>
动态路由指的是路径时动态的,路径中的某一部分是动态变化的,
需要用:
进行表征,使用?
表示是否必要
在 Nuxt.js 里面定义带参数的动态路由,需要创建对应的以下划线作为前缀的 Vue 文件 或 目录。
名称为 users-id 的路由路径带有 :id? 参数,表示该路由是可选的。如果你想将它设置为必选的路由,需要在 users/_id 目录内创建一个 index.vue 文件。
新建 pages/user/_id.vue
文件:
<template>
<div>
<h1>User Pagesh1>
<h2>{{ $route.params.id }}h2>
div>
template>
<script>
export default {
name: 'UserPage'
}
script>
新增一个 nuxt.config.js
文件进行配置:
/**
* Nuxt.js 配置文件
*/
module.exports = {
router: {
base: '/abc'
}
}
// 注意,这样配置后路由地址都应该以/abc开头:http://localhost:3000/abc/...
// 要是访问首页的话就是abc/,末尾的/不能省略
也可以使用 extendRoutes
方法
module.exports = {
router: {
base: '/abc',
// routes: 一个数组,路由配置表
// resolve: 解析路由组件路径
extendRoutes(routes, resolve) {
routes.push({
name: 'hello',
path: '/hello',
component: resolve(__dirname, 'pages/about.vue')
})
}
}
}
在 NuxtJS 中页面结构一般由三部分组成:
定制化默认的 html 模板,只需要在根目录(或者 src)创建一个 app.html
的文件:
DOCTYPE html>
<html {{ HTML_ATTRS }}>
<head {{ HEAD_ATTRS }}>
{{ HEAD }}
head>
<body {{ BODY_ATTRS }}>
{{ APP }}
body>
html>
可通过添加 layouts/default.vue
文件来扩展应用的默认布局:
<template>
<div>
<h2>layouts/default.vueh2>
<nuxt />
div>
template>
然后其他页面 (即 pages/index.vue
) 使用自定义布局:
<template>
<h1>Hello world!h1>
template>
<script>
export default {
name: 'HomePage',
// 在别的组件使用时指定layout:'foo' 也就是指定别的组件作为布局组件,也就是foo会代替default
layout: 'default' // 表示使用默认布局使用的是 layouts文件夹下面的default组件
}
script>
asyncData方法会在组件(限于页面组件)每次加载之前被调用。它可以在服务端或路由更新之前被调用。在这个方法被调用的时候,第一个参数被设定为当前页面的上下文对象,你可以利用 asyncData方法来获取数据,Nuxt.js 会将 asyncData 返回的数据融合组件 data 方法返回的数据一并返回给当前组件。
基本用法
注意事项
当你想用的动态页面内容有利于SEO或者是提升首屏渲染速度的时候,就在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": "文章数据"
}
安装 axios
:
npm i axios
在首页直接获取数据(服务端获取异步数据):
<template>
<div>
<h1>{{ title }}h1>
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/data.json'
})
return res.data
},
data () {
return {
foo: 'bar'
}
}
}
script>
如果我们尝试在asyncData里面进行console.log(‘xxx’)时,会发现在服务端的控制台输出xxx的同时,nuxt为了方便调试和更加直观,会让客户端也会输出xxx,并且客户端的xxx是包裹在Nuxt SSR对象中的,如果尝试打印this会发现是undefined,因为服务端渲染时组件还没初始化。
// pages/index.vue
<template>
<div>
<h1>{{ title }}h1>
<nuxt-link to="/about">Aboutnuxt-link>
div>
template>
<script>
import axios from 'axios'
export default {
name: 'HomePage',
layout: 'default',
async asyncData () {
console.log('xxx')
const res = await axios({
method: 'GET',
url: 'http://localhost:3000/data.json'
})
return res.data
},
data () {
return {
foo: 'bar'
}
}
}
script>
先通过地址访问首页,会发现客户端控制台打印Nuxt SSR下面输出了xxx,说明首屏是在服务端渲染的,然后输出了xxx。紧接着通过about路由导航链接跳转到about页面,然后about页面中也有个导航链接可以跳转到首页,此时跳转回首页时也会调用首页组件index.vue中的asyncData方法,此时也会打印xxx,但是这时候的xxx外层没有Nuxt SSR对象了,原因是这次导航跳转引起的调用是在客户端执行的
首屏服务端渲染数据好理解,直接拿到数据返回并返回了SPA页面脚本,但是如果客户端执行SPA程序时,不执行asyncData的话,将会导致数据无法更新,所以当我们通过导航链接进行跳转时也会在客户端进行一次调用asyncData
注意: asyncData只能在页面组件中使用,不能在非页面组件(比如页面组件的子组件)中使用,非页面组件中不会调用asyncData函数如果想在子组件使用服务端渲染时的数据,只能通过页面组件进行获取,然后再利用父子组件中的传值方法来传递给页面组件的子组件
页面组件的子组件:
// components/Foo.vue
<template>
<div>
<h1>FooPageh1>
<ul>
<li
v-for="item in posts"
:key="item.id"
>
{{ item.title }}
li>
ul>
div>
template>
<script>
export default {
name: 'FooPage',
props: ['posts'],
// asyncData 只能在页面组件中使用
// async asyncData () {
// console.log('foo asyncData')
// return {
// foo: 'bar'
// }
// }
}
script>
页面组件:
// pages/index.vue
<template>
<div>
<h1>{{ title }}h1>
<nuxt-link to="/about">Aboutnuxt-link>
<br>
<foo :posts="posts" />
div>
template>
<script>
import axios from 'axios'
import Foo from '@/components/Foo'
export default {
name: 'HomePage',
layout: 'default',
components: {
Foo
},
// 当你想要动态页面内容有利于 SEO
// 或者是提升首屏渲染速度的时候,
// 就在 asyncData 中发请求拿数据
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 中即可
data () {
return {
foo: 'bar'
}
}
}
script>
比如:
http:// localhost:3000/artical/5
这个路径就应该对应第五篇文章,那么问题是怎么获取这个5呢
首先我们容易想到路由对象this.$route.params
,但是asyncData
在服务端执行时是没有this
的,也就是说this
不指向当前Vue
实例
所以我们需要使用asyncData
中的上下文对象参数来获取,上下文对象中可以获取动态路由中的参数
// pages/article/_id.vue
// 根据路径中的最后一位id值的不同来拿到不同的对象,然后渲染页面中的不同内容
<template>
<div>
<h1>{{ article.title }}h1>
<div>{{ article.body }}div>
div>
template>
<script>
import axios from 'axios'
export default {
name: 'ArticlePage',
// asyncData 上下文对象
async asyncData (context) {
// 这里有我们需要的数据
console.log(context)
const { data } = await axios({
method: 'GET',
url: 'http://localhost:3000/data.json'
})
// asyncData 里面没有 this, 不能通过这种方式获取 id
// console.log(this.$route.params)
// 可以通过上下文对象的 params.id 或者 router.params.id
// 拿到后将字符串类型转换为数字类型
// 根据路径中的最后一位id值的不同来拿到不同的对象,然后渲染页面中的不同内容
const id = Number.parseInt(context.params.id)
return {
article: data.posts.find(item => item.id === id)
}
}
}
script>