主题
Nuxt.js 基础
一、安装
1. 使用淘宝镜像
bash
npm config set registry https://registry.npmmirror.com2. 脚手架安装
bash
npx create-nuxt-app nuxtApp
# 或
yarn create nuxt-app <my-project>3. 配置端口
package.json:
json
"config": {
"nuxt": {
"port": "3002"
}
}提示:不能使用6666等特殊端口,否则无法打开网页
4. 运行 npm run dev
二、目录结构
1. assets(资源目录)
存放需要webpack编译的静态资源如Less、SASS或JavaScript
引用地址:@/assets
2. static(静态文件目录)
存放不需要webpack编译的资源如图片
服务器启动的时候,该目录下的文件会映射到应用的根路径/下
引用地址:/
3. components(组件目录)
Nuxt不会扩展增强该目录下Vue.js组件,即这些组件不会像页面组件那样有asyncData方法等特性
4. layouts(布局目录)
用于组织应用的布局组件
5. middleware(中间件目录)
用于存放应用的中间件(会在页面渲染之前被调用,相当于导航守卫)
6. pages(页面目录)
Nuxt.js 框架读取该目录下所有的 .vue 文件并自动生成对应的路由配置
7. plugins(插件目录)
用于组织那些需要在 根vue.js应用 实例化之前需要运行的 Javascript 插件,如element-ui
8. store(目录)
在 store 目录下创建一个 index.js 文件可激活Vuex
9. nuxt.config.js(nuxt配置文件)
10. 别名
@对应着文件根目录
三、页面组件
在pages文件夹下定义的.vue文件,都是页面组件;页面组件相比于Vue组件,多了一些特殊的配置项
vue
<script>
export default {
data() {
return {
name: "",
};
},
/* 获取数据生命周期,在服务端被调用,返回值设置组件的数据*/
asyncData() {
return { name: "world" };
},
/* 用于在渲染页面之前填充状态树(store)数据,不会设置组件的数据*/
fetch() {},
/* 设置当前页面的Meta标签 */
head() {},
/* 指定当前页面使用的布局,默认使用layouts目录下的default.vue*/
layout() {},
loading() {},
/* 指定页面切换的过渡动效 */
transition() {},
// 布尔值,默认false,用于判定渲染页面前是否需要将当前页面滚动至顶部。
//用于嵌套路由的应用场景
scrollToTop() {},
/* 校验动态路由参数 */
validate() {},
/* 指定页面的中间件,中间件会在页面渲染之前被调用;相当于导航守卫*/
middleware() {},
//为查询字符串设置一个监视器
//如果定义的字符串发生变化,所有的组件方法都会被调用(fetch除外)
//默认情况下,返回值为false,以提高性能
watchQuery() {
return boolean;
},
};
</script>四、asyncData
用来获取接口数据。第一个参数获取当前页面的上下文对象(可获取路由参数)。asyncData返回的数据融合组件data方法返回的数据一并返回给当前组件
注意:由于asyncData方法是在组件初始化前被调用的,所以在方法内是没有办法通过 this 来引用组件的实例对象。
js
export default {
async asyncData({ params }) {
const { data } = await axios.get(`https://my-api/posts/${params.id}`);
return { title: data.title };
},
};js
/* 并发请求 */
async asyncData() {
let [a, b] = await Promise.all([API.getContactList(), API.getUser()]);
return {
contactList: a.data.data,
user: b.data.data,
};
},五、路由
路由
六、视图
1. 默认布局
@/layouts/default.vue。
vue
<template>
<div>
<p>文杰的博客</p>
<nuxt />
</div>
</template><nuxt/> 组件用于显示页面的主体内容
2. 自定义布局
layouts 目录中的每个文件都将创建一个可通过页面组件中的 layout 属性访问的自定义布局。
假设我们要创建一个 博客布局 并将其保存到layouts/blog.vue:
vue
<template>
<div>
<div>我的博客导航栏在这里</div>
<nuxt />
</div>
</template>然后我们必须告诉页面 (即pages/posts.vue) 使用自定义布局:
vue
<script>
export default {
layout: "blog",
};
</script>3. 错误页面
可以通过编辑 layouts/error.vue 文件来定制化错误页面
警告: 虽然此文件放在 layouts 文件夹中, 但应该将它看作是一个 页面(page).
vue
<template>
<div>
<h2 v-if="error.statusCode == 404">404页面不存在</h2>
<h2 v-else>500服务器错误</h2>
<ul>
<li><nuxt-link to="/">HOME</nuxt-link></li>
</ul>
</div>
</template>
<script>
export default {
props: ["error"],
};
</script>七、baseURL多环境配置
运行
bash
npm i @nuxtjs/dotenv cross-env -S在nuxt.config.js中配置modules模块
js
module.exports = {
modules: [
["@nuxtjs/dotenv"], //默认读取目录下的.env文件
],
};新建.env文件
bash
DEV_BASE_URL = 'localhost:9000/api'
PROD_BASE_URL = 'https://www.example.com/api'在nuxt.config.js中
js
require("dotenv").config();
let baseUrl = "";
switch (process.env.BASE) {
case "dev":
baseUrl = process.env.DEV_BASE_URL;
break;
case "pro":
baseUrl = process.env.PROD_BASE_URL;
break;
default:
baseUrl = process.env.PROD_BASE_URL;
break;
}
export default {
env: {
baseUrl: baseUrl,
},
};在package.json中配置启动命令
json
"scripts": {
"dev": "cross-env NODE_ENV=development BASE=dev nuxt",
"build": "nuxt build",
"start": "cross-env MODE=production BASE=pro nuxt start",
"generate": "nuxt generate"
},现在 process.env.baseUrl 可以在全局进行访问
八、axios
前提:在nuxt中使用axios中进行跨域代理时,发现寻常代理方式不起作用,只能使用官方推荐的工具
1. 安装
bash
npm i @nuxtjs/axios @nuxtjs/proxy -D2. 在nuxt.config.js中进行配置
js
modules: [
'@nuxtjs/axios',
'@nuxtjs/proxy'
],
axios: {
prefix: "/juhe",
credentials: true,
proxy: true
},
proxy: {
'/juhe': {
target: 'https://v.juhe.cn',
changeOrigin: true,
pathRewrite: {
"^/juhe": ""
}
},
}3. 使用
html
<template>
<article>
<card :url="'/toutiao.png'" :source="List">今日头条</card>
</article>
</template>js
export default {
data() {
return {
contactList: [],
};
},
//请求数据的方法(相当于vue中的created)
async asyncData({ app }) {
let params = {
type: "top",
key: "your_api_key",
};
let { data } = await app.$axios("/toutiao/index", { params: params });
return {
contactList: data.data,
};
},
//methods/created/mounted中使用
mounted() {
let params = {
type: "guonei",
key: this.$store.state.key,
};
this.$axios("/toutiao/index", { params: params });
},
};4. 配置拦截器
nuxt.config.js
js
plugins: ["@/plugins/axios"];plugins/axios.js
js
export default function ({ $axios, redirect }) {
$axios.setHeader("Authorization", "123");
$axios.onRequest((config) => {
console.log("Making request to " + config.url);
});
$axios.onError((error) => {
const code = parseInt(error.response && error.response.status);
if (code === 400) {
redirect("/400");
}
});
}五种拦截情况:
- onRequest(config)
- onResponse(response)
- onError(err)
- onRequestError(err)
- onResponseError(err)
参考网址:http://www.axios-js.com/zh-cn/docs/nuxtjs-axios.html
九、配置
1. build
(1)analyze
例:使用webpack-bundle-analyzer来查看打包的大小
安装:
bash
npm install webpack-bundle-analyzer --save-dev在nuxt.config.js文件build中增加配置
js
build: {
analyze:true,
}运行:
bash
npm run build --analyze(2)babel
自定义babel配置
例:按需引入element-ui
1.安装
bash
npm install babel-plugin-component -D- 在nuxt.config.js文件中build对象下添加配置
js
babel: {
'plugins': [
[
'component',
{
'libraryName': 'element-ui',
'styleLibraryName': 'theme-chalk'
}
]
],
'comments': true
}- 修改plugins文件夹下element-ui.js
js
import { Pagination, Tag } from "element-ui";
Vue.use(Pagination, { locale });
Vue.use(Tag, { locale });(3)crossorigin
类型:string
默认:undefined
在生成的 HTML 中的 <link rel="stylesheet"> 和 <script> 标记上配置 crossorigin 属性
(4)extractCSS
类型:Boolean
默认:false
使用extract-css-chunks-webpack-plugin将主块中的 CSS 提取到一个单独的 CSS 文件中(自动注入模板),该文件允许单独缓存文件。当有很多共用 CSS 时建议使用此方法,异步组件中的 CSS 将保持内联为 JavaScript 字符串并由 vue-style-loader 处理
(5)optimization
webpack代码压缩、拆包
(6)optimizeCSS
优化css,可与extractCSS配合使用
(7)plugins
配置webpack插件
例:配置编译后的全局变量
js
import webpack from 'webpack'
plugins: [
new webpack.DefinePlugin({
version: 'v1',
}),
],全局访问version可得到v1
(8)transpile
将库使用babel进行转换
例:element-ui
安装
bash
npm i element-ui -S在plugins文件夹下面,新建element-ui.js文件
js
import Vue from "vue";
import Element from "element-ui";
import locale from "element-ui/lib/locale/lang/en";
Vue.use(Element, { locale });在nuxt.config.js中增加配置
js
//全局css配置
css: [
'element-ui/lib/theme-chalk/index.css'
],
//第三方插件配置
plugins: [
'@/plugins/element-ui'
],
//打包配置
build: {
//使用babel转换element-ui
transpile: [/^element-ui/],
}2. CSS
配置全局CSS,scss文件
js
// Global CSS (https://go.nuxtjs.dev/config-css)
css: [
'@/assets/css/normalize.css',
'@/assets/css/main.scss'
],3. styleResources
配置全局scss、less变量
安装scss
bash
npm install sass sass-loader@^10.5.2 -D运行:
bash
npm i @nuxtjs/style-resources --save--dev在nuxt.config.js中配置:
js
modules: ['@nuxtjs/style-resources'],
styleResources: {
scss: './assets/variables.scss',
less: './assets/**/*.less'
// sass: ...
}4. generate
在 Nuxt.js 执行 generate 命令时,动态路由 会被忽略
通过此配置使静态页面生成动态路由
https://www.nuxtjs.cn/api/configuration-generate
5. head
配置应用默认的 meta 标签
6. loading
配置页面切换时,顶部加载进度条
https://www.nuxtjs.cn/api/configuration-loading
7. modules
扩展nuxt功能,比如axios,pwa等
8. plugins
该配置项用于配置那些需要在 根vue.js应用 实例化之前需要运行的 Javascript 插件
十、个性meta设置
页面的Meta对于SEO的设置非常重要
vue
<script>
export default {
//独立设置head信息
head() {
return {
title: "",
meta: [
{ hid: "description", name: "news", content: "This is news page" },
],
};
},
};
</script>注意:为了避免子组件的meta标签不能正确覆盖父组件中相同的标签而产生重复的现象,建议使用hid键位meta标签配一个唯一的标识编号
十一、插件
插件
十二、Vuex状态树
Nuxt.js会根据store目录结构自动创建Vuex状态库
在store下新建index.js,Nuxt.js则会自动启用Vuex。
1. ~store/index.js
js
export const state = () => ({
counter: 0,
});
export const mutations = {
increment(state) {
state.counter++;
},
};index.js则是主仓库,有state,mutations ,actions,getters
在store下再新建其他js文件,则会自动创建以该文件名为名称的模块,并且自动添加命名空间。
2. ~store/todo.js
在store下创建todos.js
js
export const state = () => ({
list: [],
});
export const mutations = {
add(state, text) {
state.list.push({
text,
done: false,
});
},
remove(state, { todo }) {
state.list.splice(state.list.indexOf(todo), 1);
},
toggle(state, todo) {
todo.done = !todo.done;
},
};Vuex将如下创建
js
new Vuex.Store({
state: () => ({
counter: 0,
}),
mutations: {
increment(state) {
state.counter++;
},
},
modules: {
todos: {
namespaced: true,
state: () => ({
list: [],
}),
mutations: {
add(state, { text }) {
state.list.push({
text,
done: false,
});
},
remove(state, { todo }) {
state.list.splice(state.list.indexOf(todo), 1);
},
toggle(state, { todo }) {
todo.done = !todo.done;
},
},
},
},
});3. 在组件中使用
vue
<template>
<div>
<h2>About Index page</h2>
<li v-for="(todo, index) in list" :key="index">
<input type="checkbox" :checked="todo.done" @change="toggle(todo)"/>
<span :class="{ done: todo.done }">{{ todo.text }}</span>
</li>
<li>
<input placeholder="What needs to be done?" @keyup.enter="addTodo"/>
</li>
</ul>
</div>
</template>
<script>
import { mapMutations , mapState} from "vuex";
export default {
computed: {
...mapState('todos',[
'list'
])
// list() {
// return this.$store.state.todos.list;
// },
},
methods: {
addTodo(e) {
this.add(e.target.value);
// this.$store.commit('todos/add',e.target.value)
e.target.value = "";
},
...mapMutations('todos',[
'toggle',
'add'
]),
},
};
</script>
<style>
.done {
text-decoration: line-through;
}
</style>(1)取值
在computed中,通过函数的方式取值
js
computed: {
list() {
return this.$store.state.todos.list;
},
},或利用mapState函数
js
import { mapState } from "vuex";
computed: {
...mapState('todos',[
'list'
])
},mapState第一个参数,是模块的名称,在nuxt.js中也就是创建的文件名。第二个参数可以是个数组,里面是String类型,放置属性名称
(2)改变state状态(mutations)
在methods中,通过this.$store.commit()方式改变state值
todos/add:第一个是模块名称,第二个是方法
js
import { mapMutations } from "vuex";
methods: {
addTodo(e) {
this.$store.commit('todos/add',e.target.value)
e.target.value = "";
},
},或利用mapMutations函数
js
import { mapMutations } from "vuex";
methods: {
addTodo(e) {
this.add(e.target.value);
e.target.value = "";
},
...mapMutations('todos',[
'toggle',
'add'
]),
},十三、fetch方法
fetch方法会在渲染页面前被调用,作用是填充状态树(store)数据,与asyncData方法类似,不同的是它不会设置组件的数据。
fetch方法的第一个参数是页面组件的上下文对象context,可通过解构取得想要的值
警告: 您无法在内部使用this获取组件实例,fetch是在组件初始化之前被调用
1. 直接在fetch中调用接口
例如 pages/index.vue:
vue
<template>
<h1>Stars: {{ $store.state.stars }}</h1>
</template>
<script>
export default {
async fetch({ store, params }) {
let { data } = await axios.get("http://my-api/stars");
store.commit("setStars", data);
},
};
</script>调用mutation方法需要同步,这里通过async与await方法,在调完接口之后再执行store.commit方法
2. 将接口定义在actions中
store/index.js
js
export const actions = {
async GET_STARS({ commit }) {
const { data } = await axios.get("http://my-api/stars");
commit("SET_STARS", data);
},
};调用
vue
<script>
export default {
async fetch({ store, params }) {
await store.dispatch("GET_STARS");
},
};
</script>3. 监听query字符串的改变
默认情况下,不会在查询字符串更改时调用fetch方法。如果想更改此行为,例如,在编写分页组件时,您可以设置通过页面组件的watchQuery属性来监听参数的变化
类型: Boolean or Array (默认: [])
使用watchQuery属性可以监听参数字符串的更改。 如果定义的字符串发生变化,将调用所有组件方法(asyncData, fetch, validate, layout, ...)。 为了提高性能,默认情况下禁用。
如果您要为所有参数字符串设置监听, 请设置: watchQuery: true.
js
export default {
watchQuery: ["page"],
};十四、打包
1. 打包静态资源
步骤一:首先关闭其他环境的服务
步骤二:在nuxt.config.js下增加配置
js
export default {
target: "static",
};步骤三:运行npm run generate
步骤四:可以运行 npm start 起本地服务,查看页面效果
步骤五:配置Nginx
在Nginx服务下,创建static目录,并将dist文件拷贝到其中(dist文件是外部的,不是.next文件夹中的)
nginx
server {
listen 9001;
server_name localhost;
location / {
root static/dist;
try_files $uri $uri/ /index.html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}步骤六:http://localhost:9001/#/ 通过地址查看演示效果
2. 打包SSR资源
与PM2结合使用
(一)修改nuxt.config.js
删除打包静态资源配置的 target: 'static',
(二)在根目录下新建ecosystem.config.js
js
module.exports = {
apps: [
{
name: "nuxtApp",
exec_mode: "cluster",
instances: "max", // Or a number of instances
script: "./node_modules/nuxt/bin/nuxt.js",
args: "start",
env: {
PORT: 3002,
NODE_ENV: "production",
},
},
],
};(三)项目运行:npm run build
(四)将.nuxt,static,nuxt.config.js,package.json,ecosystem.config.js五个文件压缩上传到服务器
(五)在服务器上进行编译,在该目录下运行 npm i
(六)运行
bash
pm2 start npm --name "nuxtApp" -- start(七)配置Nginx
nginx
#node 服务
server {
listen 443 ssl; #SSL协议访问端口号为443。此处如未添加ssl,可能会造成Nginx无法启动。
server_name www.example.com; #将localhost修改为您证书绑定的域名,例如:www.example.com。
#root html;
# index.html index.htm;
ssl_certificate domain/nuxt.pem; #将domain name.pem替换成您证书的文件名。
ssl_certificate_key domain/nuxt.key; #将domain name.key替换成您证书的密钥文件名。
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; #使用此加密套件。
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #使用该协议进行配置。
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://localhost:3002/;
}
# etag on;
# expires 7d;
}注意点:之前一直想找HTML静态文件,但这是SSR渲染,是node服务,所以只需配置代理路径即可 http://127.0.0.1:3002;
提示:之前写的代理路径为http://127.0.0.1:3002,但是网页报502,查看运行日志发现,启动改为了http://localhost:3002/