最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

vue-router+vuex addRoutes實(shí)現(xiàn)路由動(dòng)態(tài)加載及菜單動(dòng)態(tài)加載

 更新時(shí)間:2017年09月28日 10:44:30   作者:BeArchitect  
本篇文章主要介紹了vue-router+vuex addRoutes實(shí)現(xiàn)路由動(dòng)態(tài)加載及菜單動(dòng)態(tài)加載,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

此案例主要實(shí)現(xiàn)了一個(gè)功能是,在vue實(shí)例首次運(yùn)行時(shí),在加載了login和404兩個(gè)路由規(guī)則,登錄成功后,根據(jù)登錄用戶角色權(quán)限獲取該角色相應(yīng)菜單權(quán)限,生成新的路由規(guī)則添加進(jìn)去。

做過后臺(tái)管理系統(tǒng)都一定做過這個(gè)功能,在對(duì)菜單權(quán)限進(jìn)行粗粒度權(quán)限控制的時(shí)候,通過角色獲取菜單后,異步生成菜單,所以一開始拿到需求的時(shí)候,我也以為這和平常的沒什么不同,不過做起來就發(fā)現(xiàn)了很多問題,

1.vue-router的實(shí)例,在new vue實(shí)例的時(shí)候,就加載了,且必須加載,這個(gè)時(shí)候,登錄路由一定要加載,可是這個(gè)時(shí)候沒有登錄,無法確定權(quán)限
2.路由規(guī)則與菜單的同步

解決思路演化,菜單和路由同步,肯定是采用了vuex,一開始的思路的是,在一開始,就把所有的路由規(guī)則加載,然后在登錄的時(shí)候,取得權(quán)限路由,對(duì)比兩個(gè)路由,通過修改修改一個(gè)權(quán)限字段來隱藏菜單,如果在后臺(tái)頁面添加了新菜單規(guī)則,路由是按模塊加載的不同的文件,這時(shí)對(duì)路由的文件進(jìn)行新的讀寫,雖然可以解決問題,但是如果手動(dòng)在瀏覽器地址上路由,依然可以訪問,所以在路由的全局鉤子上還要做攔截。

這個(gè)解決方案雖然解決,但是顯的比較復(fù)雜,于是就想需找新的方法,重新瀏覽官方api,發(fā)現(xiàn)在2.2.0以后,官方新增了api,addRoutes,專門針對(duì)服務(wù)端渲染路由,那么這下問題就比較簡單了,下面列出實(shí)現(xiàn)代碼。以下代碼不能直接復(fù)用,需要根據(jù)實(shí)際情況修改,只是提供思路

app.js

let permission = JSON.parse(window.sessionStorage.getItem('permission')) 
if (permission) { 
 store.commit(ADD_MENU, permission) 
 router.addRoutes(store.state.menu.items) 
} 
router.beforeEach((route, redirect, next) => { 
 if (state.app.device.isMobile && state.app.sidebar.opened) { 
  store.commit(TOGGLE_SIDEBAR, false) 
 } 
 if (route.path === '/login') { 
  window.sessionStorage.removeItem('user') 
  window.sessionStorage.removeItem('permission') 
  store.commit(ADD_MENU, []) 
 } 
 let user = JSON.parse(window.sessionStorage.getItem('user')) 
 if (!user && route.path !== '/login') { 
  next({ path: '/login' }) 
 } else { 
  if (route.name) { 
   next() 
  } else { 
   next({ path: '/nofound' }) 
  } 
 } 
}) 

登錄的組件login.vue

<template> 
 <el-form :model="ruleForm2" :rules="rules2" ref="ruleForm2" label-position="left" label-width="0px" 
      class="demo-ruleForm login-container"> 
  <h3 class="title">系統(tǒng)登錄</h3> 
  <el-form-item prop="account"> 
   <el-input type="text" v-model="ruleForm2.account" auto-complete="off" placeholder="賬號(hào)"></el-input> 
  </el-form-item> 
  <el-form-item prop="checkPass"> 
   <el-input type="password" v-model="ruleForm2.checkPass" auto-complete="off" placeholder="密碼"></el-input> 
  </el-form-item> 
  <el-checkbox v-model="checked" checked class="remember">記住密碼</el-checkbox> 
  <el-form-item style="width:100%;"> 
   <el-button type="primary" style="width:100%;" @click.native.prevent="handleSubmit2" :loading="logining">登錄 
   </el-button> 
   <!--<el-button @click.native.prevent="handleReset2">重置</el-button>--> 
  </el-form-item> 
 </el-form> 
</template> 
 
<script> 
 import NProgress from 'nprogress' 
 import { mapActions, mapGetters } from 'vuex' 
 export default { 
  data () { 
   return { 
    logining: false, 
    ruleForm2: { 
     account: 'admin', 
     checkPass: '123456' 
    }, 
    rules2: { 
     account: [ 
      {required: true, message: '請(qǐng)輸入賬號(hào)', trigger: 'blur'} 
      // { validator: validaePass } 
     ], 
     checkPass: [ 
      {required: true, message: '請(qǐng)輸入密碼', trigger: 'blur'} 
      // { validator: validaePass2 } 
     ] 
    }, 
    checked: true 
   } 
  }, 
  computed: { 
   ...mapGetters([ 
    'menuitems', 
    'isLoadRoutes' 
    // ... 
   ]) 
  }, 
  methods: { 
   handleReset2 () { 
    this.$refs.ruleForm2.resetFields() 
   }, 
   handleSubmit2 (ev) { 
    this.$refs.ruleForm2.validate((valid) => { 
     if (valid) { 
      this.logining = true 
      NProgress.start() 
      let loginParams = {loginName: this.ruleForm2.account, password: this.ruleForm2.checkPass} 
      this.$http.post('/api/privilege/user/login', loginParams).then(resp => { 
       this.logining = false 
       NProgress.done() 
       let {message, data} = resp.data 
 
       if (message === 'fail') { 
        this.$notify({ 
         title: '錯(cuò)誤', 
         message: message, 
         type: 'error' 
        }) 
       } else { 
        window.sessionStorage.setItem('user', JSON.stringify(data.user)) 
        window.sessionStorage.setItem('permission', JSON.stringify(data.permission)) 
        this.addMenu(data.permission) 
        if (!this.isLoadRoutes) { 
         this.$router.addRoutes(this.menuitems) 
         this.loadRoutes() 
        } 
        this.$router.push('/system/office') 
       } 
      }) 
     } else { 
      console.log('error submit!!') 
      return false 
     } 
    }) 
   }, 
 
   ...mapActions([ 
    'addMenu', 
    'loadRoutes' 
   ]) 
  } 
 } 
 
</script> 
 
<style lang="scss" scoped> 
 .login-container { 
  /*box-shadow: 0 0px 8px 0 rgba(0, 0, 0, 0.06), 0 1px 0px 0 rgba(0, 0, 0, 0.02);*/ 
  -webkit-border-radius: 5px; 
  border-radius: 5px; 
  -moz-border-radius: 5px; 
  background-clip: padding-box; 
  margin-bottom: 20px; 
  background-color: #F9FAFC; 
  margin: 180px auto; 
  border: 2px solid #8492A6; 
  width: 350px; 
  padding: 35px 35px 15px 35px; 
 
 .title { 
  margin: 0px auto 40px auto; 
  text-align: center; 
  color: #505458; 
 } 
 
 .remember { 
  margin: 0px 0px 35px 0px; 
 } 
 
 } 
</style> 

關(guān)鍵點(diǎn)解釋

computed: { 
   ...mapGetters([ 
    'menuitems', 
    'isLoadRoutes' 
    // ... 
   ]) 
  }, 

這里是從vuex取得兩個(gè)對(duì)象,menuitems是菜單對(duì)象,isLoadRoutes是用來判斷是否是第一次登錄,用來排除重復(fù)加載路由規(guī)則

...mapActions([ 
    'addMenu', 
    'loadRoutes' 
   ]) 

這里是從vuex取得兩個(gè)方法,一個(gè)是添加菜單,一個(gè)更改loadRoutes的值

this.$router.addRoutes(this.menuitems) 

這是關(guān)鍵api,動(dòng)態(tài)的向router實(shí)例中添加路由規(guī)則

menu模塊的state與mutations

const state = { 
 items: [ 
 ], 
 isLoadRoutes: false 
} 
 
const mutations = { 
 [types.EXPAND_MENU] (state, menuItem) { 
  if (menuItem.index > -1) { 
   if (state.items[menuItem.index] && state.items[menuItem.index].meta) { 
    state.items[menuItem.index].meta.expanded = menuItem.expanded 
   } 
  } else if (menuItem.item && 'expanded' in menuItem.item.meta) { 
   menuItem.item.meta.expanded = menuItem.expanded 
  } 
 }, 
 [types.ADD_MENU] (state, menuItems) { 
  if (menuItems.length === 0) { 
   state.items = [] 
  } else { 
   generateMenuItems(state.items, menuItems) 
  } 
 }, 
 [types.LOAD_ROUTES] (state) { 
  state.isLoadRoutes = !state.isLoadRoutes 
 } 
} 

路由配置文件router.js

import Vue from 'vue' 
import Router from 'vue-router' 
import menuModule from 'vuex-store/modules/menu' 
Vue.use(Router) 
 
export default new Router({ 
 mode: 'hash', // Demo is living in GitHub.io, so required! 
 linkActiveClass: 'is-active', 
 scrollBehavior: () => ({ y: 0 }), 
 routes: [ 
  { 
   path: '/login', 
   component: require('../Login.vue'), 
   meta: { 
    expanded: false, 
    show: false 
   }, 
   name: 'Login' 
  }, 
  { 
   path: '/', 
   component: require('../views/Home.vue'), 
   meta: { 
    expanded: false, 
    show: false 
   }, 
   children: [ 
    { path: '/nofound', component: require('../404.vue'), name: 'NOFOUND', meta: {show: false} } 
   ] 
  }, 
  ...generateRoutesFromMenu(menuModule.state.items) 
 ] 
}) 
 
// Menu should have 2 levels. 
function generateRoutesFromMenu (menu = [], routes = []) { 
 for (let i = 0, l = menu.length; i < l; i++) { 
  let item = menu[i] 
  if (item.path) { 
   routes.push(item) 
  } 
 } 
 return routes 
} 

vuex

import Vue from 'vue' 
import Vuex from 'vuex' 
import * as actions from './actions' 
import * as getters from './getters' 
 
import menu from './modules/menu' 
 
Vue.use(Vuex) 
 
const store = new Vuex.Store({ 
 strict: true, // process.env.NODE_ENV !== 'development', 
 actions, 
 getters, 
 modules: { 
  menu 
 }, 
 mutations: { 
 } 
}) 
 
export default store 

actions

export const addMenu = ({ commit }, menuItems) => { 
 if (menuItems.length > 0) { 
  commit(types.ADD_MENU, menuItems) 
 } 
} 
 
export const loadRoutes = ({ commit }) => { 
 commit(types.LOAD_ROUTES) 
} 

getters

const menuitems = state => state.menu.items 
const isLoadRoutes = state => state.menu.isLoadRoutes 
export { 
 menuitems, 
 isLoadRoutes 
} 

mutations_type.js

export const ADD_MENU = 'ADD_MENU' 
 
export const LOAD_ROUTES = 'LOAD_ROUTES' 

因?yàn)樯厦娴拇a不能直接運(yùn)行,再次梳理一下思路,

1.創(chuàng)建vue實(shí)例的時(shí)候,將vuex和vue-router加載,這個(gè)時(shí)候,vue-router只有登錄規(guī)則和404規(guī)則

2.vuex中state管理的狀態(tài)對(duì)象有,菜單對(duì)象menuitems,是否加載過路由loadRoutes ,并提供相應(yīng)的getters與actions當(dāng)然還有一些其他的,這里沒有列舉

3.然后在登錄組件中,登錄成功后,將服務(wù)端傳回來之后,調(diào)用actions更改state.menuitems,并且中間有格式化的過程,這個(gè)過程的代碼沒有貼出來,主要是由于不同的表涉和服務(wù)端返回的數(shù)據(jù)不一樣,,

4.然后調(diào)用addRoutes和actions更改已經(jīng)加載過路由的方法

5.然后為了防止用戶直接手動(dòng)按f5刷新頁面,這個(gè)時(shí)候會(huì)重新構(gòu)建vue實(shí)例,而又沒有重新登錄,所以vuex里面的東西會(huì)清空,所以將登錄后的數(shù)據(jù)存放在sessionStroage中,在刷新頁面,重新構(gòu)建vue實(shí)例的時(shí)候,會(huì)有判斷

6.之后會(huì)渲染側(cè)邊欄組件,列出菜單,數(shù)據(jù)就可以根據(jù)state.menuitems來就可以了,我這里沒有貼我的,實(shí)際根據(jù)自己的需求來

后面有時(shí)間會(huì)在github上上傳完整代碼。

以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Vue.js如何監(jiān)聽window窗口尺寸變化

    Vue.js如何監(jiān)聽window窗口尺寸變化

    使用VUE開發(fā)后臺(tái)項(xiàng)目,后臺(tái)項(xiàng)目需要進(jìn)行后臺(tái)根據(jù)瀏覽器窗口進(jìn)行變化,需要使用vue來監(jiān)聽瀏覽器的窗口變化,這篇文章主要給大家介紹了關(guān)于Vue.js如何監(jiān)聽window窗口尺寸變化的相關(guān)資料,需要的朋友可以參考下
    2023-11-11
  • 詳解vue中的動(dòng)態(tài)組件component和keep-alive

    詳解vue中的動(dòng)態(tài)組件component和keep-alive

    這篇文章主要介紹了詳解vue中的動(dòng)態(tài)組件component和keep-alive的相關(guān)資料,這大家需要注意include屬性和exclude屬性只能用一個(gè),不能同時(shí)使用,本文給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2023-11-11
  • Vue中的混入的使用(vue mixins)

    Vue中的混入的使用(vue mixins)

    這篇文章主要介紹了Vue中的混入的使用(vue mixins),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-06-06
  • Avue實(shí)現(xiàn)動(dòng)態(tài)查詢與數(shù)據(jù)展示的示例代碼

    Avue實(shí)現(xiàn)動(dòng)態(tài)查詢與數(shù)據(jù)展示的示例代碼

    Avue是一個(gè)基于Vue.js的前端框架,它是由阿里云開發(fā)的一款企業(yè)級(jí)UI組件庫,旨在提供一套全面、易用且高性能的界面解決方案本文介紹了Avue實(shí)現(xiàn)動(dòng)態(tài)查詢與數(shù)據(jù)展示的示例,需要的朋友可以參考下
    2024-08-08
  • 解決Vue2.0 watch對(duì)象屬性變化監(jiān)聽不到的問題

    解決Vue2.0 watch對(duì)象屬性變化監(jiān)聽不到的問題

    今天小編就為大家分享一篇解決Vue2.0 watch對(duì)象屬性變化監(jiān)聽不到的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-09-09
  • vue3.0中使用Element-Plus中Select下的filter-method屬性代碼示例

    vue3.0中使用Element-Plus中Select下的filter-method屬性代碼示例

    這篇文章主要給大家介紹了關(guān)于vue3.0中使用Element-Plus中Select下的filter-method屬性的相關(guān)資料,Filter-method用法是指從一組數(shù)據(jù)中選擇滿足條件的項(xiàng),文中通過圖文以及代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-12-12
  • Vue后臺(tái)中優(yōu)雅書寫狀態(tài)標(biāo)簽的方法實(shí)例

    Vue后臺(tái)中優(yōu)雅書寫狀態(tài)標(biāo)簽的方法實(shí)例

    在Vue中,我們可以非常便捷地通過標(biāo)簽實(shí)現(xiàn)狀態(tài)的保存,這篇文章主要給大家介紹了關(guān)于Vue后臺(tái)中如何優(yōu)雅的書寫狀態(tài)標(biāo)簽的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2021-08-08
  • 手把手帶你安裝vue-cli并創(chuàng)建第一個(gè)vue-cli應(yīng)用程序

    手把手帶你安裝vue-cli并創(chuàng)建第一個(gè)vue-cli應(yīng)用程序

    vue-cli這個(gè)構(gòu)建工具大大降低了webpack的使用難度,支持熱更新,有webpack-dev-server的支持,相當(dāng)于啟動(dòng)了一個(gè)請(qǐng)求服務(wù)器,給你搭建了一個(gè)測(cè)試環(huán)境,下面這篇文章主要給大家介紹了關(guān)于安裝vue-cli并創(chuàng)建第一個(gè)vue-cli應(yīng)用程序的相關(guān)資料,需要的朋友可以參考下
    2022-08-08
  • 詳解.vue文件中監(jiān)聽input輸入事件(oninput)

    詳解.vue文件中監(jiān)聽input輸入事件(oninput)

    本篇文章主要介紹了詳解.vue文件中監(jiān)聽input輸入事件(oninput),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-09-09
  • 如何使用vue實(shí)現(xiàn)前端導(dǎo)入excel數(shù)據(jù)

    如何使用vue實(shí)現(xiàn)前端導(dǎo)入excel數(shù)據(jù)

    在實(shí)際開發(fā)中導(dǎo)入功能是非常常見的,導(dǎo)入功能前端并不難,下面這篇文章主要給大家介紹了關(guān)于如何使用vue實(shí)現(xiàn)前端導(dǎo)入excel數(shù)據(jù)的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-04-04

最新評(píng)論

宁强县| 渭源县| 隆子县| 镇江市| 宁都县| 灵宝市| 鲁山县| 晋中市| 阜康市| 广州市| 莫力| 新晃| 宁阳县| 长乐市| 贵南县| 钟山县| 湖南省| 额济纳旗| 肃宁县| 乃东县| 扶沟县| 峨边| 湘乡市| 丘北县| 古丈县| 汽车| 巴南区| 惠东县| 刚察县| 新宁县| 华宁县| 集安市| 南昌市| 麻城市| 冕宁县| 定襄县| 丰镇市| 永和县| 扶风县| 泰宁县| 黑龙江省|