项目流程图
其中以下基础配置是与我们当前开发的后台管理系统进行对标的,方便我们快速上手,方便使用
以上是本地安装所选项,具体安装所选项和安装后目录展示可以异步到这里https://blog.csdn.net/qq_28846389/article/details/116459936
本来打算学习nuxt的,刚好有个后台管理系统入口的静态页面需要实现,就简单的撸了一下,初步主要涉及到资源引入,组件,组件数据传输,整体开发方式跟vue一样,只是组件需要放到components下,页面放到paga下面,然后就是打包部署,目前不需要服务端渲染,只需要打包后丢到nginx即可,即
静态应用部署
npm run generate
会生成一个dist文件,然后所有的静态资源都在这里
实现上述简单页面所遇到的问题
1.assets/static中资源引入
template,style中引入方法相同
~/assets/your-image.png
1.环境配置(请求接口的api、资源路径,本地,测试,正式线)
2.axios的使用
3.axios拦截扩展
4.css,scss的引入配置
5.scss全局样式具体配置
6.px2rem插件配置
npm i cross-env -D
//package.josn
"scripts": {
"dev": "cross-env BASE_URL='后端服务器地址' BASE_API='后端服务器地址' NODE_ENV=development nuxt",
"start": "cross-env BASE_URL='后端服务器地址' BASE_API='后端服务器地址' NODE_ENV=production nuxt start",
"build": "cross-env BASE_URL='后端服务器地址' BASE_API='后端服务器地址' NODE_ENV=production nuxt build",
"test": "cross-env BASE_URL='后端服务器地址' BASE_API='后端服务器地址' NODE_ENV=production nuxt generate",
"generate": "cross-env BASE_URL='后端服务器地址' BASE_API='后端服务器地址' NODE_ENV=production nuxt generate"
},
可以根据自己项目所需环境进行上述指令配置,与公司其他项目对标,一般需要以下3个环境
npm run dev 本地环境开发
npm run build:stage 测试线环境
npm run build:prod 正式线环境
//环境变量
env: {
BASE_URL: process.env.BASE_URL,
NODE_ENV: process.env.NODE_ENV,
BASE_API:process.env.BASE_API //静态资源路径
},
在使用axios进行数据拦截时,可以设置
export const request= axios.create({
baseURL: process.env.BASE_URL
})
或者可以直接在template中直接使用,比如引入图片时
data:{
return {
hrefApi: process.env.BASE_API
}
}
<img :src="hrefApi" alt="">
参考链接:添加链接描述
npm install @nuxtjs/axios
nuxt.config.js
modules: [
'@nuxtjs/axios'
]
在asyncData选项是在组件初始化前被调用的,所有在该选项中是没有办法使用this的,但是可以使用上下文对象
注意:asyncData只能在页面组件中使用,也就是pages目录下的组件,而不是components目录下的组件
```javascript
//其中context是上下文对象
async asyncData(context){
const res = await context.$axios.$post(process.env.BASE_API+'/public/user/login',{"username":"admin","password":"xxx","roleType":1})
//返回出去,可以在模板中直接使用
return {
token:res.data.token
}
}
//在组件的其他选项中可以直接使用
methods: {
async getToken(){
const res = this.$axios.$post(process.env.BASE_API+'public/user/login',{"username":"admin","password":"xxx","roleType":1})
}
}
如果需要通过注册拦截器或者改变全局设置来定制axios,需要创建一个nuxt plugin
nuxt.config.js
modules: [
'@nuxtjs/axios'
],
plugins: [
'~/plugins/axios'
],
plugins/axios.js
// import request from '@/utils/request'
import axios from 'axios'
export const request= axios.create({
baseURL: process.env.BASE_URL
})
export default ({ store }) => {
// 请求拦截器
request.interceptors.request.use(function (config) {
// Do something before request is sent
return config;
}, function (error) {
// Do something with request error
return Promise.reject(error);
});
// 响应拦截器
request.interceptors.response.use(function (response) {
// Any status code that lie within the range of 2xx cause this function to trigger
// Do something with response data
return response;
}, function (error) {
// Any status codes that falls outside the range of 2xx cause this function to trigger
// Do something with response error
return Promise.reject(error);
});
}
import {request} from '@/plugins/axios'
export const login = data => {
return request({
method: 'POST',
url: 'public/user/login',
data
})
}
import {login} from '~/api/request'
async getToken(){
const res = await login({"username":"admin","password":"xxx","roleType":1})
}
参考链接添加链接描述
我们需要引入公共的初始化样式,比如reset
nuxt.config.js
css: [
'~/assets/reset.css'
]
<style lang="scss" scoped>
下面的版本能正常安装
“dependencies”:{
"node-sass": "^4.7.2",
"sass-loader": "7.0.3",
}
代码中测试
$color:red;
.test {
color: $color;
font-size: 20px;
}
nuxt.config.js
css: [
{src:'~/assets/sass/common.scss',lang:'scss'}
],
npm i -D @nuxtjs/style-resources
nuxt.config.js
modules: [
'@nuxtjs/style-resources'
],
styleResources: {
scss: [
//把全局样式放到这里,同时把css节点中引用的scss删除
'~/assets/sass/common.scss'
]
},
组件中lang="scss",就可以直接使用了
plugins/px2rem.js
plugins: [
{ src: '@/plugins/custom/px2rem', ssr: false }
],
$phone: 750;
$remBase: $phone/7.5;
@function toRem($size) {
$remSize: $size / $remBase;
@return $remSize * 1rem;
}
.test {
font-size: toRem(20);
}
import Vue from 'vue'
let ownFun = function(){
let message = function(msg){
msg&&console.log(msg)
}
let otherFun = function(){}
return {
message,
otherFun
}
}
Vue.prototype.$log = ownFun()
plugins: [
'~/plugins/common'
],
<script>
export default {
created() {
this.$log.message('小老弟,你怎么回事')
}
}
</script>
//全局引入
import Vue from 'vue'
import Element from 'element-ui'
import locale from 'element-ui/lib/locale/lang/en'
Vue.use(Element,{locale })
//局部使用
import Vue from 'vue'
import {Button,Input} from 'element-ui'
import locale from 'element-ui/lib/locale/lang/en'
Vue.use(Button,Input,{locale })
css: [
'element-ui/lib/theme-chalk/index.css'
],
plugins: [
'@/plugins/element-ui'
],
<el-button>按钮</el-button>
<el-input/>
首先想到的是使用插件vuex-persistedstate,对state数据进行持久化存储
在一般的vue-cli项目中,我们可以用vuex-persistedstate,它可以使vuex的状态持久化,页面刷新都不会丢失
npm install vuex-persistedstate --save
import createPersistedState from 'vuex-persistedstate'
export default (context) => {
createPersistedState({
reducer(obj) {
// 其中 username authority 为需要自动存储的 state
const { token, token1 } = obj;
return {token, token1 }
}
})(context.store);
}
plugins: [
{ src: '~/plugins/vuex-persistedstate', ssr: false },
],
import createPersistedState from "vuex-persistedstate"
export const plugins = [createPersistedState()];
然后发现会报window is not define,修改以下两点后:
检查nuxt.config.js中是否将ssr置为false
将nuxt.config.js中mode设置为’spa’
百度后发现:
因为vuex-persistedstate原理是存放在localstorage中,由于在created钩子中不存在window对象(获取cookie、localStorage都需要window对象),如果我们想要获取用户态,然后根据用户态,去修改页面中用户状态,我们只能在mounted中进行操作,这样的话,我们在进入页面的一瞬间还是无法得知登录状态,体验上会有影响,会存在显示用户名等组件显示隐藏延迟。
async asyncData(context){
console.log(localStorage,'%c=======asyncData========','color:red;')
}
created(){
console.log(localStorage,'%c=======created========','color:red;')
}
mounted () {
console.log(localStorage,'%c=======mounted========','color:red;')
}
怎么做更好呢?
nuxt非常友好,它提供了fetch钩子,还有nuxtServerInit,这两个钩子都运行在服务端并且我们能很快速地操作store
在asyncData,created,mounted选项中打印
async asyncData(context){
console.log('%c=======asyncData========','color:red;')
},
created () {
console.log('%c=======created========','color:red;')
}
mounted () {
console.log('%c=======mounted========','color:red;')
}
2.nuxtServerInit
状态树文件中指定了nuxtServerInit方法,nuxtJs调用它的时候会将页面的context上下文对象作为第2个参数传给它以供服务端调用,与fetch一样,不包括context.redirect和context.error方法,具体哪些参数可以查看官方文档。当我们想要将服务端的一些数据传到客户端,可以通过这个获取保存在状态中,客户端再从状态里取出来就好了。
nuxtServerInit:先把token存入cookie,这样每次请求都会自带cookie,那么利用nuxtServerInit里的参数 {req, res},去获取到请求附带的cookie,然后解析出token,然后再存入vuex。
推荐使用cookie插件cookie-universal-nuxt
npm i --save cookie-universal-nuxt
modules: [
// Simple usage
'cookie-universal-nuxt'
]
参考链接:添加链接描述
//组件未初始化时,需要使用上下文对象调用
//eg:
aysncData(context){
context.$cookies.set('name',value)
context.$cookies.get('name')
}
//组件已经初始化,可以直接使用this
create(){
this.$cookies.set('name',value)
this.$cookies.get('name')
}
store/index.js
import Vuex from 'vuex'
import cookieparse from '~/plugins/cookieparse'
import { login} from '~/api/request'
export const state = () => ({
token: null
})
export const mutations = {
saveToken(state, token) {
console.log('store.token.save = ' + token)
state.token = token
}
}
export const actions = {
async nuxtServerInit({ commit }, app) {
console.log('00000000000')
}
}
然后发现nuxtServerInit并未执行,mode改成universal之后,nuxtServerInit可以运行
运行结果:
mode的这两种模式有什么区别呢?
最直观的区别应该就是
spa不是ssr渲染,而universal是服务器端渲染
参考链接:添加链接描述
查看文件,vendors/app.js有6.3M
使用插件babel-plugin-component实现懒加载,优化打包体积
npm i babel-plugin-component -D
build: {
// 为 JS 和 Vue 文件设定自定义的 babel 配置。
babel: {
plugins: [
[
'component', { libraryName: 'element-ui', styleLibraryName: 'theme-chalk' }
]
]
}
}
再运行后
# NPM
npm install --save-dev webpack-bundle-analyzer
build: {
analyze: true
// or
analyze: {
analyzerMode: 'static'
}
}
npx nuxt build --analyze
//or
// npx nuxt build --a
优化前
优化
1.plugins/element-ui.js
import Vue from 'vue'
// import Element from 'element-ui'
import locale from 'element-ui/lib/locale/lang/en'
import { Button,Input } from 'element-ui'
import '../assets/stylesheets/element-variables.scss'
Vue.use(Button,{locale})
Vue.use(Input,{locale})
2.assets/stylesheets/element-variables.scss
// element-variables.scss
/* 样式--按需引入 */
@import "../../node_modules/element-ui/packages/theme-chalk/src/button";
@import "../../node_modules/element-ui/packages/theme-chalk/src/input";