前言
- 最近被逼去搞vue了,这玩意早忘光了,看了下是要搞个类似后台管理项目,看看vue-elemnt-admin学学。
- 它还有个简易版vue-element-template,看了下缺的东西蛮多,权限路由也没写判断。
Mock
- vue-element-admin里的mock是nodejs整的服务,甩到了dev-server里。
- 需要关闭就把
before: require('./mock/mock-server.js')
这玩意给注释了就行。 - 如果调用是mock接口,那么启动控制台会显示invoke xxxx path。
- mock写法看文档:https://panjiachen.gitee.io/vue-element-admin-site/zh/guide/essentials/mock-api.html#easy-mock
layout
- 主要框子是layout,页面部分是app-main:
<template>
<section class="app-main">
<transition name="fade-transform" mode="out-in">
<keep-alive :include="cachedViews">
<router-view :key="key" />
</keep-alive>
</transition>
</section>
</template>
- 他这里做了很多处理,比如上面那个tag缓存什么的,这些写起来真是相当麻烦。不过并不推荐用keepalive,因为可能有缓存问题。
- 另外还整了右键做tag清除之类。
路由
- 这个路由写了相当多,包括mock里面也写了路由,然后我一研究发现,mock里的路由是其中有一页给角色分配路由权限用的,实际路由仍然是前端判断。
- 路由信息在router中集合。其中分为constants与n个asyncRoute。
- 一开始通过createRouter只加载了constantsRoute,asyncRoute是在vuex里的permission里派发的。
- 在路由钩子beforeEach中,会进行派发:
// get user info
// note: roles must be a object array! such as: ['admin'] or ,['developer','editor']
const { roles } = await store.dispatch('user/getInfo')
// generate accessible routes map based on roles
const accessRoutes = await store.dispatch('permission/generateRoutes', roles)
// dynamically add accessible routes
router.addRoutes(accessRoutes)
- 调用addRoutes动态加载路由。
- 常规路由和动态路由就照着往里面添加即可:
{
path: "/xxx",
component: Layout,
children: [
{
path: "index",
component: () => import("@/views/mytest/index"),
name: "mytest",
meta: { title: "mytest", icon: "bug", noCache: true }
}
]
},
{
path: "/kkkk",
component: Layout,
children: [
{
path: "edit/:id(\\d+)",
component: () => import("@/views/mytest2/index"),
name: "test2",
meta: {
title: "test2",
noCache: true
},
hidden: true
}
]
}
{
path: "/permission",
component: Layout,
redirect: "/permission/page",
alwaysShow: true, // will always show the root menu
name: "Permission",
meta: {
title: "Permission",
icon: "lock",
roles: ["admin", "editor"] // you can set roles in root nav
},
vuex
- vue-element-admin并没有什么非常骚的写法,还是比较容易懂的。
- 就是把modules下的文件都作为一个namespace然后该处理就处理。
- 他也并没有用常量去整,其实我觉得也挺好,不然看着麻烦。
- 异步派发就在actions里 ,mutations修改state 。
- 外层单独做了个getters可以方便的取各个namespace下的state。
- 你可以使用mapgetters来把state挂到this上:
import { mapGetters } from "vuex";
export default {
computed: {
...mapGetters(["roles"])
},
mounted() {
console.log(this.roles);
}
};
this.$store.dispatch('user/changeRoles', val)
主题
- 它这个主题写的是直接发个请求去拿对应element变量,然后创建style进行替换的骚操作。
- 如果有需要可以自行更改。
权限
- 除了上面的路由权限,它还封装了按钮级别的权限判断:
<template>
<!-- Admin can see this -->
<el-tag v-permission="['admin']">admin</el-tag>
<!-- Editor can see this -->
<el-tag v-permission="['editor']">editor</el-tag>
<!-- Editor can see this -->
<el-tag v-permission="['admin','editor']">Both admin or editor can see this</el-tag>
</template>
<script>
// 当然你也可以为了方便使用,将它注册到全局
import permission from '@/directive/permission/index.js' // 权限判断指令
export default{
directives: { permission }
}
</script>
- 实际就是通过getter拿role判断权限。没权限找el的父亲删掉它。
- 也可以使用权限判断函数+ vif判断,这种好理解点:
<template>
<el-tab-pane v-if="checkPermission(['admin'])" label="Admin">Admin can see this</el-tab-pane>
<el-tab-pane v-if="checkPermission(['editor'])" label="Editor">Editor can see this</el-tab-pane>
<el-tab-pane v-if="checkPermission(['admin','editor'])" label="Admin-OR-Editor">Both admin or editor can see this</el-tab-pane>
</template>
<script>
import checkPermission from '@/utils/permission' // 权限判断函数
export default{
methods: {
checkPermission
}
}
</script>
请求
service.interceptors.request.use(
config => {
// do something before request is sent
if (store.getters.token) {
// let each request carry token
// ['X-Token'] is a custom headers key
// please modify it according to the actual situation
config.headers['X-Token'] = getToken()
}
return config
},
error => {
// do something with request error
console.log(error) // for debug
return Promise.reject(error)
}
)
// response interceptor
service.interceptors.response.use(
/**
* If you want to get http information such as headers or status
* Please return response => response
*/
/**
* Determine the request status by custom code
* Here is just an example
* You can also judge the status by HTTP Status Code
*/
response => {
const res = response.data
// if the custom code is not 20000, it is judged as an error.
if (res.code !== 20000) {
Message({
message: res.message || 'Error',
type: 'error',
duration: 5 * 1000
})
// 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
// to re-login
MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
confirmButtonText: 'Re-Login',
cancelButtonText: 'Cancel',
type: 'warning'
}).then(() => {
store.dispatch('user/resetToken').then(() => {
location.reload()
})
})
}
return Promise.reject(new Error(res.message || 'Error'))
} else {
return res
}
},
error => {
console.log('err' + error) // for debug
Message({
message: error.message,
type: 'error',
duration: 5 * 1000
})
return Promise.reject(error)
}
)
- 它是会在请求头上带上X-token,当然这个根据实际情况写。
- 后面的响应也是根据自己实际来。
- gettoken是在cookie中拿的:
import Cookies from 'js-cookie'
const TokenKey = 'Admin-Token'
export function getToken() {
return Cookies.get(TokenKey)
}
export function setToken(token) {
return Cookies.set(TokenKey, token)
}
export function removeToken() {
return Cookies.remove(TokenKey)
}
login({ commit }, userInfo) {
const { username, password } = userInfo
return new Promise((resolve, reject) => {
login({ username: username.trim(), password: password }).then(response => {
const { data } = response
commit('SET_TOKEN', data.token)
setToken(data.token)
resolve()
}).catch(error => {
reject(error)
})
})
},
国际化
- 装b利器,不过默认下载的版本没装。
- 自行到i18n里去拿国际化版本:https://github.com/PanJiaChen/vue-element-admin/tree/i18n
样式
- 这个基本没啥说的,不像react的antdpro有样式污染问题。(虽然可以cssmodule或者jss解决)
- 全部加scope即可。
Plop
- 终于懂得起要加个plop了,有这玩意开发效率就高了一截。
- 它的plop配置是3种:
const viewGenerator = require('./plop-templates/view/prompt')
const componentGenerator = require('./plop-templates/component/prompt')
const storeGenerator = require('./plop-templates/store/prompt.js')
module.exports = function(plop) {
plop.setGenerator('view', viewGenerator)
plop.setGenerator('component', componentGenerator)
plop.setGenerator('store', storeGenerator)
}
- 结合Package.json,比如你要加个view,就npm run view,然后会让你输入view名字生成模板。(生成view其实用处不大,编辑器都有自带的直接写好)
- 然后还有store,component,跟view一个套路。