vue 自定义系统流程【3】 路由及权限 -- 未完待续
路由及权限
一、初始化 及测试路由
安装 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 栏,可以查看错误信息
安装
文档 vuex.vuejs.org/zh/
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 中全局引入
官网示例:github.com/vuejs/vuex/…
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-scope
are 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
beforeDestroy
lifecycle hook is deprecated. UsebeforeUnmount
instead
照着改
引入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.
作者:刺猬老爷
链接:https://juejin.cn/post/7022167007910952997