vite+ts+mock+vue-router+pinia实现vue的路由权限

0.权限管理

前端的权限管理主要分为如下:

  • 接口权限
  • 路由权限
  • 菜单权限
  • 按钮权限

权限是对特定资源的访问许可,所谓权限控制,也就是确保用户只能访问到被分配的资源

1.项目搭建

创建vite项目

yarn create vite

配置别名

npm install path --save

npm install @types/node --save-dev

tsconfig.json
在这里插入图片描述

    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"],
      "@components/*": ["./src/components/*"]
    },

vite.config.ts

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from "path";

// https://vitejs.dev/config/
export default defineConfig({
  resolve: {
    // 配置路径别名
    alias: {
      "@": path.resolve(__dirname, "./src"),
      "@components": path.resolve(__dirname, "./src/components"),
    },
  },
  plugins: [
    vue(),
  ]
  
})

创建基础路由

npm i vue-router@4
const routes = [
    {
      name: "Home",
      path: "/",
      component: () => import("@/views/Home.vue"),
    },
   
  ];
  export default routes; //导出
  
import { createRouter, createWebHistory } from "vue-router";
import routes from "./router";

const router = createRouter({
  history: createWebHistory(),
  routes,
});
export default router;

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router'
const app =createApp(App)
app.use(router)
app.mount('#app')
<script setup lang="ts">
</script>

<template>
  <router-view></router-view>
</template>

<style scoped>

</style>

配置mock

yarn add mockjs vite-plugin-mock -D
import { MockMethod } from 'vite-plugin-mock';
export default [
  {
    url: `/api/list`,
    method: 'get',
    response: () => {
      return [{
 			 name:'tom',
 			 age:16,
 			 nation:'USA'
			}];
    },
  },
 
] as MockMethod[];

vite.config.ts配置

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
import { viteMockServe } from 'vite-plugin-mock'

// https://vitejs.dev/config/
export default defineConfig({
  resolve: {
    // 配置路径别名
    alias: {
      "@": path.resolve(__dirname, "./src"),
      "@components": path.resolve(__dirname, "./src/components"),
    },
  },
  plugins: [
    vue(),
    viteMockServe({
	    mockPath: './src/mock'
	  })
  ]
})

使用

<script setup lang="ts">
import axios from 'axios';

axios.get('/api/list').then(res=>{
    console.log(res.data);

})
</script>

<template>
<h1>超市管理系统首页</h1>

</template>

<style scoped>

</style>

在这里插入图片描述

安装pinia

yarn add pinia
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router'
import { createPinia } from 'pinia'
const pinia = createPinia()


const app =createApp(App)
app.use(router)
app.use(pinia)
app.mount('#app')

import { defineStore } from 'pinia'

export const useMarkStore = defineStore('mark', {
    state: () => ({ count: 0 }),
    getters: {
      double: (state) => state.count * 2,
    },
    actions: {
      increment() {
        this.count++
      },
    },
})

<script setup lang="ts">
import { useMarkStore } from '@/store/store';
import axios from 'axios';

const store= useMarkStore()
axios.get('/api/list').then(res=>{
    console.log(res.data);

})
</script>

<template>
<h1>超市管理系统首页</h1>
<h1>{{ store.count }}</h1>

</template>

<style scoped>

</style>

在这里插入图片描述

安装js-cookie插件

yarn add js-cookie

2.路由权限(包括菜单权限和按钮权限)

目录结构:
在这里插入图片描述

mock

import { MockMethod } from "vite-plugin-mock";
export default [
  {
    url: `/api/list`,
    method: "post",
    response: ({ body }) => {
      return body;
    },
  },
  {
    url: `/api/login`, //登录逻辑
    method: "post",
    response: ({ body }) => {
      let data = {};
      if (body.username == "tom") {
        data = {
          id: "1111",
          token: "4566adasdqfrqwd",
        };
      } else if (body.username == "amy") {
        data = {
          id: "222",
          token: "45184adaczz52za",
        };
      }
      return data;
    },
  },
  {
    url: `/api/getRoutes`, //简单方案:根据用户返回不同路由,真实后端逻辑:根据登录用户的角色去表里查授权该角色的的菜单
    method: "post",
    response: ({ body }) => {
      console.log(body);
      const routes = [];
      if (body.id == "1111") {
        routes.push(
          {
            name: "page1",
            path: "/page1",
            component: "/Page1.vue",
          },
          {
            name: "page2",
            path: "/page2",
            component: "/Page2.vue",
          }
        );
      } else if (body.id == "222") {
        routes.push( {
          name: "page3",
          path: "/page3",
          component: "/Page3.vue",
        });
      }
      return routes;
    },
  },
] as MockMethod[];

router

在这里插入图片描述

store

import { defineStore } from "pinia";
import Cookies from "js-cookie";
import axios from "axios";
import routes from '@/router/router'
const modules = import.meta.glob("../views/**/*.vue");

export const useMarkStore = defineStore("mark", {
  state: () => ({
    pageRoutes: <any>[], //当前页面缓存路由
    asyncRoutes: <any>[],//从接口获取到的路由数组
  }),
  getters: {
  },
  actions: {
    SET_ROUTES(_routes: any[]){
    //设置state中的值
        this.$state.asyncRoutes=_routes
        this.$state.pageRoutes=routes.concat(_routes)

    },
    getRouter() {
    //从后端接口获取到动态路由
      let _id = Cookies.get("id");
      if (_id) {
        return new Promise((resolve, reject) => {
          axios.post("/api/getRoutes", { id: _id }).then((res) => {
            console.log(res);
            let _data = res.data;
            let newData = this.parseRouter(_data);
            this.SET_ROUTES(newData)
            resolve(newData);
          });
        });
      }
    },
    parseRouter(_data: Array<any>) {
      //处理后端返回的路由数据=》vite项目能解析的路由格式
      let _newArr: Array<any> = [];
      _data.forEach((item: any) => {
        let newItem = Object.assign({}, item);
        let comp = item.component;

        newItem.component = modules[`../views${comp}`];
        _newArr.push(newItem);
      });
      return _newArr;
    },
  },
  getButtonCode(){
    //按钮权限思路:
    //1.在登录的时候拉取按钮权限编码code['EXPORT_LIST','OPEN_MODAL']
    //2.将编码缓存本地
    //3.页面通过v-if控制按钮或是自义定指令控制按钮

  }
});

permission.ts

import router from "@/router";
import { useMarkStore } from "@/store/store";
import Cookies from "js-cookie";


//获取view下所有的vue文件
// const modules = import.meta.glob('../views/**/*.vue')


//   export const getCurrRoutes=(name:string)=>{

//   }

// await axios.post('/api/getRoutes',{username:'tom'}).then(res=>{
//     console.log(res);
//     let _data=res.data
//     _data.forEach((item:any)=>{
//         let newItem=Object.assign({},item)
//         let comp=item.component

//         newItem.component=modules[`../views${comp}`]
//         router.addRoute(newItem)
//     })

// })
//白名单
const whiteList=['/about','/new','/login']

//路由守卫
router.beforeEach(async(to,from,next)=>{
    const store= useMarkStore()

    const token=Cookies.get("token")
    console.log(token);
   
    if(token){
        if(to.path=='login'){
            next('/')
        }else{
            //判断是否拿了路由规则
            if(store.asyncRoutes.length==0){
                //格式化好的路由
              const _temp:any=  await store.getRouter()
              _temp.forEach((item:any)=>router.addRoute(item))
              //继续跳转
              next(to.path)

            }else{
                if(to.matched.length!=0){
                    next()
                }else{
                    alert('无页面权限')
                    next(from.path)
                }
            }
        }
    }else{
        if(whiteList.indexOf(to.path)!= -1){
            next()
        }else{
            next('/login')
        }
        
    }
})

Login.vue

<script setup lang="ts">
import axios from 'axios';
import { ref } from 'vue';
import Cookies from 'js-cookie'
import { useRouter } from 'vue-router';
const router =useRouter()
const username=ref()

const login=()=>{
    axios.post('/api/login',{username:username.value}).then(res=>{
    console.log(res);
    if(res.data.token){
        Cookies.set('token',res.data.token)
        Cookies.set('id',res.data.id)
        router.push('/')
    }

})  
  axios.post('/api/getRoutes',{username:username.value}).then(res=>{
    console.log(res);

})
}
</script>

<template>
<h1>登录</h1>
<div>用户名:<input type="text" v-model="username"></div>
<button @click="login">登录</button>

</template>

<style scoped>

</style>

Home.vue

<script setup lang="ts">
import { useMarkStore } from '@/store/store';
import axios from 'axios';
import Cookies from 'js-cookie'

const store= useMarkStore()
axios.post('/api/list',{params:{name:'aaa'}}).then(res=>{
    console.log(res);

})

import { useRouter } from 'vue-router';
const router =useRouter()
const loginout=()=>{
    Cookies.remove('token')
    Cookies.remove('id')
    router.push('/login')
}

</script>

<template>
    <div @click="loginout">登出</div>
<h1>超市管理系统首页</h1>
<div>当前用户{{  }}</div>
<div>当前用户可用菜单:</div>
<div v-if="store.asyncRoutes" style="display: flex;flex-direction: column;" >
    <a v-for="item in store.asyncRoutes" :href="item.path">{{ item?.name }}</a>
</div>

</template>

<style scoped>

</style>

main.ts

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router'
import { createPinia } from 'pinia'
import  '@/util/permission'
const pinia = createPinia()

const app =createApp(App)
app.use(router)
app.use(pinia)
app.mount('#app')

按钮权限思路

 getButtonCode(){
    //按钮权限思路:
    //1.在登录的时候拉取按钮权限编码code['EXPORT_LIST','OPEN_MODAL']
    //2.将编码缓存本地
    //3.页面通过v-if控制按钮或是自义定指令控制按钮

  }

前端控制权限

//1.在路由配置中配置白名单
{
   name: "Login",
   path: "/login",
   component: () => import("@/views/Login.vue"),
   meta:{
		whiteList:['admin','tom']
	}
 },
 //2.在路由守卫beforeEach中判断当前用户角色是否在meta中,是就next()

效果

在这里插入图片描述
tom登录
在这里插入图片描述
amy登录

在这里插入图片描述

3.接口权限

登录完拿到token,将token存起来,通过axios请求拦截器进行拦截,每次请求的时候头部携带token

axios.interceptors.request.use(config => {
    config.headers['token'] = cookie.get('token')
    return config
})
axios.interceptors.response.use(res=>{},{response}=>{
    if (response.data.code === 40099 || response.data.code === 40098) { //token过期或者错误
        router.push('/login')
    }
})

4.注意点

mock


const login=()=>{//这里传参有三种方式:data,params,{}
    axios.post('/api/login',{username:'tom'}).then(res=>{
    console.log(res);

}) 
import { MockMethod } from "vite-plugin-mock";
export default [
  {
    url: `/api/login`, //登录逻辑
    method: "post",
    response: ({ body }) => {//获取传的参数使用body
      return body;
    },
  },
 
] as MockMethod[];

addRoute

动态添加路由在vite中不能使用以下方法:

// 路由拼接
function loadView(view:string) {
    return () => import(`@/views/${view}`)
}

上面的代码会报错:TypeError: Failed to resolve module specifier,应该采用import.meta.glob方式

import router from "@/router";
import axios from "axios";
//获取view下所有的vue文件
const modules = import.meta.glob('../views/**/*.vue')

//这里需要将异步获取的值改为同步
await axios.post('/api/getRoutes',{username:'tom'}).then(res=>{
    console.log(res);
    let _data=res.data
    _data.forEach((item:any)=>{
        let newItem=Object.assign({},item)
        let comp=item.component
        newItem.component=modules[`../views${comp}`]
        router.addRoute(newItem)
    })

})

5.源码地址

https://gitee.com/beekim/vue-route-mgr

参考:
https://cloud.tencent.com/developer/article/1794300
https://github.com/vitejs/vite/discussions/2746
https://blog.csdn.net/lucklymm/article/details/125420877
https://blog.csdn.net/weixin_43239880/article/details/129922664
https://blog.csdn.net/qq_36651686/article/details/116520731

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/634610.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

查看cpu

cpu是几核的怎么查看_windows查看cpu核数-CSDN博客文章浏览阅读1.4w次&#xff0c;点赞11次&#xff0c;收藏24次。cpu是几核的怎么查看_windows查看cpu核数https://blog.csdn.net/llg___/article/details/125317223?ops_request_misc&request_id&biz_id102&utm_t…

多模态大模型新进展——GPT-4o、Project Astra关键技术丨青源Workshop第27期

青源Workshop丨No.27 多模态大模型新进展—GPT-4o、Project Astra关键技术主题闭门研讨会 刚刚过去的两天&#xff0c;OpenAI、Google纷纷发布了多模态大模型的最新成果&#xff0c;GPT-4o、Project Astra先后亮相。 本周五&#xff08;北京时间5月17日&#xff09;18点&#x…

力扣1809 没有广告的剧集(postgresql)

需求 Table: Playback ----------------- | Column Name | Type | ----------------- | session_id | int | | customer_id | int | | start_time | int | | end_time | int | ----------------- 该表主键为&#xff1a;session_id &#xff08;剧集id&#xff09; customer_…

v-md-editor和SSE实现ChatGPT的打字机式输出

概述 不论是GPT还是文心一言&#xff0c;在回答的时候类似于打字机式的将答案呈现给我们&#xff0c;这样的交互一方面比较友好&#xff0c;另一方面&#xff0c;当答案比较多、生成比较慢的时候也能争取一些答案的生成时间。本文后端使用express和stream&#xff0c;使用SSE将…

WXML模板语法-数据绑定

1.数据绑定的基本原则 (1)在data中定义数据 (2)在WXML中使用数据 2.在data页面中定义数据&#xff1a;在页面对应的.js文件中&#xff0c;把数据定义在data对象中即可 &#xff08;这里打错了 应该是数组类型的数据... 报意思啊&#xff09; 3.Mustache语法的格式 把data中的…

容器组件:栅格布局,侧边栏容器(HarmonyOS学习第四课【4.5】)

栅格布局 栅格布局可以为布局提供规律性的结构&#xff0c;解决多尺寸多设备的动态布局问题&#xff0c;保证不同设备上各个模块的布局一致性。 栅格容器组件&#xff0c;仅可以和栅格子组件(GridCol)在栅格布局场景中使用。 说明 该组件从API Version 9开始支持。后续版本…

WordPress主题 7B2 PRO 5.4.2 免授权开心版源码

本资源提供给大家学习及参考研究借鉴美工之用&#xff0c;请勿用于商业和非法用途&#xff0c;无任何技术支持&#xff01; WordPress主题 7B2 PRO 5.4.2 免授权开心版源码 B2 PRO 5.4.2 最新免授权版不再需要改hosts&#xff0c;和正版一样上传安装就可以激活。 直接在Word…

计算机精选期刊特辑

文章目录 一、征稿简介二、合作期刊三、投稿咨询四、咨询 一、征稿简介 艾思科蓝依托互联网信息与数据库技术、整合渠道与合作资源&#xff0c;提供EI/SCI/SCIE/SSCI期刊论文的内容审查、发表支持等服务。艾思科蓝与多所知名出版社达成战略合作关系&#xff0c;持续开展合作征…

【Unity】Rider无法调试团结引擎

近在学习unity&#xff0c;代码编辑器选择了熟悉的idea系列&#xff0c;C# 对应的编辑器 rider 之前在使用unity的时候&#xff0c;可以直接使用 Rider进行调试&#xff0c;很方便 但是后来又安装了团结引擎&#xff0c;在启动调试的时候断点总是无法激活 在点击调试按钮的时…

Vue文本溢出如何自动换行

css新增 word-break: break-all; word-wrap: break-word;

如何在没有密码或Face ID的情况下解锁iPhone

iPhone 是一款以其一流的安全功能而闻名的设备&#xff0c;包括面容 ID 和密码。但是&#xff0c;你有没有想过&#xff0c;如果没有这些安全措施&#xff0c;你是否可以解锁iPhone&#xff1f;无论您是忘记了密码&#xff0c;Face ID不起作用&#xff0c;还是只是对其他方法感…

浅析declval关键字

浅析 declval 关键字 文章目录 浅析 declval 关键字前言declval 的基本概念declval 的工作原理declval 的实际应用案例总结 前言 ​ 在现代C编程中&#xff0c;std::declval是一个非常有用的工具&#xff0c;它允许我们在不实例化对象的情况下使用其类型。这在模板元编程中尤其…

Git系列:git rm 的高级使用技巧

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

实用css整理

网页一键变灰 body{filter: grayscale(1); } 一般用于特殊时期&#xff0c;网页变灰&#xff0c;只需要给body标签添加这行样式代码。 一键换主题色 body {filter: hue-rotate(45deg);} 给body标签设置这个属性样式&#xff0c;改变角度看看效果吧。 设置字母大小写 p {t…

ESP32开发环境搭建Windows VSCode集成Espressif IDF插件开发环境搭建 IDF_V5.2.1

一、安装Visual Studio Code 下载地址&#xff1a;Download Visual Studio Code - Mac, Linux, Windows 打开上方链接&#xff0c;选择页面中的Windows版本&#xff0c;单击下载 将下载好的VSCodeUserSetup-x64-1.89.1.exe。单击右键&#xff0c;选择以管理员身份运行&#xf…

网络安全之BGP详解

BGP&#xff1b;边界网关协议 使用范围&#xff1b;BGP范围&#xff0c;在AS之间使用的协议。 协议的特点&#xff08;算法&#xff09;&#xff1a;路径矢量型&#xff0c;没有算法。 协议是否传递网络掩码&#xff1a;传递网络掩码&#xff0c;支持VLSM&#xff0c;CIDR …

【制作100个unity游戏之26】unity2d横版卷轴动作类游戏7(附带项目源码)

最终效果 系列导航 文章目录 最终效果系列导航前言血条 能量条UI配置画布绘制血条 能量条UI 头像框 延迟虚血源码参考完结 前言 欢迎来到【制作100个Unity游戏】系列&#xff01;本系列将引导您一步步学习如何使用Unity开发各种类型的游戏。在这第26篇中&#xff0c;我们将探索…

ESP8266 作为客户端 透传的实验

配置流程 1.配置WIFI模式 ATCWMODE1 配置成Station模式 2.完成配置后重启 ATRST 重启 3.连接路由器 ATCWJAP“777”,“123456lzg” 连接wifi 4.配置单路连接模式 ATCIPMUX0 5.开启透传模式 ATCIPMODE1 6.建立TCP连接 ATCIPSTART“TCP”,“172.20.10.10”,8081 //注意服务器和es…

鸿蒙OS开发:【一次开发,多端部署】(典型布局场景)

典型布局场景 虽然不同应用的页面千变万化&#xff0c;但对其进行拆分和分析&#xff0c;页面中的很多布局场景是相似的。本小节将介绍如何借助自适应布局、响应式布局以及常见的容器类组件&#xff0c;实现应用中的典型布局场景。 布局场景实现方案 开发前请熟悉鸿蒙开发指导…

[机器学习聚类算法实战-1] | Scikit-Learn工具包进阶指南:机器学习聚类算法之层次聚类、特征集聚、均值移位聚类、k-均值聚类实战分析

&#x1f3a9; 欢迎来到技术探索的奇幻世界&#x1f468;‍&#x1f4bb; &#x1f4dc; 个人主页&#xff1a;一伦明悦-CSDN博客 ✍&#x1f3fb; 作者简介&#xff1a; C软件开发、Python机器学习爱好者 &#x1f5e3;️ 互动与支持&#xff1a;&#x1f4ac;评论 &…