本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。
路由及权限
一、初始化 及测试路由
- 安装 js-cookie
npm i js-cookie
- 工具类
- ./utils/auth.js token 验证 【后面权限会用到,就一起增加了】
import Cookies from 'js-cookie'
const TokenKey = 'Admin-Token' //默认自定义 token
export function getToken() {
return Cookies.get(TokenKey)
}
export function setToken(token) {
return Cookies.set(TokenKey, token)
}
export function removeToken() {
return Cookies.remove(TokenKey)
}
- ./utils/get-page-title.js 获取页头标题
import defaultSettings from '@/config/settings'
const title = defaultSettings.title || 'Vue Element Admin'
export default function getPageTitle(pageTitle) {
if (pageTitle) {
return `${pageTitle} - ${title}`
}
return `${title}`
}
- 在main.js 中引入 工具类
import { getToken } from '@/utils/auth' // get token from cookie
import getPageTitle from '@/utils/get-page-title'
- 路由控制器 设置路由
- ./src/router/index.js 继承【1】 的 index.js
- 【增加】 登录页面路由、错误页面 404 401 路由
//staicRoutes 中增加
{
path: '/login',
component: () => import('@/views/login/index'),
hidden: true
},
{
path: '/404',
component: () => import('@/views/error-page/404'),
hidden: true
},
{
path: '/401',
component: () => import('@/views/error-page/401'),
hidden: true
},
{
path: '/',
component: () => import('@/views/layout/index'),
//hidden: true
},
- 静态资源
- 我把图片文件都拷贝到了
- src\assets\images\errors/
- 模板
- \src\views\error-page/401.vue
- \src\views\error-page/404.vue
- 修改401,404 图片文件路径 为上面的路径
@/assets/images/errors/xxx.xxx
- 拷贝\src\views\login 文件夹
- SocialSignin.vue 要在 wechatHandleClick(thirdpart) 和 tencentHandleClick(thirdpart) 下添加
console.log(thirdpart)
//否则可能 Esline 会提示 定义但是没有使用的错误
- 创建 ./premission.js 权限控制器
- 这里面的设置标题,有一点问题,后面有机会再延伸开展,先挖坑
import router from './router'
import { getToken } from '@/utils/auth' // get token from cookie
import getPageTitle from '@/utils/get-page-title'
const whiteList = ['/login', '/auth-redirect'] // no redirect whitelist
router.beforeEach(async(to, from, next) => {
document.title = getPageTitle(to.meta.title) //设置标题
const hasToken = getToken() //获取token
if (hasToken) {
// console.log(hasToken)
next()
}else{
if (whiteList.indexOf(to.path) !== -1) {
// in the free login whitelist, go directly
next()
} else {
// other pages that do not have permission to access are redirected to the login page.
next()//暂时忽略
// next(`/login?redirect=${to.path}`)
// NProgress.done()
}
}
})
- 测试页面
- 浏览器 测试 index.js 的各个页面
http://localhost:8080/login
http://localhost:8080/401
。。。
二、控制权限 及 限定路由跳转
- 说明:
- 这里面有2种思路。一种是传统类似 cms的,首页是可以访问的,但是 后台管理页面是另外的,那就涉及到多入口进入,也可以叫做不限制入口,这种适合综合网站,设置也比较复杂,暂时不展开。
- 另外一种是 默认就限制入口的单入口进入,适合直接就是管理后台模板【当前使用这种】
- 路由说明:所有的路由都由 getToken 获取 ,如果获取不到,则全部跳转到登录页面
- 跳转路由:router/index.js staticRoutes 下,最顶部增加
{
path: '/redirect',
//component: Layout,
hidden: true,
children: [
{
path: '/redirect/:path(.*)',
component: () => import('@/views/redirect/index')
}
]
},
-
拷贝跳转页面 模板: src/views/redirect
-
权限控制
- permission.js 找到
if (whiteList.indexOf(to.path) !== -1) {
// in the free login whitelist, go directly
next()
} else {
。。。
- else 部分改为
next(`/login?redirect=${to.path}`)
- 测试一下
- 浏览器进入网址,最终都会跳转到 http://localhost:8080/login?redirect=/xxx
http://localhost:8080
- NProgress 进度条
三、axios
- 安装
- axios 网络请求 ajax
npm i axios
四、Vuex 状态管理模式 v4.x 【权限配置相关】
- 整体控制都在 permission.js 里面 router.beforeEach(async(to, from, next) => { 中进行
- 提示:浏览器 的 websocket 栏,可以查看错误信息
- 安装
npm i vuex@next
- 新建 状态文件夹 src/store
- 复制 store/getter.js
- store/index.js 引入 vuex
- 新写法如下
import { createStore } from 'vuex'
import getters from './getters'
//模块文件夹
const modulesFiles = require.context('./modules', true, /\.js$/)
//解析模块
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
// set './app.js' => 'app'
const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
const value = modulesFiles(modulePath)
modules[moduleName] = value.default
return modules
}, {})
export default createStore({
modules,
getters
})
- /src/main.js 中全局引入
import store from './store'
。。。
const app = createApp(App)
app.component('svg-icon', SvgIcon).use(ElementPlus).use(router).use(store).mount('#app')
4 ./src/permission.js 中引入
- 新写法
import { useStore } from 'vuex'
import getters from './getters'
//模块文件夹
const modulesFiles = require.context('./modules', true, /\.js$/)
//解析模块
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
// set './app.js' => 'app'
const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
const value = modulesFiles(modulePath)
modules[moduleName] = value.default
return modules
}, {})
export default {
setup () {
const store = useStore({
modules,
getters
})
return store
}
}
- /src/router/index.js
- 找到 export default router
//在 上面添加 :重置路由函数
const router = createRouter({
history: createWebHistory(),
// scrollBehavior: () => ({ y: 0 }),
routes: staicRoutes
})
- \src\store\modules/user.js 用户状态管理
- 拷贝
- ENV 环境变量文件
- 全局根目录下,新建 /.env.development
- 主要定义了当前 ENV 的类型以及 VUE_APP_BASE_API 【ajax路径】
- 后面还有其他的env ,先挖坑
- /utils/request.js 请求工具
- axios 请求 都在这里发出
- 创建 src/api 文件夹 所有接口文件夹
- 在这里引入了request.js
- api/user 暂时直接考过去
- 这时候 打开控制台,测试一下登录,然后发现后台console 请求失败,说明前面步骤已经测通,准备开始下一步
errError: Request failed with status code 404
- 剩余的几个文件暂时不考过去【继续挖坑】
流程说明
- 实现流程
- src/views/login/index.vue 中
- 通过 handleLogin() {
- 访问状态 this.$store.dispatch('user/login', this.loginForm)
- 在 store/modules/user.js 中调用 api/user.js 的 login方法
- 进行提交 login
- 流程解析
- 这时候重新看刚才的第9步的问题:
- 浏览器 刚才那个登录页面,console 打开,查看 network 部分,login是红色,点击后查看 右侧 header
- Request Url:http://localhost:8080/dev-api/vue-element-admin/user/login 这个就是请求的地址
- 其实是由 env 和 api 拼接的。
- 延伸阅读
- 如果在路由 router/index.js 中把刚才那个 链接 加进去设置的话
/dev-api/vue-element-admin/user/login
- 是可以访问的,但还是不能进行post,还是会 一样出现404
- 原因是什么?
- 因为 进行POST 请求的是外站【也就是后端】,而路由配置的都是本站,也就是前端请求。
- 具体的解释是什么?继续挖坑。。。以后补上
五、搭建 本地虚拟测试服务器 mockjs
- 为了模拟后台数据及接口
1. 安装
npm i -D mockjs
2. 引入 mockjs 的使用
- 进入 vue.config.js devServer 属性
- 增加如下
before: require('./mock/mock-server.js')
3.自建 mockjs server
- 根目录 创建 mock 文件夹
- 以下创建的.js 文件 或 文件夹 全部都在 mock 文件夹内
- 创建 工具类 utils.js
-
创建 mock-server.js【服务器】 文件
-
创建 index.js【入口】文件
- 拷贝过去就好了
- 先注销跟 article、search 相关的语句
- 创建 user.js 用户文件【拷贝】
- 模拟请求访问后得到的用户数据
- 这时候 重启启动服务器
- 点击登录后 发现会跳转了
- 如果 url 只是指向 login 的话,就完成登录,会跳到 路由设置的 ‘/’ 首页中
- 如果还有别的指向,则跳转到之前设置的 页面中
4. 完成路由及权限控制
- 接下来完成 之前的权限路由 src/permission.js
- 之前的路由已经实现没有权限,除登录外,全部跳转到登录页面
- 现在还要实现,有权限的情况下,登录页面 直接跳到首页
- 有权限,但是没有路由的话,跳到404
- 提示:如果想要明显的看出效果,可以在 if (hasToken) { 里面 加上,你就知道权限在哪里了
alert('23')
- /src/router/index.js 增加 特殊权限路由
- 原本的 constantRoutes、asyncRoutes 我改为 staicRoutes、rolesRoutes 我觉得更直观点。一个是静态路由,不需要权限的,一个是权限路由
- 如果改这两个名字的,permission.js 的第一行导入 要记得换成一样的
export const rolesRoutes = [
{
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
},
children: [
{
path: 'page',
component: () => import('@/views/permission/page'),
name: 'PagePermission',
meta: {
title: 'Page Permission',
roles: ['admin'] // or you can only set roles in sub nav
}
},
{
path: 'directive',
component: () => import('@/views/permission/directive'),
name: 'DirectivePermission',
meta: {
title: 'Directive Permission'
// if do not set roles, means: this page does not require permission
}
},
{
path: 'role',
component: () => import('@/views/permission/role'),
name: 'RolePermission',
meta: {
title: 'Role Permission',
roles: ['admin']
}
}
]
},
// 404 page must be placed at the end !!!
{ path: '*', redirect: '/404', hidden: true }
]
- 权限控制 src/permission.js
- 创建 role 文件夹 【权限访问模拟】
- role/index.js 用户文件【拷贝】
- 模拟请求访问后得到的用户数据
- /store/modules/permission.js
- 1步设置的 accessRoutes,最终获取到这里,用于判断是否在 【有权限的状态】
- redirect 的跳转的路由
- 增加 @/directive/permission/index.js' // 权限判断指令
- @/utils/permission' // 权限判断函数
- 'views/permission/components/SwitchRoles'
- 接口
- src/api/role.js
- src/api/user.js
- 工具
- /utils/index.js
- src\views\permission
- role.vue
- role.vue 中部分修改
slot-scope 全部改为 v-slot
- 示例
//原
<template slot-scope="scope">
{{ scope.row.key }}
</template>
//改为
<template v-slot="{scope}">
{{ scope.row.name }}
</template>
-
- role.vue
29 行 :visible.sync= 改为
v-model=
- 到了这一步,总觉得路由和权限这块还是没说清楚,而且总觉得有点太繁琐了。
- 虽然这个是最重要的地方,但是觉得还是有点绕圈圈。有空再重新做一下
六. 框架填充及路由的深度优化
1. 框架填充
- 增加 前台模板框架
- 原本的layout文件夹 vue-element-admin\src\layout\components
- 拷贝到 views\layout\components
-
拷贝控制台模板 src\views\dashboard
-
/router/index.js 修改
- asyncRoutes 增加路由
2. 拷贝 \src\layout\mixin
- 主要用于防抖
- 参考 blog.csdn.net/zcc900726/a…
3. 拷贝组件 [\src\components]
- Breadcrumb 面包屑导航
- ErrorLog 错误日志
- HeaderSearch 页头搜索
- RightPanel 右侧栏
- ScreenFull 全屏
- SizeSelect 尺寸选择?
- ThemePicker 模板选择
- Hamburger ?
4. 安装 依赖
- vue-count-to 计时器?
- echarts 表格样式?
- screenfull 全屏
- fuse.js
npm i vue-count-to
npm i echarts
npm i screenfull
npm i fuse.js
5. 模板填充 及 修改vue
- 复制vue
- src\views\dashboard\admin\components/BarChart.Vue
- beforeDestroy.vue 改 beforeUnmount【问题10】
- boxCard.vue slot 改 :v-slot 【问题5】
- LineChart.vue、PieChart.vue beforeDestroy 改 beforeUnmount
- views\dashboard\admin\components\TodoList\index.vue 这个改动的比较多 主要是filter 废除 还未解决
- views\dashboard\admin\components\TransactionTable.vue 这个改动的比较多 主要是filter 废除 还未解决
- src\api/remote-search.js
- \src\components\GithubCorner
- \src\components\PanThumb
- \src\components\TextHoverEffect
- 修改 新版本echart 引入【问题11】
- PieChart.vue
- LineChart.vue
- RaddarChart.vue
- BarChart.vue
- import echarts from 'echarts'
- 改为
import * as echarts from 'echarts'
- index.vue
- 之前测试的那个可以去掉了,改成现在的了
- 拷贝 layout/index.vue 过去
line 61 @import "~@/styles/mixin.scss"; => @import "~@/res/styles/mixin.scss";
line 62 @import "~@/styles/variables.scss"; => @import "~@/res/styles/variables.scss";
- \src\views\layout\mixin\ResizeHandler.js
line 8 暂时增加 console.log(route)
6. 修改组件模板 vue 【\src\views\layout\components\】
- Sidebar\index.vue
line25 import variables from '@/styles/variables.scss' => import variables from '@/res/styles/variables.scss'
- Navbar.vue
1. slot => :v-slot
2. @click.native => v-on:click
- Sidebar\SidebarItem.vue
slot => :v-slot
- TagsView\ScrollPane.vue
line2: @wheel.native.prevent => v-on:prevent
line25: beforeDestroy => beforeUnmount
- TagsView\Index.vue
line12:@click.middle.native => v-on:click
line13:@contextmenu.prevent.native => v-on:prevent
- ThemePicker\Index.vue
11 const version = require('element-ui/package.json').version // element-ui version from node_modules
- 改为
const version = require('element-plus/package.json').version // element-ui version from node_modules
- ErrorLog\index.vue
line 3 @click.native => v-on@click
line 9 :visible.sync => :v-bind:visible
line 10. slot => :v-slot
line 16. slot-scope => v-slot
- \RightPanel\index.vue,Screenfull\index.vue
beforeDestroy => beforeUnmount
- SizeSelect\index.vue
line 6 slot => :v-slot
- ThemePicker\index.vue
line 28 handler: function(val, oldVal) {
- 暂时修改 :增加 console.log(oldVal)
七、状态管理
- 之前挖的 那个 store 文件夹的文件坑,现在来补上
- 拷贝
- 把app.js/errorLog.js/setting.js/tagView.js 考过去
- 修改
- setting.js
line1 import variables from '@/styles/element-variables.scss' => import variables from '@/res/styles/element-variables.scss'
line2 import defaultSettings from '@/settings' => import defaultSettings from '@/config/settings'
- /src/res/styles/element-variables.scss
line 23 : $--font-path: "~element-ui/lib/theme-chalk/fonts"; => $--font-path: "~element-plus/lib/theme-chalk/fonts";
line 25 : @import "~element-ui/packages/theme-chalk/src/index"; => @import "~element-plus/packages/theme-chalk/src/index";
- 【暂时】把assets\custom-theme/fonts 文件夹 考入 src\res\styles 下面
七点五、半途小记
- 做到这里,发现页面不显示了,应该是其他的component 没有拷贝进来,发现的问题也越来越多了。文档有时候都来不及写了,因为边写边码实在是太慢了。有时候解决完几个问题了,又忘记写记录了。。。
- 只好放在最后复盘的时候再来吧
- 之前的路由 router.js 中 那个 静态权限和必要权限 的 变量名,我还是改回去了,constantRoutes 和 asyncRoutes,因为后面有部分地方需要用到。暂时还是先完成升级,再来处理这个问题吧。
- 【3】不知不觉写的有点多了,估计很多都可以放到【4】去写。。。但是感觉还差一些,而且也得放到【3】中。那就继续吧。
八、component 的文件补充
- 问题分析
- 登录后 console 出现 vue 的警告问题【问题12】、【问题13】,并且页面显示空白
- 初步分析是因为路由有写,但是 component 没有拷贝过来。
- 这样就不是 error 型的错误,不需要检查前面的框架进入流程错误。而是属于 warm 警告类的错误,检查页面模板就可以
- 看错误主要是出在子菜单上面
- 【问题13的解决】结果:
- 找了半天,始终无法解决。后来发现自己的思路错了,去翻了一下 element-plus 的文档。问题也很简单。。。element-plus 和 element-ui 的部分代码不一样。。。
- el-submenu 【2.x】 =》 el-sub-menu
- 【卡在 问题14 Unhandled error during execution of render function】 上面了,好像很多人都是卡在这里。。
- 我也无奈了,只能等更新完了再继续了。。
九、后记
- 写到这里我决定暂停一下了。实在看不出问题在哪里。。。我决定去啃文档了。
- 之前写的几篇,都没有做整理。以后完成了再来整理吧。当前还是得先去啃文档。
- 暂停。。这算是大坑了吧~~~
问题
- 登录界面 index.vue
- Missing required prop: "modelValue"
- xtraneous non-props attributes (visible) were passed to component but could not be automatically inherited because component renders fragment or text root nodes.
- 问题原因:
- blog.csdn.net/Zoroastrian…
- 解决:
- vue.config.js
configureWebpack 底下的
module: {
// rules: [
全部注释掉就可以了
- 似乎已经由vue 进行控制了,就不要在这里配置了
- vuex.esm-browser.js?5502:1012 [vuex] unknown action type: user/login
- 一般是 store/index.js 的配置出错
- 例如:检查这里
export default createStore({
modules: {
modules,
getters
},
})
- 应该改为
export default createStore({
modules,
getters
})
- errError: Request failed with status code 404
- mock.js 没有起作用,或者 request.js 的最终路由写错
- Cannot read property 'concat' of undefined
- 部分 vue 没有加载
slot-scopeare deprecated
- 插槽:v3 中的
slot和slot-scope改为 v-slot - 文档 v3.cn.vuejs.org/guide/compo…
- 解决
//原写法
<div class="content">
<slot name="contrite"></slot>
</div>
//js
<h1 slot="contrite" class="title">内容</h1>
//渲染结果
<div class="content">
<h1 class="title">内容</h1>
</div>
//2.新写法
<div class="content">
<slot name="contrite"></slot>
</div>
<template v-slot:contrite>
内容
</template>
//可以简写
<template #contrite>
内容
</template>
//渲染结果一致
-
::v-deep usage as a combinator has been deprecated. Use :deep() instead.
-
[Vue Router warn]: Component "default" in record with path "undefined" is not a valid component. Received "undefined".
-
[Vue Router warn]: uncaught error during route navigation:
-
vue-router.esm-bundler.js?6c02:72 [Vue Router warn]: Unexpected error when starting the router: Error: Invalid route component
- 94 行 directory v-deep 改为
- 示例
//原
.parent ::v-deep .child {
...
}
//改为
.parent ::v-deep(.child) {
...
}
- 到登录成功后的 无路由404
- The
beforeDestroylifecycle hook is deprecated. UsebeforeUnmountinstead
- 照着改
- 引入echars5.0报错“export ‘default‘ (imported as ‘echarts‘) was not found in ‘echarts‘
- 【解决】引入方式改为
import * as echarts from 'echarts';
// 或
const echarts = require('echarts');
- Cannot read property 'icon' of undefined
- 估计问题在 router ,部分 component 没有引入
- console 定位到错误 Proxy.render (Item.vue?b2c3:16)
- 位于:\src\views\layout\components\Sidebar\item.vue
- Failed to resolve component: el-submenu If this is a native custom element, make sure to exclude it from component resolution via compilerOptions.isCustomElement.
- 无法解析组件【el子菜单】
- Unhandled error during execution of render function 。。。
- Unhandled error during execution of scheduler flush. This is likely a Vue internals bug.