一、引入并创建nuxt项目
确认已经安装 npx ( npx
依附于 npm 5.2.0
安装引入)
npx create-nuxt-app
或者在 npm
v6.1版本后 可以这样创建:
npm init nuxt-app@latest
或者用: yarn:
yarn create nuxt-app
二、引入axios库
1、使用nuxt自带模块
npm i @nuxtjs/axios -s
1) 、在 nuxt.config.js
中引入
export default {
/*
** Runtime Config
*/
publicRuntimeConfig: {
axios: {
baseURL: 'https://api.nuxtjs.dev'
}
},
/*
** Modules - https://nuxtjs.org/docs/2.x/directory-structure/modules
*/
modules: ['@nuxtjs/axios']
}
2) 、页面内使用 $axios
获取数据,并用 $config
获取 API 接口的 URL
async asyncData({$axios}) {
let { res } = await $axios.get(`https://xxx.com/api/xxx`)
console.log(res)
}
3) 、设置公共拦截
在 ~/plugins
创建 axios.js
文件
export default function ({store, redirect, req, router, $axios }) {
// baseUrl可以在上面的配置中,也可在这儿配置
$axios.defaults.baseURL = 'http://XXX/api';
if(process.server){
// 获取服务端的token,对应函数请自行封装
var token = getcookiesInServer(req).token;
}
if(process.client){
// 获取客户端token,对应函数请自行封装
var token = getcookiesInClient('token');
}
// request拦截器
$axios.onRequest(config => {
if(process.client){
// 客户端下,请求进度条开始
NProgress.start();
}
// 将获取到token加入到请求头中
config.headers.common['Authorization'] = token;
});
// response拦截器,数据返回后,可以先在这里进行一个简单的判断
$axios.interceptors.response.use(
response => {
if(process.client){
// 客户端下, 请求进度条结束
NProgress.done();
}
// return response
if(response.data.code == 401){
// 返回401,token验证失败
removeToken("token");
// 重定向到登录页面, 这里做一个判断,容错:req.url 未定义
if(req.url){
redirect("/sign?ref="+req.url)
}else{
redirect("/sign")
}
}else if(response.data.code == 404){
// 重定向到404页面
redirect("/")
}
else{
// 请求接口数据正常,返回数据
return response
}
},
error => {
if(process.client){
NProgress.done();
}
if(error.response.status == 500){
// http状态500,服务器内部错误,重定向到500页面
redirect("/500.htm")
}
if(error.response.status == 404){
// http状态500,请求API找不到,重定向到404页面
redirect("/404.html")
}
return Promise.reject(error.response) // 返回接口返回的错误信息
})
}
2、外部引入axios
npm i axios -s
1) 、创建request文件夹
在文件夹内创建 http.js
文件, urls
文件夹, apis
文件夹
http.js
import axios from 'axios'
import Vue from 'vue'
const ajax = axios.create({
baseURL: process.env.baseUrl,
timeout: 30 * 1000
})
// 请求拦截器
ajax.interceptors.request.use(
config => {
// const Token = getToken()
// if (Token) {
// config.headers['token'] = getToken()
// }
config.headers['Content-Type'] = 'application/json;chartset=utf-8'
// config.headers["Authorization"] = "Bearer atwerjjhqkwehtjhsdfqwehjhwrgqre";
return config
},
error => {
throw new Error(`请求错误: ${error}`)
}
)
// 响应拦截器
ajax.interceptors.response.use(
response => {
if (response.status === 200) {
// 处理返回流文件报错
if (response.config.responseType === 'blob') {
var reader = new FileReader()
reader.readAsText(response.data)
reader.onload = e => {
const result = JSON.parse(e.target.result)
if (result.code !== 200) {
Vue.prototype.$message.error(result.msg)
}
}
}
if (response.data.code === 200) {
return response.data.data
} else {
Vue.prototype.$message.error(response.data.message)
return Promise.reject(response.data)
}
} else {
return response
}
},
error => {
throw new Error(error)
// throw new Error(`请求错误: ${error}`)
}
)
/*
* @params {config} 参数从API传递过来
* @params @{config} {url} 请求地址
* @params @{config} {data} 请求数据
*/
export function get(config) {
let obj = {
url: config.url,
method: 'get',
params: {
...config.data,
}
}
return ajax(obj)
}
export function post(config) {
let obj = {
url: config.url,
method: 'post',
data: {
...config.data,
}
}
return ajax(obj)
}
export function upload(config) {
let obj = {
url: config.url,
method: 'post',
data: config.data,
headers: {
'Content-Type': 'multipart/form-data'
}
}
return ajax(obj)
}
urls文件夹下创建对应模块的url信息
例如 urls/user.js
export default {
userinfo: '/user/userinfo',
userList: '/user/userList'
}
apis文件夹下创建对应模块的api函数
例如 apis/user.js
import { get, post } from '../http.js'
import user from '../urls/user'
export function getUserinfo(params) {
return get({ url: userUrls.userinfo, params })
}
export function getUserList(params) {
return post({ url: userUrls.userList, params })
}
页面内正常使用我们熟知的方式引入api函数去调接口获取数据
3、axios跨域配置
1) 、使用官方axios模块时的配置
export default {
axios: {
proxy: true,
prefix: '/api', // baseURL
credentials: true,
retry: { retries: 3 }
},
proxy: {
'/api': {
target: 'http://192.168.xxx.xxx:xxxx', // 代理地址
changeOrigin: true,
pathRewrite: {
'^/api': '', //将 /api 替换掉
}
},
}
}
2) 、使用官方axios模块,引入官方模块 @nuxtjs/proxy
配置
npm i @nuxtjs/proxy -D
在 nuxt.config.js
中配置
modules: [
'@nuxtjs/axios',
'@nuxtjs/proxy'
],
proxy: [
[
'/api',
{
target: 'http://localhost:3001', // api主机
pathRewrite: { '^/api' : '/' }
}
]
]
3) 、使用外部引入的方式
配合后端部署设置nginx
三、登录状态持久化
npm i -S cookie-universal-nuxt
在 nuxt.config.js
中配置
modules: [
// 登录状态持久化
['cookie-universal-nuxt', { parseJSON: true }]
],
store配置请参考本文下面的i18n部分, store/index.js
四、引入ant-design-vue组件库
npm i -S ant-design-vue
npm install babel-plugin-import --save-dev
1、按需引入配置
// nuxt.config.js
{
build: {
babel: {
plugins: [
[
'import',
{
libraryName: 'ant-design-vue',
libraryDirectory: 'es',
style: true
// 默认不使用该选项,即不导入样式 , 注意 ant-design-vue 使用 js 文件引入样式
// true 表示 import 'ant-design-vue/es/component/style'
// 'css' 表示 import 'ant-design-vue/es/component/style/css'
}
]
]
}
}
}
在 ~/plugins
文件夹创建 antd-ui.js
文件
import Vue from 'vue'
Vue.config.productionTip = false
import { Button } from 'ant-dsign-vue'
Vue.use(Button)
2、antd-icon
过大
不是所有的图标我们都能用到
在 ~/plugins
文件夹创建 antd-icons.js
文件
export {
// 需要使用到的 Icons
InfoCircleFill,
DownOutline,
UpOutline,
RightOutline,
LeftOutline
} from '@ant-design/icons'
// nuxt.config.js
const CompressionPlugin = require('compression-webpack-plugin')
const path = require('path')
export default {
build: {
vendor: ['axios', 'ant-design-vue'],
// 解决less加载使用不了的问题
loaders: {
less: {
javascriptEnabled: true
}
},
analyze: {
analyzerMode: 'static'
},
// 使用Babel与特定的依赖关系进行转换
transpile: [/ant-design-vue/],
extend(config, ctx) {
// 配置eslint
if (ctx.isClient) {
config.module.rules.push({
enforce: 'pre',
test: /\.(js|vue)$/,
loader: 'eslint-loader',
exclude: /(node_modules)/
})
// ant-design-vue 的icon组件,按需引入需要的图标,文件太大
config.resolve.alias['@ant-design/icons/lib/dist$'] = path.resolve(__dirname, './plugins/antd-icons.js') // 引入需要的
}
},
// 打包构建优化
plugins: [
new CompressionPlugin({
test: /\.js$|\.html$|\.css/, // 匹配文件名
threshold: 10240, // 对超过10kb的数据进行压缩
deleteOriginalAssets: false // 是否删除原文件
})
],
optimization: {
splitChunks: {
minSize: 10000,
maxSize: 250000
}
}
}
}
注意: 这儿安装 compression-webpack-plugin
插件会报错,指定插件版本就行了
npm i --save-dev [email protected]
提醒:图标使用
如果有组件内使用的,例如
五、国际化
1、引入i18n
npm i vue-i18n --save
2、在 plugins
下创建 i18n.js
// nuxt.config.js
export default {
plugins: [
'@/plugins/antd-ui',
{ src: '@/plugins/lazy-load', ssr: false },
'@/plugins/i18n.js',
{ src: '~/plugins/lodash.js', ssr: false },
{ src: '~/plugins/moment.js', ssr: false },
{ src: '@/plugins/vue-swiper.js', mode: 'client' },
],
}
import Vue from 'vue'
import VueI18n from 'vue-i18n'
Vue.use(VueI18n)
export default ({ app, store }) => {
// Set i18n instance on app
// This way we can use it in middleware and pages asyncData/fetch
app.i18n = new VueI18n({
locale: store.state.locale,
fallbackLocale: store.state.locale,
messages: {
'en-US': require('@/language/en-US.json'),
'zh-CN': require('@/language/zh-CN.json')
},
silentTranslationWarn: true
})
app.i18n.path = link => {
// 如果是默认语言,就省略
if (app.i18n.locale === app.i18n.fallbackLocale) {
return `/${link}`
}
return `/${app.i18n.locale}/${link}`
}
}
3、在 middleware
下创建 i18n.js
// nuxt.config.js
export default {
router: {
middleware: ['i18n']
},
}
export default function({ isHMR, app, store, route, params, error, redirect }) {
const defaultLocale = app.i18n.fallbackLocale
// If middleware is called from hot module replacement, ignore it
if (isHMR) return
// Get locale from params
const locale = params.lang || defaultLocale
if (store.state.locales.indexOf(locale) === -1) {
return error({ message: '页面未找到.', statusCode: 404 })
}
// Set locale
// store.commit('SET_LANG', locale)
app.i18n.locale = store.state.locale
// If route is //... -> redirect to /...
if (locale === defaultLocale && route.fullPath.indexOf('/' + defaultLocale) === 0) {
const toReplace = '^/' + defaultLocale + (route.fullPath.indexOf('/' + defaultLocale + '/') === 0 ? '/' : '')
const re = new RegExp(toReplace)
return redirect(route.fullPath.replace(re, '/'))
}
}
4、在 store
下创建 index.js
import { getToken } from '@/lib/token.js'
const state = () => ({
token: '',
locales: ['en-US', 'zh-CN'],
locale: 'en-US'
})
const mutations = {
setToken(state, token) {
state.token = token
},
SET_LANG(state, locale) {
if (state.locales.indexOf(locale) !== -1) {
state.locale = locale
}
}
}
const actions = {
async nuxtServerInit({ commit }, { app }) {
let token = getToken(app) || ''
commit('setToken', token)
//还可以获取一些通用信息,比如个人信息,通用配置什么的
}
}
export default {
state,
actions,
mutations
}
5、在 language
下创建 en-US.json
、 zh-CN.json
更多语言库,请按照规则添加
配置对应的变量属性名称,在页面用
{{ $t('变量名') }}
对应antd-vue组件库国际化,官方推荐使用 config-provider
组件
// default.vue页面
header
footer
在 language
下创建 antd-lang/index.js
, 包含所有的支持语言库
// 阿拉伯
import arEG from '~/node_modules/ant-design-vue/es/locale/ar_EG'
// 保加利亚语
import bgBG from '~/node_modules/ant-design-vue/es/locale/bg_BG'
// 加泰罗尼亚语
import caES from '~/node_modules/ant-design-vue/es/locale/ca_ES'
// 捷克语
import csCZ from '~/node_modules/ant-design-vue/es/locale/cs_CZ'
// 德语
import deDE from '~/node_modules/ant-design-vue/es/locale/de_DE'
// 希腊语
import elGR from '~/node_modules/ant-design-vue/es/locale/el_GR'
// 英语
import enGB from '~/node_modules/ant-design-vue/es/locale/en_GB'
// 英语(美式)
import enUS from '~/node_modules/ant-design-vue/es/locale/en_US'
// 西班牙语
import esES from '~/node_modules/ant-design-vue/es/locale/es_ES'
// 爱沙尼亚语
import etEE from '~/node_modules/ant-design-vue/es/locale/et_EE'
// 波斯语
import faIR from '~/node_modules/ant-design-vue/es/locale/fa_IR'
// 芬兰语
import fiFI from '~/node_modules/ant-design-vue/es/locale/fi_FI'
// 法语(比利时)
import frBE from '~/node_modules/ant-design-vue/es/locale/fr_BE'
// 法语
import frFR from '~/node_modules/ant-design-vue/es/locale/fr_FR'
// 冰岛语
import isIS from '~/node_modules/ant-design-vue/es/locale/is_IS'
// 意大利语
import itIT from '~/node_modules/ant-design-vue/es/locale/it_IT'
// 日语
import jaJP from '~/node_modules/ant-design-vue/es/locale/ja_JP'
// 韩语/朝鲜语
import koKR from '~/node_modules/ant-design-vue/es/locale/ko_KR'
// 挪威
import nbNO from '~/node_modules/ant-design-vue/es/locale/nb_NO'
// 荷兰语(比利时)
import nlBE from '~/node_modules/ant-design-vue/es/locale/nl_BE'
// 荷兰语
import nlNL from '~/node_modules/ant-design-vue/es/locale/nl_NL'
// 波兰语
import plPL from '~/node_modules/ant-design-vue/es/locale/pl_PL'
// 葡萄牙语(巴西)
import ptBR from '~/node_modules/ant-design-vue/es/locale/pt_BR'
// 葡萄牙语
import ptPT from '~/node_modules/ant-design-vue/es/locale/pt_PT'
// 斯洛伐克语
import skSK from '~/node_modules/ant-design-vue/es/locale/sk_SK'
// 塞尔维亚
import srRS from '~/node_modules/ant-design-vue/es/locale/sr_RS'
// 斯洛文尼亚
import slSI from '~/node_modules/ant-design-vue/es/locale/sl_SI'
// 瑞典语
import svSE from '~/node_modules/ant-design-vue/es/locale/sv_SE'
// 泰语
import thTH from '~/node_modules/ant-design-vue/es/locale/th_TH'
// 土耳其语
import trTR from '~/node_modules/ant-design-vue/es/locale/tr_TR'
// 俄罗斯语
import ruRU from '~/node_modules/ant-design-vue/es/locale/ru_RU'
// 乌克兰语
import ukUA from '~/node_modules/ant-design-vue/es/locale/uk_UA'
// 越南语
import viVN from '~/node_modules/ant-design-vue/es/locale/vi_VN'
// 简体中文
import zhCN from '~/node_modules/ant-design-vue/es/locale/zh_CN'
// 繁体中文
import zhTW from '~/node_modules/ant-design-vue/es/locale/zh_TW'
export default {
arEG,
bgBG,
caES,
csCZ,
deDE,
elGR,
enGB,
enUS,
esES,
etEE,
faIR,
fiFI,
frBE,
frFR,
isIS,
itIT,
jaJP,
koKR,
nbNO,
nlBE,
nlNL,
plPL,
ptBR,
ptPT,
skSK,
srRS,
slSI,
svSE,
thTH,
trTR,
ruRU,
ukUA,
viVN,
zhCN,
zhTW
}
六、scss、less样式全局引用
SASS: `yarn add sass-loader node-sass`
LESS: `yarn add less-loader less`
Stylus: `yarn add stylus-loader stylus`
yarn add @nuxtjs/style-resources
npm i @nuxtjs/style-resources --save-dev
配置请参考:@nuxtjs/style-resources
// nuxt.config.js
export default {
// 下面这两个配置用一个就行了
modules: ['@nuxtjs/style-resources'],
buildModules: ['@nuxtjs/style-resources'],
// 配置我们需要用到的less、scss全局变量,然后在.vue文件内直接引入
styleResources: {
// your settings here
sass: [],
scss: ['./assets/vars/*.scss', './assets/abstracts/_mixins.scss'],
less: ['./assets/vars/*.less'],
stylus: []
},
}