1. 异步数据 AsyncData
1.1 获取并返回数据
AsyncData:在设置组件之前能异步获取或处理数据。async方法会在页面组件每次加载之前调用(没有this),可以在服务端或路由更新之前调用。在这个方法调用的时候,第一个参数被设定为当前页面的上下文对象,可以利用asyncData方法来获取数据,nuxt.js会将asyncData返回的数据融合组件data返回的数据一并返回给当前组件。
在详情页面使用asyncData调用并返回数据:
pages/detail/_id.vue
export default Vue.extend({
asyncData({params}) {
console.log(params, '当前params指代的是什么内容') // params指代路径参数,比如详情页面路径上的id
return axios.get('http://127.0.0.1:8090/api/fruits').then(({data}) => {
console.log(data.dataSource, '返回结果') // 接口返回值
return {
list: data.dataSource // return中返回的值和设置的属性,会合并到data中
}
})
},
})
- 可以通过Promise、async/await、callback方式来处理返回值,以上述为例,通过Promise方式调用接口return一个属性,属性的值为对应接口的值,这个属性和值会同时被合并到data中,在页面加载完成后即可使用
1.2 处理异步请求
当发起网络请求时,我们通常可能需要对headers中增加信息进行校验,也可能需要对返回的response信息进行处理,可以通过进行封装Axios,增加拦截器来进行处理
- 封装自己的带有拦截器的Axios request/index.js
import axios from "axios";
const myAxios = axios.create({
baseURL: 'http://127.0.0.1:8090/api'
})
myAxios.interceptors.request.use(
(req) => {
req.headers.Authorization = 'XXX' // 在headers中增加信息进行校验等...
return req
}
)
myAxios.interceptors.response.use(
(res) => {
return {
data: res.data
}
}, // 正确返回时处理response返回至
(err) => {
console.log(err)
// return Promise.reject(err)
} // 发生错误时,处理错误信息
)
export default myAxios
- 在页面使用封装拦截后的Axios
import myAxios from "~/request";
async asyncData() {
try {
let { data } = await myAxios.get('http://127.0.0.1:8090/api/fruits')
return {
list: data.dataSource || []
}
}catch (err) {
console.log(err.message)
// alert(err.message)
}
},
2. 插件
2.1 注入Vue实例
若有需要用到相关的插件,在vue.js执行前进行执行,比如Toast组件,要做到以下几步
2.1.1 自定义Toast插件
components/Toast.vue
<template>
<transition name="fade">
<div v-if="visible" class="toast">
{{ message }}
</div>
</transition>
</template>
<script>
export default {
data() {
return {
visible: false,
message: ''
};
},
methods: {
show(msg, duration = 2000) {
this.message = msg;
this.visible = true;
setTimeout(() => {
this.visible = false;
}, duration);
}
}
};
</script>
<style scoped>
.toast {
width: 200px;
height: 100px;
border-radius: 36px;
background-color: green;
color: blue;
position: fixed;
left: 50%;
top: 40px;
transform: translateX(-50%);
z-index: 2;
display: flex;
justify-content: center;
align-items: center;
}
.fade-enter-active, .fade-leave-active {
transition: opacity 0.5s;
}
.fade-enter, .fade-leave-to /* .page-leave-active 在 <2.1.8 版本中 */ {
opacity: 0;
}
</style>
2.1.2 声明插件
plugins/toast.js
import Vue from 'vue';
import Toast from '~/components/Toast.vue';
const ToastConstructor = Vue.extend(Toast);
const instance = new ToastConstructor();
// 将实例挂载到body上
instance.$mount(document.createElement('div'));
document.body.appendChild(instance.$el);
// 注入到Vue原型上
Vue.prototype.$toast = (msg, duration) => {
instance.show(msg, duration);
};
2.1.3 配置插件
nuxt.config.js
export default {
plugins: [
'~/plugins/toast.js'
],
}
2.1.4 页面使用
this.$toast(`Hello 用户${this.currentId}`, 1000)
2.2 注入$root和context
在2自定义插件中,我们将Toast注入Vue实例,通过$toast在Vue组件中进行使用这个函数,除此之外,我们还可以注入context
2.2.1 注入context
context注入也是plugins插件中的一种,我们可以在context上面定义一些方法,比如说是一些通用的公共的方法,在每一次需要context以及这个方法时直接调用,而不用重复写多次代码
- plugins/ctx-inject.js
export default ({ app }, inject) => {
app.myInjectedFunction = (string) => { // 可以传参
console.log(app, 'app是什么') // Vue实例
console.log(inject, 'inject是什么') // inject方法
console.log('Okay, another function', string) // 定义某种具体的操作
}
}
- nuxt.config.js
plugins: [
'~/plugins/ctx-inject.js',
],
- 页面使用 xx.vue
async asyncData(context) {
context.app.myInjectedFunction('use context 注入')
}
2.3 同时注入
上述2.2注入context的方式只限于在使用上下文时进行使用,如果我们想在context、Vue实例甚至是Vuex中同时注入,我们可以依然可以通过inject方法来实现一个更加完美的方式
- plugins/combine-inject.js
export default ({ app }, inject) => {
inject('myCombineInjectFunction', params => console.log('Okay, this combine inject', params))
}
- nuxt.config.js 中配置
plugins: [
'~/plugins/combine-inject.js'
],
- xx.vue 页面中使用
async asyncData(context) {
context.app.$myCombineInjectFunction('context中混合注入') // 注意,此处与context的区别是function前面增加了$符号
}
mounted() {
this.$myCombineInjectFunction('mounted中混合注入') // store中用法与此处相同
}
3. 模块
模块是Nuxt.js的扩展,可以扩展其核心功能并添加无限的集成。Nuxt 可以使用配置选项和插件进行扩展,但是在多个项目中维护这些自定义是繁琐、重复和耗时的。 我们可以使用功能强大的 Hookable Nuxt.js 系统来完成特定事件的任务。Nuxt 模块可以合并到 npm 包中
3.1 基本模块
模块只是简单的功能,可以打包为npm模块或直接包含在项目源代码中
- 定义modules/my-nuxt-module/index.js
export default function (moduleOptions = {}) {
// 你可以在这里添加插件、中间件、服务器端中间件等
// 例如,添加一个简单的插件
this.nuxt.hook('build:before', () => {
console.log('Nuxt build is starting...'); // 在build时打印在terminal上
});
// 添加单个插件
// this.addPlugin({
// src: '~/plugins/combine-inject.js', // 注意这里的路径是相对于 Nuxt 项目的根目录
// ssr: false, // 如果插件只在客户端运行,设置为 false
// });
// 添加多个插件
this.nuxt.options.plugins.push(
{ src: '~/plugins/combine-inject.js', ssr: true },
{ src: '~/plugins/ctx-inject.js', ssr: false },
)
}
// 你可以在这里导出模块元数据(可选) 若想要发布到npm上面,这一步骤是必须的
module.exports.meta = require('../../package.json');
- 在nuxt.config.js中应用该modules
export default {
modules: [
// 引入自定义模块
'~/modules/my-nuxt-module'
],
}
- this代表module中的context
- this.options可以直接访问nuxt选项,这是nuxt.config.js,其中包含所有默认选项,可用于模块之间的共享选项。
- this.nuxt, 对当前nuxt实例的引用
- module.export.meta 模块发布npm必须选项
3.2 异步模块
并不是所有模块都能同步完成全部操作,比如我们会需要获取某些API或执行异步IO操作的模块,Nuxt支持在异步模块中返回Promise或调用回调
- async/await方式
modules/async-module.js
import fse from 'fs-extra'
export default async function() {
const pages = await fse.readJson('../../package.json')
console.log(pages, '读取到的内容有哪些') // 打印读取了package.json中的内容
}
nuxt.config.js
export default {
modules: [
'~/modules/async-module'
]
}
- promise方式
import axios from 'axios'
export default function asyncModule() {
return axios
.get('https://jsonplaceholder.typicode.com/users')
.then(res => res.data.map(user => '/users/' + user.username))
.then(routes => {
// Do something by extending Nuxt routes
})
}
4. 插件与模块的异同
模块与插件是两种用于扩展nuxt应用功能的方式
4.1 共同点
- 扩展性: 无论模块还是插件,都是为了增加nuxt应用的功能而设计的,使得开发者能够根据自己的需求进行扩展
- 可重用性:两者都支持被封装成独立的单元,以便于在多个项目中重复使用
4.2 不同点
-
定义与用途
- 模块:模块是nuxt的扩展,可以扩展nuxt的核心功能并添加新的集成。模块通常包含一系列预定义的配置和钩子,用于在nuxt应用的生命周期中注入额外的功能和逻辑。它可以在nuxt.config.js中被引入和配置
- 插件通常用于向Vue组件中注入全局属性和方法,或者添加Vue实例的混入等,插件需要在nuxt的插件系统中注册,以便在应用启动时加载
-
加载时机
- 模块: 模块在nuxt应用启动时加载,并按照在nuxt.config.js中声明的顺序执行,它们可以在nuxt的生命周期中的不同阶段注入代码,从而影响应用的构建、渲染等过程
- 插件:插件通常在Vue应用实例创建之前被加载,并可以访问到Vue上下文(如Vue实例,Vuex store等)。这使得插件能够在Vue组件初始化之前,向Vue实例中添加全局方法、混入等
-
作用域
- 模块: 模块的作用域相对较广,可以影响nuxt应用的各个方面,如路由、Vuex、组件等,模块通常通过Nuxt的生命周期钩子来实现其功能。
- 插件:插件的作用域更关注与Vue组件和Vue实例,它们主要用于向Vue组件中注入全局的功能和属性,以便在组件内部使用
-
使用方式:
- 模块:在nuxt.config.js文件中,通过modules数组引入模块,并且可以传递配置选项给模块
- 插件:在Nuxt的插件目录中创建插件文件,然后在nuxt.config.js中plugins数组中注册插件。插件可以是一个JavaScript文件,也可以是一个对象,用于定义插件的源文件、模式(如客户端或服务器端)等选项。
注意事项
- 默认情况下 Nuxt 使用 vue-loader、file-loader 以及 url-loader 这几个 Webpack 加载器来处理文件的加载和引用。对于不需要通过 Webpack 处理的静态资源文件,可以放置在 static 目录中。需要处理的可以放到 assets 目录。
- 在任何 Vue 组件的生命周期内, 只有 beforeCreate 和 created 这两个方法会在 客户端和服务端被调用。其他生命周期函数仅在客户端被调用。
- 注意nuxt 与 nuxt start并不是相同的指令,在使用时不同的指令有不同的先决条件,不要用错
如果有用,点个赞呗~
总结用法,希望可以帮助到你,
我是Ably,你无须超越谁,只要超越昨天的自己就好~