最近小编新接手了两个项目,这两个项目均是使用nuxt.js框架进行开发的,这对小编来说又是一个新的大陆,故而和各位小伙伴们絮叨絮叨这个东西。
首先先说明一下这个东西是个啥。
Nuxt.js 是一个基于 Vue.js 的通用应用框架,如同Next.js之于React一样(Next.js 是一个轻量级的 React 服务端渲染应用框架)
通过对客户端/服务端基础架构的抽象组织,Nuxt.js 主要关注的是应用的 UI渲染。
Nuxt.js 预设了利用Vue.js开发服务端渲染的应用所需要的各种配置。
小编的个人看法是,nuxt.js相对于vue而言确实便捷一些。
创建:npx create-nuxt-app 项目名 (npx在安装npm的时候已经安装,因此不用担心,直接使用就好)
各项配置的选择:
这些配置如果没有有特殊需要的话,直接按回车键就好,如果前两项需要填写也可以进行填写,第三项是使用nuxt默认的服务器端框架。
创建成功之后,是需要进入的文件夹中还是可以直接进行运行均会有提示,按照提示操作即可,之后打开提供的链接进行访问即可。
1、路由
①一般路由
在vue中,路由的跳转使用的是vue-router,路由的跳转需要开发人员自己进行编写配置,nuxt.js不需要自行编写,它会根据开发者page文件夹下的结构自动生成路由配置。
假设 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'
}
]
}
②子路由
在 Nuxt.js 里面定义带参数的动态路由,需要创建对应的以下划线作为前缀的 Vue 文件 或 目录。如果想生成的路由为二级(/index/1)、三级(/index/1/2)或是更多级,以及需要url后添加id等皆可使用子路由实现。
目录结构:
pages/
-----| comments.vue
-----| users.vue
-----| users/
--| _id.vue
Nuxt.js 生成对应的路由配置表为
router: {
routes: [
{
name: 'index',
path: '/',
component: 'pages/index.vue'
},
{
name: 'users',
path: '/users/:id?',//url为/users/id
component: 'pages/users/_id.vue'
}
}
注:_id.vue中可以什么都不写
nuxt.js中还有其他的路由,在此我就不一一介绍了,毕竟除了以上的两种,其他的路由小编在此次项目中并没有使用到,了解的不是很多,故而就不在这里多说了,有兴趣或是需要的小伙伴可以自行到官网中了解。
2、asyncData
①在组件(限于页面组件)每次加载之前被调用。返回的数据融合组件 data 方法返回的数据一并返回给当前组件。
②例子1.get请求:let [request1Data] = await Promise.all([ axios.get(url1), axios.get(url2), ])
例子2:post请求,如果post请求的参数传递和get请求一样是直接使用?连接在url后边的话便可使用
let [request1Data] = await Promise.all([ axios.postForm(url1), axios.postForm(url2), ])
注:请求的函数,例如get和postForm可以自行封装在一个js中,小编封装的js函数是http.js,并把它放在plugins文件夹下。
http.js
import axios from ‘axios’;
import qs from ‘qs’;
import config from ‘…/conf/config.service’;
// 超时时间
// axios.defaults.timeout = 5000
axios.defaults.headers.post[‘Content-Type’] = ‘application/x-www-form-urlencoded;’;
// response.addHeader( “Cache-Control”, “no-cache” );
axios.defaults.headers[‘Cache-Control’] = “no-cache”;
axios.defaults.withCredentials = true;
axios.defaults.baseUrl = config.proxyUrl;
axios.postByQs = function (url, data) {
return axios.post(url, qs.stringify(data), {
headers: {
‘Content-Type’: ‘application/x-www-form-urlencoded’,
‘Cache-Control’: ‘no-cache’,
}
})
}
axios.GET = function (url) {
return axios.get(url, {
headers: {
‘Cache-Control’: ‘no-cache’,
}
})
}
axios.postForm = function (url, data) {
return axios.post(url, data, {
headers: {
‘Content-Type’: false,
‘Cache-Control’: ‘no-cache’,
}
})
}
axios.postFile = function (url, data) {
return axios.post(url, data, {
headers: {
‘Content-Type’: ‘multipart/form-data’,
‘Cache-Control’: ‘no-cache’
}
})
}
axios.interceptors.response.use(
response => {
if (response.data.status == 401) {
window.location.hash = ‘login’;
window.location.reload()
}
return response;
},
error => {
return Promise.reject(error.response.data) // 返回接口返回的错误信息
});
export default axios
③使用asyncData获取数据可以更好的进行SEO优化。但若该页面的数据是随时改变的,小编不建议该页面使用此方法,因为数据随时的改动,今日收录的数据对于明日来说并没有多大的用处。所以小编推荐,当确认该页面显示的数据并不是时时更新再使用此方法。使用此方法获取数据时,只有数据获取成功并完成后客户端才会显示并进行渲染,否则,页面将一直处于加载状态。
3、关于plugins文件夹
plugins文件夹为插件目录,顾名思义,是用于组织那些需要在 根vue.js应用 实例化之前需要运行的 Javascript 插件。这么说也比较模糊,在此和大家举个例子吧。比如,在此次项目中,小编要用到swiper插件,于是到npm中找到了vue-awesome-swiper插件。通过npm安装依赖成功之后,并不能够直接使用,需要进行以下几个步骤:
①在plugins文件夹中新建js文件,例如取名为swiper.js。此js文件是说明该项目使用vue-awesome-swiper/dist/ssr插件。
swiper.js:
import Vue from 'vue'
export default () => {
if (process.browser) {
//console.log('浏览器端渲染');
Vue.use(require('vue-awesome-swiper/dist/ssr'), /* { default global options } */)
}else{
//console.log("非浏览器端渲染");
}
}
②到nuxt.config.js文件中添加
....
plugins: [
{src:'@/plugins/swiper.js',ssr:false}
]
....
③通过以上两步,该插件才叫做可以使用了。在components文件夹中新建文件,例如:slider.vue。
slider.vue:
<template>
<div class="swiper_container swiper-no-swiping">
<div class="swiper_wrapper_content">
<no-ssr>
<div v-swiper:mySwiper="swiperOption" @someSwiperEvent="swiperEvent" class="swiper_wrapper_content_con">
<div class="swiper-wrapper">
<div class="swiper-slide img1"><span></span></div>
</div>
<!-- <div class="swiper-pagination"></div>-->
</div>
</no-ssr>
</div>
</div>
</template>
<script>
export default {
name: '',
layout: 'welcomeIndex',
data() {
return {
swiperOption: {
pagination: {
el: '.swiper-pagination',
clickable: false
},
autoplay: {
delay: 5000,
},
effect: 'slide',
paginationClickable: true,
speed: 800,
loop:true,
observer: true,
observeParents: true,
autoplayDisableOnInteraction: false
}
}
},
computed: {},
created() {
},
mounted() {
},
methods: {
}
}
</script>
<style lang="scss" scoped>
.swiper_container{
width: 100%;
height: 100%;
.swiper_wrapper_content{
width: 100%;
height: 100%;
.swiper_wrapper_content_con{
width: 100%;
height: 100%;
.swiper-wrapper{
width: 100%;
height: 100%;
.swiper-slide {
width: 100%;
height: 100%;
span {
width: 100%;
height: 100%;
display: inline-block;
background-color: #00dad7;
background: url("../static/images/banner/banner1.jpg") no-repeat top center;
}
}
img{
width: 100%;
height: 100%;
}
}
}
}
}
</style>
在此,小编将轮播图作为背景图是为了适配,防止图片由于屏幕大小、分辨率问题导致图片变形。
④在页面中使用该组件
<template>
<div class="container">
<div class="banner">
<Slider></Slider>
</div>
</div>
</template>
<script>
import Slider from "~/components/slider.vue"
export default {
name:"index",
data() {
return{
}
},
components: {
Slider,
},
}
</script>
注:引入bootstrap、jq等插件时,小编不推荐直接在页面中的head里直接引用,即最好不要使用以下方式引用
<script>
export default {
data(){
return{
}
},
head(){
return {
title: '',
meta: [
{ hid: 'description', name: 'description', content: '' },
{ hid: 'keywords', name: 'keywords', content: '' }
],
srcipt:[
{src:'xxxxx.js'}
]
}
},
}
</script>
温馨提示:
1、若想使用asyncData进行异步获取数据,页面的跳转建议不使用nuxt-router,若使用nuxt-router进行路由跳转,当用户点击浏览器返回箭头时会报错,需要进行手动刷新。当页面停留时间过长,进行刷新时也会报错,这时建议在使用asyncData前先判断是否是服务端渲染,若是服务端则再进行数据的请求,这样就不会出现以上问题。
2、使用asyncData异步获取数据时,除了return所需的数据字段,不要在其他的地方使用return,否则会导致数据无法正常返回而造成数据渲染显示异常。
3、若项目中使用element-ui的NavMenu组件,循环渲染el-dropdown-item标签时,不要使用v-text进行数据渲染,页面会报虚拟DOM的警告,虽然只是警告,但作为一名合格的程序员,控制台报红都是分分钟刺眼的事。
官方文档:https://zh.nuxtjs.org/