后臺(tái)管理系統(tǒng)的項(xiàng)目小結(jié)
寫(xiě)起來(lái)卻觸及到不少知識(shí)點(diǎn),關(guān)于vue全家桶什么的都用到了
實(shí)現(xiàn)功能或者一些想記錄的點(diǎn)
1.登錄(axios實(shí)例和攔截器)
2.動(dòng)態(tài)側(cè)邊欄和面包屑(this.$router.options.routes,meta路由元的使用)
3.iconfont的使用
4.頁(yè)面布局和可復(fù)用組件
5.element-ui,js-cookie,一些工具方法的使用
6.vuex模塊化和抽離api接口
7.es6/7和webpack的一些語(yǔ)法
實(shí)現(xiàn)思路
登錄:獲取用戶(hù)表單信息,提交后給后端接口驗(yàn)證,如果匹配則返回一個(gè)token,使用cookie存儲(chǔ),再根據(jù)token去拉取用戶(hù)信息接口獲取信息,這里的具體操作主要看后端接口如何書(shū)寫(xiě),登錄成功后,跳轉(zhuǎn)至主頁(yè)面。
這里使用自定義配置創(chuàng)建axios實(shí)例:axios.create([config]),指定的配置將與實(shí)例配置合并:axios#get(url [,config]),這里會(huì)配置基本路徑和超時(shí)時(shí)間。還使用了axios攔截器,這里使用request攔截器是為了在每個(gè)請(qǐng)求頭塞入token,好讓后端對(duì)請(qǐng)求進(jìn)行權(quán)限驗(yàn)證(根據(jù)業(yè)務(wù)而定),response攔截器,當(dāng)服務(wù)端返回特殊的狀態(tài)碼,做統(tǒng)一處理。
其中有一個(gè)導(dǎo)航守衛(wèi),有組件需要登錄才能展示,這個(gè)練習(xí)項(xiàng)目中,是先登錄才能展示其他頁(yè)面,不登錄無(wú)法展示頁(yè)面,所以有一個(gè)全局的導(dǎo)航守衛(wèi)。這里注冊(cè)一個(gè)全局前置守衛(wèi),當(dāng)一個(gè)導(dǎo)航觸發(fā)時(shí),全局前置守衛(wèi)按照創(chuàng)建順序調(diào)用。守衛(wèi)是異步解析執(zhí)行,此時(shí)導(dǎo)航在所有守衛(wèi) resolve 完之前一直處于 等待中。
每個(gè)守衛(wèi)方法接收三個(gè)參數(shù):
router.beforeEach((to, from, next) => {
// ...
})
router.beforeEach((to,from,next)=>{
if(getToken()){
if(to.path==='/login'){
next({path:'/'})
}else{
if(store.getters.roles.length===0){ //判斷當(dāng)前用戶(hù)是否已拉取完user_info信息
store.dispatch('GetInfo').then(res=>{//拉取user_info
next()
}).catch(()=>{
store.dispatch('FedLogOut').then(()=>{
Message.error('驗(yàn)證失敗,請(qǐng)重新登錄')
next({path:'/login'})
})
})
}else{
next()
}
}
}else{
if(whiteList.indexOf(to.path)!==-1){
next()
}else{
next('/login')
}
}
})
具體實(shí)現(xiàn)思路,當(dāng)用戶(hù)點(diǎn)擊提交按鈕,對(duì)表單信息格式驗(yàn)證,如果通過(guò)則觸發(fā)vuex的actions里面login方法,在回調(diào)中跳轉(zhuǎn)至主頁(yè)面。actions的login方法的主要操作是調(diào)用api接口,處理數(shù)據(jù),login里面是設(shè)置cookie('Token',token)和改變state的token,因?yàn)槭钦{(diào)用的api接口,所以在api里面的login接口,是主要書(shū)寫(xiě)接口的。
api文件的login接口
import axios from '@/utils/request' //request中,創(chuàng)建了axios實(shí)例和攔截器的書(shū)寫(xiě)
export const login=(username, password)=>{
return axios.post('/user/login',{username,password})
}
actions的login方法
Login({commit},userInfo){ //負(fù)責(zé)接口處理
const username=userInfo.name.trim()
return new Promise((resolve,reject)=>{
login(username,userInfo.password).then(res=>{
const data=res.data //接收值
setToken(data.token) //設(shè)置cookie
commit('SET_TOKEN',data.token) //設(shè)置state的token
console.log(data)
resolve()
}).catch(error=>{
reject(error)
})
})
}
//添加請(qǐng)求攔截器
axios.interceptors.request.use(function(config){
//在發(fā)送請(qǐng)求之前做某事
return config;
},function(error){
//請(qǐng)求錯(cuò)誤時(shí)做些事
return Promise.reject(error);
});
//添加響應(yīng)攔截器
axios.interceptors.response.use(function(response){
//對(duì)響應(yīng)數(shù)據(jù)做些事
return response;
},function(error){
//請(qǐng)求錯(cuò)誤時(shí)做些事
return Promise.reject(error);
});
2動(dòng)態(tài)側(cè)邊欄和面包屑
根據(jù)路由里面的配置,動(dòng)態(tài)生成導(dǎo)航,router里面配置了meta,寫(xiě)了導(dǎo)航標(biāo)題和小圖標(biāo)。在導(dǎo)航組件中遍歷this.$router.options.routes ,這個(gè)可以獲取到路由的信息,遍歷時(shí)會(huì)有一些條件判斷,根據(jù)需要來(lái)遍歷,展示相應(yīng)的導(dǎo)航。
3.iconfont的使用,看了大神的代碼,原來(lái)優(yōu)雅的代碼是這樣的,這個(gè)已經(jīng)寫(xiě)過(guò)總結(jié),這里就不寫(xiě)了。
4.vuex模塊化和api接口
對(duì)于一些大型項(xiàng)目可以把vuex進(jìn)行模塊劃分,調(diào)用模塊里的方法需要帶上模塊名,而getters卻是不區(qū)分模塊的,所以getters的命名不能重復(fù)。api文件里面主要是抽離出來(lái)的api接口,最好組件名和接口文件命名相同,便于查找。
5 代理跨域proxy
在本地開(kāi)發(fā)環(huán)境中一般會(huì)在proxytable里面進(jìn)行設(shè)置,但是在生產(chǎn)環(huán)境中還是需要解決跨域的問(wèn)題,所以在config/dev.env.js和config/prod.env.js都設(shè)置一下
dev.env.js
'use strict'
const merge = require('webpack-merge')
const prodEnv = require('./prod.env')
module.exports = merge(prodEnv, {
NODE_ENV: '"development"',
BASE_API: '"https://www.xxx.com"',
})
prod.env.js
'use strict'
module.exports = {
NODE_ENV: '"production"',
BASE_API: "https://www.xxx.com",
}
這里單獨(dú)寫(xiě)了一個(gè)js文件來(lái)處理請(qǐng)求
// 創(chuàng)建axios實(shí)例
const service = axios.create({
baseURL: process.env.BASE_API, // api的base_url,是開(kāi)發(fā)環(huán)境還是生產(chǎn)環(huán)境會(huì)自動(dòng)尋找路徑
timeout: 15000 // 請(qǐng)求超時(shí)時(shí)間
})
export default service
在main.js中引入,全局注冊(cè)
import axios from './api/index.js'
Vue.prototype.$axios=axios
使用
this.$axios.get('api/v1/topic/'+this.id)
.then(res=>{
})
項(xiàng)目過(guò)程中的記錄
1 子組件和一些可復(fù)用組件
2 slot
3 :routes="[child]" :key="child.path"
4matched=[{path:'/dashboard',meta:{title:Dashboard}}].concat(matched)
5filter
6 有header+main+sidebar,怎么在 main中點(diǎn)擊 Header組件里的menu,去觸發(fā) SideBar的效果呢。這需要用到組件中的通信,并且不是父子組件,
參考方法 1可以使用this.$root.$emit和this.$root.$on試試,event bus 2vuex,因?yàn)轫?xiàng)目里使用了vuex,所以應(yīng)該是從vuex找方法了
7路由懶加載和權(quán)限驗(yàn)證和進(jìn)度條和中英文切換
8require.context
9promise
10easy-mock.js
11支持無(wú)限嵌套路由,所有側(cè)邊欄這塊使用了遞歸組件
12api模塊和views組件命名一一對(duì)應(yīng)