附一个我完成的PHP的动态方案,主要代码
首先PHP要返回用户可访问的路由,期望的结果是菜单中可以有一个指向 /example/sample
的菜单和路由。
public function actionMenu()
{
$data =[
[
'path' => '/example',
'component' => 'Layout',
'redirect'=> '',
'name'=> 'ExampleRoot',
'meta'=> [
'title'=>'示例',
'icon'=>'table'
],
'children'=>[
[
'path' => 'sample',
'component' => '/example/sample',
'name'=> 'ExampleSample',
'meta'=> [
'title'=>'example',
'icon'=>'table'
],
]
]
]
]
;
return json_encode($data);
}
然后修改 src/store/modules/permission.js
添加一个方法
function dataArrayToRoutes(data) {
const res = []
data.forEach(item => {
const tmp = { ...item }
if (tmp.component === 'Layout') {
tmp.component = Layout
} else {
let sub_view = tmp.component
sub_view = sub_view.replace(/^\/*/g, '')
tmp.component = () => import(`@/views/${sub_view}`) //这里很重要,把view动态加载进来,而且似乎我只找到这样的写法,用拼接不行,然后 views 后面没有斜杆也不行
}
if (tmp.children) {
tmp.children = dataArrayToRoutes(tmp.children)
}
res.push(tmp)
})
return res
}
然后修改这个文件中的 actions
const actions = {
generateRoutes({ commit, state }, { roles, menus }) {
return new Promise(resolve => {
let accessedRoutes
// if (roles.includes('admin')) {
// accessedRoutes = asyncRoutes || []
// } else {
// accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
// }
// commit('SET_ROUTES', accessedRoutes)
accessedRoutes = dataArrayToRoutes(menus)
commit('SET_ROUTES', accessedRoutes)
resolve(accessedRoutes)
})
}
}
然后新增一个 user/getMenus
的 Vuex 的 action
const state = {
token: getToken(),
name: '',
avatar: '',
introduction: '',
roles: [],
menus: [] //这个是我新增的
}
const mutations = {
SET_TOKEN: (state, token) => {
state.token = token
},
SET_INTRODUCTION: (state, introduction) => {
state.introduction = introduction
},
SET_NAME: (state, name) => {
state.name = name
},
SET_AVATAR: (state, avatar) => {
state.avatar = avatar
},
SET_ROLES: (state, roles) => {
state.roles = roles
},
SET_MENUS: (state, menus) => { //这里是新增的
state.menus = menus
}
}
const actions = {
getMenus({ commit, state }) { //这个是新增的action
return new Promise((resolve, reject) => {
getMenus(state.token).then(response => { //这里的getMenus是调用request方法从服务端获得路由菜单数据的Promise,类似getInfo
const { data } = response
console.log(data)
if (!data) {
reject('Verification failed, please Login again.')
}
const menus = data
// roles must be a non-empty array
if (!menus || menus.length <= 0) {
reject('getMenus: menus must be a non-null array!')
}
commit('SET_MENUS', menus)
resolve(menus)
}).catch(error => {
reject(error)
})
})
},
}
还有一个文件是 src/permission.js
要在 store.dispatch('permission/generateRoutes')
代码附近要改一下,原先从本地配置+roles获得用户路由,现在改从服务端获得之后再 addRoutes
const menus = await store.dispatch('user/getMenus')
// generate accessible routes map based on roles
const accessRoutes = await store.dispatch('permission/generateRoutes', { menus })
// dynamically add accessible routes
router.addRoutes(accessRoutes)
亲测可行……
Originally posted by @amoydavid in #293 (comment)
7条答案
按热度按时间czfnxgou1#
Uncaught Error: Module build failed (from ./node_modules/eslint-loader/index.js):
TypeError: Cannot read property 'range' of null
Occurred while linting E:\project\base-vue\src\store\modules\permission.js:24
at SourceCode.getTokenBefore (E:\project\base-vue\node_modules\eslint\lib\source-code\token-store\index.js:298:18)
at checkSpacingBefore (E:\project\base-vue\node_modules\eslint\lib\rules\template-curly-spacing.js:60:42)
at TemplateElement (E:\project\base-vue\node_modules\eslint\lib\rules\template-curly-spacing.js:119:17)
at E:\project\base-vue\node_modules\eslint\lib\linter\safe-emitter.js:45:58
at Array.forEach ()
at Object.emit (E:\project\base-vue\node_modules\eslint\lib\linter\safe-emitter.js:45:38)
at NodeEventGenerator.applySelector (E:\project\base-vue\node_modules\eslint\lib\linter\node-event-generator.js:254:26)
at NodeEventGenerator.applySelectors (E:\project\base-vue\node_modules\eslint\lib\linter\node-event-generator.js:283:22)
at NodeEventGenerator.enterNode (E:\project\base-vue\node_modules\eslint\lib\linter\node-event-generator.js:297:14)
at CodePathAnalyzer.enterNode (E:\project\base-vue\node_modules\eslint\lib\linter\code-path-analysis\code-path-analyzer.js:634:23)
at E:\project\base-vue\node_modules\eslint\lib\linter\linter.js:936:32
at Array.forEach ()
at runRules (E:\project\base-vue\node_modules\eslint\lib\linter\linter.js:931:15)
at Linter._verifyWithoutProcessors (E:\project\base-vue\node_modules\eslint\lib\linter\linter.js:1157:31)
at Linter._verifyWithConfigArray (E:\project\base-vue\node_modules\eslint\lib\linter\linter.js:1255:21)
at Linter.verify (E:\project\base-vue\node_modules\eslint\lib\linter\linter.js:1210:25)
at eval (webpack-internal:///./src/store/modules/permission.js:1:7)
at Object../src/store/modules/permission.js ( http://localhost:9527/static/js/app.js:4193:1 )
at webpack_require ( http://localhost:9527/static/js/app.js:849:30 )
at fn ( http://localhost:9527/static/js/app.js:151:20 )
at webpackContext (eval at ./src/store/modules sync recursive .js$ ( http://localhost:9527/static/js/app.js:4158:1 ), :13:9)
at eval (webpack-internal:///./src/store/index.js:36:15)
at Array.reduce ()
at eval (webpack-internal:///./src/store/index.js:33:35)
at Object../src/store/index.js ( http://localhost:9527/static/js/app.js:4147:1 )
at webpack_require ( http://localhost:9527/static/js/app.js:849:30 )
dvtswwa32#
用的是最新的4.4.0
8iwquhpp3#
https://panjiachen.github.io/vue-element-admin-site/zh/guide/advanced/lazy-loading.html#%E6%96%B0%E6%96%B9%E6%A1%88
这里的解决方案
mmvthczy4#
import { constantRoutes } from '@/router'
import Layout from '@/layout'
import storeUtils from '@/utils/storeUtils'
function filterAsyncRoutes(routers) {
const accessedRouters = routers.filter(route => {
if (route.component) {
if (route.component === 'Layout') { // Layout组件特殊处理
route.component = Layout
} else {
debugger
route.component = _import(route.component)
}
}
if (route.children && route.children.length) {
route.children = filterAsyncRoutes(route.children)
}
return true
})
return accessedRouters
}
export const _import = file => {
debugger
return () => import(
@/views/${file}.vue
)// return (resolve) => require([
@/views/${file}.vue
], resolve)}
const state = {
addRoutes: storeUtils.getStorageS(storeUtils.CONST.addRoutes) || [],
routers: [],
permission: storeUtils.getStorageS(storeUtils.CONST.permission) || []
}
const mutations = {
SET_ROUTERS: (state, routes) => {
state.addRoutes = routes
state.routers = constantRoutes.concat(routes)
storeUtils.setStorageS(storeUtils.CONST.addRoutes, state.addRoutes)
},
SET_PERMISSION: (state, permission) => {
state.permission = permission
storeUtils.setStorageS(storeUtils.CONST.permission, state.permission)
}
}
const actions = {
generateRoutes({ commit, state }) {
return new Promise(resolve => {
console.log('过滤前传过来的', state.addRoutes)
var accessedRoutes = filterAsyncRoutes(state.addRoutes)
accessedRoutes.push({ path: '*', redirect: '/404', hidden: true })
console.log('过滤后', accessedRoutes)
commit('SET_ROUTERS', accessedRoutes)
resolve(accessedRoutes)
})
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
这是改造的代码
0dxa2lsx5#
@/views/${sub_view}
))@/views/${sub_view}
import(imUrl )
这两种方法也不行吗?
lzfw57am6#
同遇到此问题,一直卡在这
Cannot read property 'range' of null
mwkjh3gx7#
附一个我完成的PHP的动态方案,主要代码
首先PHP要返回用户可访问的路由,期望的结果是菜单中可以有一个指向
/example/sample
的菜单和路由。然后修改
src/store/modules/permission.js
添加一个方法
然后修改这个文件中的 actions
然后新增一个
user/getMenus
的 Vuex 的 action还有一个文件是
src/permission.js
要在
store.dispatch('permission/generateRoutes')
代码附近要改一下,原先从本地配置+roles获得用户路由,现在改从服务端获得之后再addRoutes
亲测可行……
Originally posted by @amoydavid in #293 (comment)
你好,我按照你的方法,路由打印出来了,但是没有跳转,一直在循环打印中。这是怎么回事呢