前置知识
Nuxt.js简单的说是Vue.js的通用框架,最常用的就是用来作SSR(服务器端渲染)。
nuxt.js她简化了SSR的开发难度。那什么是ssr?
SSR,即服务器渲染,就是在服务器端将对Vue页面进行渲染生成html文件,将html页面传递给浏览器。
SSR有两个优点:
- SSR生成的HTML是有内容的,这让搜索引擎能够索引到页面内容。
- SSR直接将HTML字符串传递给浏览器。大大加快了首屏加载时间。
安装
首先你要有vue-cli,然后你就可以初始化
vue init nuxt/starter 项目名称
安装包依赖
npm install
启动
npm run dev
1.nuxt目录结构
|-- .nuxt // Nuxt自动生成,临时的用于编辑的文件,build
|-- assets // 用于组织未编译的静态资源入LESS、SASS 或 JavaScript
|-- components // 用于自己编写的Vue组件
|-- layouts // 布局目录,用于组织应用的布局组件,不可更改。
|-- middleware // 用于存放中间件
|-- pages // 用于存放写的页面,我们主要的工作区域,(组织应用的路由及视图。Nuxt.js 框架读取该目录下所有的 .vue 文件并自动生成对应的路由配置。)
|-- plugins // 用于存放JavaScript插件的地方
|-- static // 用于存放静态资源文件,比如图片
|-- store // 用于组织应用的Vuex 状态管理。
|-- .editorconfig // 开发工具格式配置
|-- .eslintrc.js // ESLint的配置文件,用于检查代码格式
|-- .gitignore // 配置git不上传的文件
|-- nuxt.config.json // 用于组织Nuxt.js应用的个性化配置,已覆盖默认配置
|-- package-lock.json // npm自动生成,用于帮助package的统一性设置的,yarn也有相同的操作
|-- package-lock.json // npm自动生成,用于帮助package的统一性设置的,yarn也有相同的操作
|-- package.json // npm包管理配置文件
(1)引用静态文件
Nuxt 服务器启动后,会将static文件目录映射到根路径/下。
所以想引用static目录下图片,直接写法如下
<img src="/log.png"/>
引用 assets 目录下经过 webpack 构建处理后的图片,写法如下
<img src="~/assets/logo.png"/>
将项目中template需要的样式文件js文件等都可以放置在assets中,走打包这一流程,减少体积。而项目中引入的第三方的资源文件如font-awesome.css等文件可以放置在static中,因为这些引入的第三方文件已经经过处理,我们不再需要处理,直接上传。
(2)components 组件目录
一般用来存放 非页面级别 的组件,如 header、footer 等公共组件
该目录下的组件具有常规 vue 组件的方法和特性,不会被 nuxt.js 扩展特性
比如说我的default布局为上中下
我的公共组件模版写在components中
(3)中间件
中间件允许您定义一个自定义函数运行在一个页面或一组页面渲染之前。
中间件执行流程顺序:
1.nuxt.config.js
2.匹配布局
3.匹配页面
中间件可以异步执行,只需要返回一个 Promise 或使用第2个 callback 作为第一个参数:middleware/stats.js
import axios from 'axios'
export default function ({ route }) {
return axios.post('', {
url: route.fullPath
})
}
然后在你的 nuxt.config.js 、 layouts 或者 pages 中使用中间件:
nuxt.config.js:
module.exports = {
router: {
middleware: 'stats'
}
}
现在,中间件将在每个路由改变时被调用。
也可以将 middleware 添加到指定的布局或者页面:
pages/index.vue 或者 layouts/default.vue
export default {
middleware: 'stats'//你中间件文件名
}
3.nuxt常用配置项(nuxt.config.js)
(1)要是常用端口被占用,或者要指定ip的情况
需要在根目录下的package.json里对config项进行配置。(比如我现在重新配置了ip,和端口)
现在重新npm run dev后,你会发现他改变啦。
(2)怎么配置全局的css
我们在项目里会定义一个全局的css来初始化渲染,比如说我们要把页面的margin值设置为0。
先在/assets/css/demo.css
目录下设置
html{
margin:0;
}
再在/nuxt.config.js
里进行操作。
//引入css文件
css: [
// 项目里要用的 全局CSS 文件
'@/assets/css/demo.css',
// 项目里要使用的 less 文件 ~:是找到根目录
'~assets/css/demo2.scss'
],
设置好后,你页面的margin初始化值就为0啦。
(3)配置webpack的loader(要熟悉webpack配置|看|)**
比如现在我们要配置一个url-loader来进行小图片的64位打包。
在/nuxt.config.js的build选项里进行配置,
(4)可以在head标签里面配置一些自定义的meta标签,和style样式文件
//更改页面名称
title: 'nuxtdemo',
// 适配
meta: [
{charset: 'utf-8'},
{name: 'viewport', content: 'width=device-width, initial-scale=1'},
{hid: 'description', name: 'description', content: 'Nuxt.js project'}
],
link: [
{rel: 'icon', type: 'image/x-icon', href: '/favicon.ico'}
]
(4)loading的配置
在页面切换的时候,Nuxt.js 使用内置的加载组件显示加载进度条。你可以定制它的样式,禁用或者创建自己的加载组件。
//可以使用nuxt内置的加载进度条,也可以自定义样式。
// 在组件中可以使用this.$nuxt.$loading.start()来开启进度条,通过this.$nuxt.$loading.finish()来关闭进度条,
// 为了确保进度条运行没有问题,把它放在this.$nextTick(() => {}中执行 (将回调延迟到下次 DOM 更新循环之后执行)
mounted () {
this.$nextTick(() => {
//开启进度条
this.$nuxt.$loading.start()
//关闭进度条
setTimeout(() => this.$nuxt.$loading.finish(), 500)
})
}
// 页面切换的时候如果不想要进度条的话在nuxt.config.js中配置
module.exports = {
loading: false
}
进度条的配置项如下
比如说我想配置一个6像素的红色进度条,那么在/nuxt.config.js中配置
loading: {
color: 'red',
height: '6px'
},
那么你运行项目时,上方就会出现进度条展现加载速度。
也可以自定义加载组件代替默认的,需要在 loading 配置项里指定组件的路径,Nuxt.js 会自动调用该组件。
比如我在componentes下创建了一个Loading.vue
<template lang="html">
<div class="loading-page" v-if="loading">
<p>Loading...</p>
</div>
</template>
<script>
export default {
data: () => ({
loading: false
}),
methods: {
start() {
this.loading = true
},
finish() {
this.loading = false
}
}
}
</script>
<style scoped>
.loading-page {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(255, 255, 255, 0.8);
text-align: center;
padding-top: 200px;
font-size: 30px;
font-family: sans-serif;
}
</style>
然后我们要在nuxt.config.js
告诉 Nuxt.js 使用自定义加载组件:
module.exports = {
loading: '~/components/loading.vue'
}
就会出现如小图所示的自定义loading
(5)plugins配置
plugins 属性使得你可以轻易地为 Nuxt.js 配置使用 Vue.js 插件。
比如说我们想使用 vue-notifications 显示应用的通知信息,我们需要在程序运行前配置好这个插件。
首先增加文件 plugins/vue-notifications.js
import Vue from 'vue'
import VueNotifications from 'vue-notifications'
Vue.use(VueNotifications)
然后, 在 nuxt.config.js 内配置 plugins
module.exports = {
plugins: ['~/plugins/vue-notifications']
}
(6)router的配置
如果每个页面都要经过pages可以在nuxt.config.js中配置
//router的配置
router: {
base: '/pages/',
// routeNameSplitter可以更改路由的路径格式
routeNameSplitter: '/',
// linkActiveClass 全局通过路由默认激活的类
linkActiveClass: 'active-link',
// linkExactActiveClass:路由默认精确的活动类
linkExactActiveClass: 'exact-active-link',
},
(7)transition配置
//页面过渡的配置
transition: {
name: 'page',
mode: 'out-in',//更多模式详见 Vue.js transition 的使用
beforeEnter(el) {
console.log('Before enter...',el);
}
},
4.路由配置,子路由和参数传递
(1)路由配置
我在pages目录下的index中link了两个页面
目录结构是这样的
pages下面的目录结构就对应了我们要访问的路由,nuxt.js为我们配置好了路由,我们不用再手动配置。
(2)参数传递
params传递参数,我向about页面传递个参数,然后在about页面进行接收。
然后我在about下的index中用$route.params.newsId进行接收
(3)子路由
需要添加一个 Vue 文件,同时添加一个与该文件同名的目录用来存放子视图组件。
别忘了在父组件(.vue文件) 内增加 用于显示子视图内容。
这样就相当于user文件里的index.vue,是user.vue的子路由。
5.动态路由和参数校验
动态路由
我在about下面创建了_id.vue
的文件,以下画线为前缀的Vue文件就是动态路由。
用$route.params.id
来接收参数。
然后在我们在/pages/about/index.vue进行修改,增加两个详细页的路由about-1和about-2。
不用a标签,用nuxt-link
动态参数校验
进入一个页面,对参数传递的正确性校验是必须的,Nuxt.js为我们准备了校验方法validate( )。
如果校验方法返回的值不为 true或Promise中resolve 解析为false或抛出Error , Nuxt.js 将自动加载显示 404 错误页面或 500 错误页面。
6.nuxt的路由动画
7.默认模版和默认布局
改模版就要重新启动服务器。
建立一个公共模版,新建app.html,因为head在config.js中已经配置好了,所以直接引入(注意要大写)。
删除模版的时候,先关闭服务再启动。
默认布局:只能定义template里面的东西,不需要重新启动服务器。一般用这个默认布局就可以。
8.错误页面设置
9.meta标签设置
为了利于seo,需要每个页面对新闻都有不同的title和meta设置.
(1)先把pages/news/index.vue下的link进行修改,添加title(这里路由传参,网上很多name后传递的是news-id这种形式,但是我这样传递报错找不到_id,这样news/id,可以找到,可以在你的.nuxt里面router.js查看生成的你的具体路由name还有path等信息)
(2)修改/pages/news/_id.vue,让它根据传递值变成独特的meta和title标签。(如果hid没有覆盖以前的head,就会出现两个meta)
在nuxt.config.js里原本的配置
10.异步请求获取数据
在初始化页面前先得到数据,Nuxt.js为我们扩展了Vue.js的方法,增加了anyncData.
安装axiosnpm install axios --save
注意!!!
asyncData 是最常用最重要的生命周期,同时也是服务端渲染的关键点。该生命周期只限于页面组件调用,第一个参数为 context。它调用的时机在组件初始化之前,运作在服务端环境。所以在 asyncData 生命周期中,我们无法通过 this 引用当前的 Vue 实例,也没有 window 对象和 document 对象,这些是我们需要注意的。
一般在 asyncData 会对主要页面数据进行预先请求,获取到的数据会交由服务端拼接成 html 返回前端渲染,以此提高首屏加载速度和进行 seo 优化。
asyncData 只在首屏被执行,其它时候相当于 created 或 mounted 在客户端渲染页面。
举个🌰:
现在有两个页面,分别是首页和详情页,它们都有设置 asyncData。进入首页时,asyncData 运行在服务端。渲染完成后,点击文章进入详情页,此时详情页的 asyncData 并不会运行在服务端,而是在客户端发起请求获取数据渲染,因为详情页已经不是首屏。当我们刷新详情页,这时候详情页的 asyncData 才会运行在服务端。所以,不要走进这个误区(诶,不是说服务端渲染吗,怎么还会发起请求?)。
(1)我在pages下面新建了一个asyncData.vue,用axios获取json假数据。
不用上面的方法用ansyc…await来获取数据
(2)在utils文件夹下面新增加一个http.js封装axios
import axios from 'axios';
//携带证书
axios.defaults.withCredentials = true;
//设置超时时间
axios.defaults.timeout = 100000;
export default {
//get请求
requestGet(url, params = {}) {
return new Promise((resolve, reject) => {
axios.get(url, params).then(res => {
resolve(res.data)
}).catch(error => {
reject(error)
})
})
},
// post请求
requestPost(url, params = {}) {
return new Promise((resolve, reject) => {
axios.post(url, params).then(res => {
resolve(res.data)
}).catch(error => {
reject(error)
})
})
},
// delete请求
requestDelete(url, params = {}) {
return new Promise((resolve, reject) => {
axios.delete(url, params).then(res => {
resolve(res.data)
}).catch(error => {
reject(error)
})
})
},
// put请求
requestPut(url, params = {}) {
return new Promise((resolve, reject) => {
axios.put(url, params).then(res => {
resolve(res.data)
}).catch(error => {
reject(error)
})
})
}
}
然后在页面上请求
//这里请求数据
asyncData(){
// console.log();
http.requestGet('url').then(res => {
console.log(res.data);
})
},
11.静态资源打包
12.引入外部ui
按需引入ant-design
安装:npm install ant-design-vue --save
安装 babel-plugin-import来进行按需加载。:npm install babel-plugin-import --save-dev
(1)在plugins文件下面创建一个antd.js
(2)插件配置 nuxt.config.js
13.Nuxt.js国际化vue-i18n的搭配使用
找了几个文章
可以看这个文章nuxt国际化
国际化步骤
可以去官网案例中直接copy
参考文章nuxt国际化
踩坑记录
(1)connect ECONNREFUSED 127.0.0.1:80 at TCPConnectWrap.afterConnect [as oncomplete] 异常的解决。
运行项目axios获取后台数据然后报了这个错。
如果我不使用async asyncData方法去请求后台地址刷新页面就没问题。解决方案是修改了
"config": {
"nuxt": {
//这里改成0.0.0.0
"host": "0.0.0.0",
"port": "80"
}
}
然后就好了