※台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!
還在煩惱搬家費用要多少哪?台中大展搬家線上試算搬家費用,從此不再擔心「物品怎麼計費」、「多少車才能裝完」
如今前後端分離是大勢所趨,筆者雖然是做後台的,但也不得不學學前端的流行框架VUE -_-||| 。
為了學習VUE,筆者搭建了一個簡單的用戶後台,以此來了解VUE的開發思路(注:本項目不用於實際開發,只是為了學習,本文重點在於vue的動態路由添加,動態權限以及頁面處理的一些小問題)。
一、項目組成
VUE 2.6.11 + axios +VueX + ElementUI 2.13.2
二、整體思路
1. 用戶登錄后,獲取菜單數據,用以显示菜單。
2. 用戶登錄后,後台獲取Vue路由數據,用以動態添加到VueRouter中。
3. 用戶登錄后,從後台獲取用戶的權限,用以控制用戶是否對某一功能具有可操作權限。
三、具體實現
· 1. 登錄。由於本人學習重點是使用VUE動態添加路由、菜單显示和權限控制,所以登錄頁面沒有做具體功能,點擊登錄按鈕就表示登錄成功了。
由於登錄頁是用戶的第一界面,不存在任何權限問題,所以筆者就直接將登錄頁的路由直接寫在了VueRouter實例中。如下:
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [{
path: '/Login',
name: 'Login',
component: () => import('../views/Login.vue')
}]
export function initRouter() {
return new VueRouter({
routes
})
}
export default initRouter()
用戶通過 http://localhost:8080/#/login 可訪問到登陸頁面:
點擊登錄按鈕表示登錄成功!
登錄成功后的處理:
(1)向後台發請求拿到路由數據並存入VueX的state中,並通過addRoutes(routerObjArr)動態添加到路由實例中。注:後台返回的數據結構需跟route相一致,如圖:
前端所需數據結構:
後台返回的數據結構:
細節處理:由於後台返回的component字段是個組件地址字符串,這就需要將後台返回的route數據 一 一 做處理,通過import() 方法動態的加載組件,然後將返回的compoent對象重新賦值到component字段上。如圖:
代碼:
const _import = require('@/router/_import_' + process.env.NODE_ENV) //獲取組件的方法
/**將router的json字符串中的component轉換為組件對象 */
export function filterAsyncRouter(asyncRouterMap) {
if (!asyncRouterMap) return [];
function _iter(before) {
const after = Object.assign({}, before)
if (after.component) {
after.component = _import(after.component);
}
if (after.children && after.children.length) {
after.children = filterAsyncRouter(after.children);
}
return after
}
return asyncRouterMap.map(_iter)
}
圖中所用的import方法,根據生產環境不同,引用不同的文件,如圖:
各自的代碼如下:
_import_development.js:
module.exports = file => require('@/views/' + file + '.vue').default // vue-loader at least v13.0.0+
_import_production.js
module.exports = file => () => import('@/views/' + file + '.vue')
將後台的返回的路由數據處理完成后,最後就可以使用addRoutes方法動態加入VueRouter中了。此時,用戶便可以按照路由訪問頁面了。代碼如下:
//動態生成路由
axios
.get("https://localhost:5001/AdminApi/Home/GetMenuJson?userid=" + 1)
.then(res => {
//取出路由列表 (isRoute=1)
res.data.obj.router[0].children = res.data.obj.router[0].children.filter(
a => a.meta.isRoute == 1 //isRoute=1的
);
//存入緩存
this.$store.commit("setRoutes", res.data.obj.router);
//轉換組件對象
var getRouter = filterAsyncRouter(res.data.obj.router);
//打印當前路由列表
console.log("當前路由列表:", res.data.obj.router[0].children);
//清空之前的路由信息
this.$router.matcher = initRouter().matcher;
//重新添加路由信息
this.$router.addRoutes(getRouter);
//跳轉到 Layout 組件
this.$router.push("/");
});
(2)向後台發請求拿到權限數據,並存入VueX的state中。代碼如下:
※推薦台中搬家公司優質服務,可到府估價
台中搬鋼琴,台中金庫搬運,中部廢棄物處理,南投縣搬家公司,好幫手搬家,西屯區搬家
axios
.get(
"https://localhost:5001/AdminApi/Access/ActionPermission?userid=" + 1
)
.then(res => {
//存入權限
console.log("權限列表:", res.data.obj);
this.$store.commit("setAccess", res.data.obj);
});
(3)向後台請求數據並存入VueX中的state之前,需要清空上一次存入的數據(包括路由數據和權限數據),否則會造成數據混亂,如圖:
(4)addRoutes之前,不僅要做component字段的字符串轉對象的處理,還要清掉上一個用戶登錄后存入router中的路由數據,否則會造成數據混亂或者vue警告重複的路由名稱。
Login.vue組件中的全部代碼如下:
<template>
<div class="about">
<button @click="login">登錄</button>
</div>
</template>
<script> import { filterAsyncRouter } from "../common/promission"; import axios from "axios"; import { initRouter } from "@/router"; export default { created() { this.$store.commit("logout"); }, methods: { login() { //動態生成路由
axios .get("https://localhost:5001/AdminApi/Home/GetMenuJson?userid=" + 1) .then(res => { //取出路由列表 (isRoute=1)
res.data.obj.router[0].children = res.data.obj.router[0].children.filter( a => a.meta.isRoute == 1 //isRoute=1的
); //存入緩存
this.$store.commit("setRoutes", res.data.obj.router); //轉換組件對象
var getRouter = filterAsyncRouter(res.data.obj.router); //打印當前路由列表
console.log("當前路由列表:", res.data.obj.router[0].children); //清空之前的路由信息
this.$router.matcher = initRouter().matcher; //重新添加路由信息
this.$router.addRoutes(getRouter); //跳轉到 Layout 組件
this.$router.push("/"); }); axios .get( "https://localhost:5001/AdminApi/Access/ActionPermission?userid=" + 1 ) .then(res => { //存入權限
console.log("權限列表:", res.data.obj); this.$store.commit("setAccess", res.data.obj); }); } } }; </script>
promiss.js代碼如下:
const _import = require('@/router/_import_' + process.env.NODE_ENV) //獲取組件的方法
/**將router的json字符串中的component轉換為組件對象 */
export function filterAsyncRouter(asyncRouterMap) {
if (!asyncRouterMap) return [];
function _iter(before) {
const after = Object.assign({}, before)
if (after.component) {
after.component = _import(after.component);
}
if (after.children && after.children.length) {
after.children = filterAsyncRouter(after.children);
}
return after
}
return asyncRouterMap.map(_iter)
}
store.js代碼如下:
import Vue from 'vue'
import Vuex from 'vuex'
import VuexPersistence from 'vuex-persist'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
routes: [],
},
mutations: {
setRoutes: (state, routes) => {
state.routes = routes
},
setAccess: (state, access) => {
state.access = access;
},
logout: (state) => {
state.routes = [];
state.access = []
}
},
actions: {},
modules: {},
plugins: [new VuexPersistence().plugin]
})
2. 菜單。將Layout組件用作菜显示組件,將ele中的菜單組件複製到該組件中,並通過向後台請求數據,拿到菜單和菜單對應的分組數據 。拿到菜單和菜單分組數據后,循環遍歷,將菜單按照對應的分組全部显示(後台判斷當前用戶可显示的菜單,沒有權限的菜單直接不返給前台)。vue代碼以及後台數據如下:
<template>
<el-container>
<el-header>
<el-dropdown>
<i class="el-icon-setting"></i>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>修改密碼</el-dropdown-item>
<el-dropdown-item>退出</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<span>王小虎</span>
</el-header>
<el-container>
<el-aside width="250px">
<el-menu @select="handleSelect">
<el-submenu :index="group.name" v-for="group in groupList" :key="group.id">
<template slot="title">
<i class="el-icon-message"></i> {{group.title}} </template>
<template v-for="router in routerList">
<el-menu-item :index="router.path" :key="router.meta.id" v-if="router.meta.groupId == group.id"
>{{router.meta.title}}</el-menu-item>
</template>
</el-submenu>
</el-menu>
</el-aside>
<el-main>
<router-view />
</el-main>
</el-container>
</el-container>
</template>
<script> import axios from "axios"; export default { data() { return { activeIndex: "/home/Index", groupList: [], routerList: [] }; }, mounted() { this.getGroupList(); this.getRouterList(); }, methods: { //菜單點擊事件
handleSelect(key) { this.$router.push(key); }, //獲取菜單分組數據
getGroupList() { var that = this; axios .get("https://localhost:5001/AdminApi/Home/GetGroupJson") .then(res => { that.groupList = res.data.obj; }); }, //獲取菜單數據
getRouterList() { var that = this; axios .get("https://localhost:5001/AdminApi/Home/GetMenuJson") .then(res => { that.routerList = res.data.obj.router[0].children.filter( a => a.meta.display == 1 //取display=1的
); console.log("當前菜單列表"); console.log(that.routerList); }); } } }; </script>
<style> @import "../styles/layout.css"; /*引入公共樣式*/
</style>
後台分組數據:
{
"id": 14,
"name": "Customer",
"title": "客戶中心",
"target": "mainRigh",
"url": "#",
"icoCss": "layui-icon-username",
"delFlag": 0,
"sortNo": 0,
"createMan": 1,
"createTime": "2019-05-05T11:30:06"
},
{
"id": 9,
"name": "System",
"title": "系統設置",
"target": "123",
"url": "#",
"icoCss": "fa-gears",
"delFlag": 0,
"sortNo": 1,
"createMan": 1,
"createTime": "2019-05-05T11:29:56"
}
後台菜單數據:
效果圖:
3. 功能頁面的處理。
(1)組件的動態加載規則。 由於該vue項目中的組件是動態加載,那麼後台返回的路由數據中的component字段中的路徑自然也要按照某一種規則來返給前端。否則會造成import()組件的時候,由於地址不對解析加載不到組件而報錯。
例如筆者是按照這種規則:
後台數據
斜杠”/“前邊表示文件夾名稱,後邊表示組件名稱,這樣就可以按照這種規則動態加載到組件了。
(2).頁面刷新變成空白頁?(路由丟失)
遇到這個問題的話,在main.js中加入一段代碼,每次刷新頁面都把存入VueX state中的數據拿出來,判斷一下路由裡邊還存不存在當前刷新頁面的路由,如果沒有,則對VueRouters重新賦值
main.js 代碼如下:
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import store from './common/store'
import {
filterAsyncRouter
} from "./common/promission";
Vue.config.productionTip = false
Vue.use(ElementUI);
new Vue({
router,
store,
render: h => h(App),
mounted() {
// 緩存的路由信息
const routes = this.$store.state.routes
// 判斷當前路由是否被清除
const hasRoute = this.$router.options.routes.some(r => r.name == 'index')
// 如果 緩存中有路由信息 並且 當前路由被清除
if (routes.length && !hasRoute) {
//獲取路由Json字符串
var getRouter = filterAsyncRouter(routes);
// 再次添加路由信息
this.$router.addRoutes(getRouter);
// 然後強制更新當前組件
this.$forceUpdate()
}
},
}).$mount('#app')
(3) 頁面按鈕的控制
將前面存入vuex state中的權限數據,在每個組件中都拿出來一下存入一個變量中,在按鈕上使用v-if、array.indexOf(‘權限名稱’)來控制显示/隱藏。
原理是如果用戶存在該權限,則v-if=”true“,按鈕則显示,否則按鈕隱藏。
代碼如下:
<el-button @click="edit(scope.row)" type="text" size="small" v-if="accessList.indexOf('SysRole/AddEdit')>-1"
>編輯</el-button>
效果圖:
好了,筆者就介紹到這裏。當然,如果要做一個完整的後台,肯定還有很多要做的東西,比如用戶角色啊、角色授權啊等等;但筆者這次學習的重點是VUE的動態路由、動態權限,以及頁面處理中一些比較常見的坑,所以別的就不多介紹了。
如有需要,朋友們可以聯繫我,大家多多交流。
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
※台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!
還在煩惱搬家費用要多少哪?台中大展搬家線上試算搬家費用,從此不再擔心「物品怎麼計費」、「多少車才能裝完」