本篇文章主要记录项目开发过程及nuxt的基本使用
新建项目
首先在github上新建一个repository,下载到本地,用编辑器打开
利用nuxt提供的脚手初始化项目
vue init nuxt/starter
安装依赖
npm install
执行
npm run dev
目录结构
nuxt初始化的项目结构为

一、nuxt.config.js
用于组织Nuxt.js 应用的个性化配置,以便覆盖默认配置
比如配置header,全局css,plugin等,具体使用看下文
二、layouts
nuxt新增了layouts概念,初始化layouts/index.vue,<nuxt /> 组件用于显示页面的主体内容,本项目只用了index.vue,后期可以考虑优化
<template>
<div>
<nuxt />
</div>
</template>
nuxt允许在 layout 目录下创建自定义的布局,从而实现页面的多个布局切换,将页面分为三层layouts => page => component,可以减少代码冗余
1、在layouts下新建[name].vue布局,其中default.vue 文件来扩展应用的默认布局,error.vue 文件来定制化错误页面,错误页面仅是page,不需要包含 <nuxt/> 标签
2、在page通过layout属性访问自定义的布局,如果不写,则默认是默认布局
export default {
layout: 'name'
}
三、plugins
用于组织那些需要在根vue.js应用实例化之前需要运行的 Javascript 插件。
比如本项目使用到的
1. echarts
安装echarts
npm install echarts -S
在plugin目录下新建echarts.js
import Vue from 'vue'
import echarts from 'echarts' // 引入echarts
Vue.prototype.$echarts = echarts
在nuxt.config.js 配置
plugins: ['~plugins/echarts']
2. vue-awesome-swiper
安装vue-awesome-swiper
npm install vue-awesome-swiper -S
在plugins目录下新建vueSwiper.js
import Vue from 'vue'
import VueAwesomeSwiper from 'vue-awesome-swiper/dist/ssr'
Vue.use(VueAwesomeSwiper)
在nuxt.config.js配置全局css等
css: [
"swiper/dist/css/swiper.css"
],
plugins: [{
src: '~plugins/vueSwiper',
ssr: false
}
],
四、store
用于组织应用的 Vuex 状态树 文件
如本项目的nav需要用到store 在store新建nav.js
export const state = () => ({
activeUrl: '/'
});
const getters = {
getActiveUrl: state => state.activeUrl
};
const mutations = {
setActiveUrl(state, num) {
state.activeUrl = num;
}
};
/*const actions = {
async SET_isLogin({state, commit}, val) {
commit('SET_isLogin', val);
}
};*/
export default {
namespaced: true,
state,
getters,
// actions,
mutations
};
配置路由
Nuxt.js 依据 pages 目录结构自动生成 vue-router 模块的路由配置
一、基础路由
无需手动配置,可在.nuxt/router.js下看到具体的路由
如本项目的pages目录结构

Nuxt.js自动生成的路由配置如下:

二、<nuxt-link>
在页面使用路由用<nuxt-link>标签
<ul class="nav-list">
<li
v-for="(item, index) in list"
v-bind:key="index"
class="nav-item"
@click="navigater(item.url)"
>
<nuxt-link :to="item.url" :class="[item.url == activeUrl ? 'active' : '']">
{{
item.title
}}
</nuxt-link>
</li>
</ul>
三、动态路由
在 Nuxt.js 里面定义带参数的动态路由,只需创建对应的以下划线作为前缀的 Vue 文件或目录即可
比如,在pages目录下新建user文件夹,user下新建_id.vue,则nuxt会生成
{
name: 'users-id',
path: '/users/:id?',
component: 'pages/users/_id.vue'
},
此外,nuxt还支持在动态路由组件中定义参数校验方法
比如在 pages/users/_id.vue
export default {
validate ({ params }) {
// 必须是number类型
return /^\d+$/.test(params.id)
}
}
如果校验方法返回的值不为 true或Promise中resolve 解析为false或抛出Error , Nuxt.js 将自动加载显示 404 错误页面或 500 错误页面
api实现
服务端
nuxt的server端使用的是express,数据库使用的是mysql,server端目录组织如图:

-
db.js是连接数据库的配置
-
sql.js是sql语句
-
index.js是express的启动文件
const express = require('express')
const consola = require('consola')
const { Nuxt, Builder } = require('nuxt')
const app = express()
const router = require('./router');
const path = require('path');
// Import and Set Nuxt.js options
const config = require('../nuxt.config.js')
config.dev = process.env.NODE_ENV !== 'production'
async function start() {
// Init Nuxt.js
const nuxt = new Nuxt(config)
const { host, port } = nuxt.options.server
// Build only in dev mode
if (config.dev) {
const builder = new Builder(nuxt)
await builder.build()
} else {
await nuxt.ready()
}
app.use(router)
app.use(nuxt.render)
// Listen the server
app.listen(port, host)
consola.ready({
message: `Server listening on http://${host}:${port}`,
badge: true
})
}
start()
api.js
const mysql = require('mysql');
const db = require('./db');
const sql = require('./sql');
/**
* 查询导航栏数据
*/
exports.queryNav = () => {
return new Promise((resolve, reject) => {
const con = mysql.createConnection(db);
con.connect();
con.query(sql.queryNav, (err, result) => {
if (err) {
reject('err:queryNav');
}
resolve(result);
});
con.end();
})
}
router.js
const express = require('express');
const router = express.Router();
const api = require('./api');
router.get('/api/nav', async (req, res, next) => {
let data = await api.queryNav();
res.send(data);
res.end();
})
前端
在根目录下新建data文件夹

import axios from 'axios';
import qs from 'qs';
axios.defaults.timeout = 5000; //响应时间
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'; //配置请求头
// axios.defaults.baseURL = 'http://localhost:3000'; //配置接口地址
let baseUrl="http://localhost:3000/api";
// let baseUrl="https://www.xxx";
//POST传参序列化(添加请求拦截器)
axios.interceptors.request.use((config) => {
//在发送请求之前做某件事
if(config.method === 'post'){
config.data = qs.stringify(config.data);
}
return config;
},(error) =>{
// console.log('错误的传参');
return Promise.reject(error);
});
//返回状态判断(添加响应拦截器)
axios.interceptors.response.use((res) =>{
//对响应数据做些事
if(!res.data.success){
return Promise.resolve(res);
}
return res;
}, (error) => {
return Promise.reject(error);
});
//返回一个Promise(发送post请求)
export function fetchPost(url, params) {
return new Promise((resolve, reject) => {
axios.post(baseUrl+url, params)
.then(response => {
resolve(response.data);
}, err => {
reject(err);
})
.catch((error) => {
reject(error)
})
})
}
//返回一个Promise(发送get请求)
export function fetchGet(url) {
return new Promise((resolve, reject) => {
axios.get(baseUrl+url)
.then(response => {
resolve(response.data)
}, err => {
reject(err)
})
.catch((error) => {
reject(error)
})
})
}
export default {
fetchPost,
fetchGet,
}
api.js 用来统一管理接口
import { fetchGet, fetchPost } from "./httpUtil";
/**
* 获取Nav内容
*/
export const getQueryNav = () => {
return fetchGet("/nav");
};
export default {
getQueryNav
}
视图层使用
import Api from "~/data/api.js";
export default {
async asyncData() {
const studentList = await Api.getStudentList();
return {
studentList
};
}
};
asyncData异步数据
Nuxt.js 扩展了 Vue.js,增加了一个叫 asyncData 的方法,使得我们可以在设置组件的数据之前能异步获取或处理数据。
asyncData方法会在组件(限于页面组件)每次加载之前被调用。它可以在服务端或路由更新之前被调用,该方法第一个参数被设定为当前页面的上下文对象,可以利用 asyncData方法来获取数据,Nuxt.js 会将 asyncData 返回的数据融合组件data 方法返回的数据一并返回给当前组件。
由于asyncData方法是在组件初始化前被调用的,所以在方法内是没有办法通过this 来引用组件的实例对象
比如本项目中有需要获取router中的query
async asyncData({query}) {
const detail = await Api.getStudentDetail(query.id);
return {
detail
};
},
优化
图片懒加载
安装vue-lazyload:
npm install vue-lazyload -S
在plugins目录下新建vue-lazyload.js:

import Vue from 'vue'
import VueLazyload from 'vue-lazyload'
Vue.use(VueLazyload);
在nuxt.config.js配置
plugins: ['~plugins/echarts', {
src: '~plugins/vueSwiper',
ssr: false
}, {
src: '~/plugins/vue-lazyload',
ssr: false
},
],
build: {
extend(config, ctx) {
},
vendor:['vue-lazyload'],
}
在template img 标签将src换为
<img v-lazy="require('../../assets/img/bg.png')" alt />
使用变量
<img v-lazy="imgUrl" alt />