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

news2024/11/18 19:57:20

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

不用从头训练,通过知识融合创建强大的统一模型

在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;大型语言模型&#xff08;LLMs&#xff09;的开发和训练是一个复杂且成本高昂的过程。数据需求是一个主要问题&#xff0c;因为训练这些模型需要大量的标注数据来保证其准确性和泛化能力&#xff1b;计算资源也是一个…

关于基础的流量分析(1)

1.对于流量分析基本认识 1&#xff09;简介&#xff1a;网络流量分析是指捕捉网络中流动的数据包&#xff0c;并通过查看包内部数据以及进行相关的协议、流量分析、统计等来发现网络运行过程中出现的问题。 2&#xff09;在我们平时的考核和CTF比赛中&#xff0c;基本每次都有…

【Linux取经路】进程通信——共享内存

文章目录 一、直接原理1.1 共享内存的的申请1.2 共享内存的释放 二、代码演示2.1 shmget2.1.1 详谈key——ftok 2.2 创建共享内存样例代码2.3 获取共享内存——进一步封装2.4 共享内存挂接——shmat2.5 共享内存去关联——shmdt2.6 释放共享内存——shmctl2.7 开始通信2.7.1 pr…

安全攻防基础

一、安全是什么&#xff1f;就是三个基础原则 安全就是保护数据 1. 机密性 对未授权的主体不可见 开发人员不能拥有敏感数据的访问权限 密钥要复杂 显示器伤的数据被别有用心的人窥探 2. 完整性 没授权的人不可修改数据 3. 可用性 被授权的主体可读 二、如何解决安全问题…

Rust面试宝典第14题:旋转数组

题目 给定一个数组&#xff0c;将数组中的元素向右移动k个位置&#xff0c;其中k是非负数。要求如下&#xff1a; &#xff08;1&#xff09;尽可能想出更多的解决方案&#xff0c;至少有三种不同的方法可以解决这个问题。 &#xff08;2&#xff09;使用时间复杂度为O(n)和空间…

微服务远程调用 RestTemplate

Spring给我们提供了一个RestTemplate的API&#xff0c;可以方便的实现Http请求的发送。 同步客户端执行HTTP请求&#xff0c;在底层HTTP客户端库(如JDK HttpURLConnection、Apache HttpComponents等)上公开一个简单的模板方法API。RestTemplate通过HTTP方法为常见场景提供了模…

VisualStudio2022的使用

Visual Studio 2022 的安装、卸载和使用方法详解 一、安装Visual Studio 2022 1. 下载Visual Studio 2022 要安装Visual Studio 2022&#xff0c;需要先下载安装程序。可以从微软的官方网站&#xff08;Visual Studio下载页面&#xff09;下载免费的社区版&#xff08;Commun…

非平稳信号的傅里叶变换与短时傅里叶变换

一、仿真一个非平稳的时间序列。 N 10000; t 0:N-1; z1 4.2*sin(2*pi/20.*t5); z2 2.2*sin(2*pi/100.*(10.001*t).*t8); w1 randn(length(t),1); yz1z2w1; figure;plot(y,LineWidth,1.5);grid on; ylabel(Signal); xlabel(Time); 二、傅里叶变换&#xff08;FFT&#xff…

网创教程:WordPress插件网创自动采集并发布

网创教程&#xff1a;WordPress插件网创自动采集并发布 使用插件注意事项&#xff1a; 如果遇到404错误&#xff0c;请先检查并调整网站的伪静态设置&#xff0c;这是最常见的问题。需要定制化服务&#xff0c;请随时联系我。 本次更新内容 我们进行了多项更新和优化&#x…

保护共享资源的方法(互斥锁)

我最近开了几个专栏&#xff0c;诚信互三&#xff01; > |||《算法专栏》&#xff1a;&#xff1a;刷题教程来自网站《代码随想录》。||| > |||《C专栏》&#xff1a;&#xff1a;记录我学习C的经历&#xff0c;看完你一定会有收获。||| > |||《Linux专栏》&#xff1…

一个基于vue、nuxt.js的网盘搜索项目,且持续开源和维护;目的实现人人都可以拥有自己的网盘搜索网站;

一个基于vue、nuxt.js的网盘搜索项目&#xff0c;且持续开源和维护&#xff1b;目的实现人人都可以拥有自己的网盘搜索网站&#xff1b; &#x1f310;Github地址 https://github.com/unilei/aipan-netdisk-search &#x1f310;在线体验 https://so.aicompasspro.com/

我在去哪儿薅到了5块钱火车票代金券,速薅

哈哈&#xff0c;亲爱的薅羊毛小伙伴们&#xff01; 刚刚在去哪儿大佬那儿发现了一个超级薅羊毛福利&#xff01;我只花了短短两分钟&#xff0c;就搞到了一张5块钱火车票代金券&#xff0c;简直是天上掉馅饼的节奏啊&#xff01; 话不多说&#xff0c;薅羊毛的姿势给你们摆好…

202473读书笔记|《但愿呼我的名为旅人:松尾芭蕉俳句300》——围炉夜话,身顿心安,愿每个人都能在爱里自由驰骋

202473读书笔记|《但愿呼我的名为旅人&#xff1a;松尾芭蕉俳句300》——围炉夜话&#xff0c;身顿心安&#xff0c;愿每个人都能在爱里自由驰骋 &#x1f60d;&#x1f60d;&#x1f929;&#x1f929; 译者序正文二正文三正文四正文五正文六正文七 《但愿呼我的名为旅人&…

【动手学强化学习】第 6 章 Dyna-Q 算法知识点总结

【动手学强化学习】第 6 章 Dyna-Q 算法知识点总结 本章知识点基于模型的强化学习与无模型的强化学习方法简介无模型的强化学习方法基于模型的强化学习方法 强化学习算法的评价指标Dyna-Q算法Dyna-Q 算法的具体流程Dyna-Q 代码实践 本章知识点 基于模型的强化学习与无模型的强…

前端 CSS 经典:好看的标题动画

前言&#xff1a;好看的标题动画实现。 效果&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><…

syncthing文件夹同步与版本管理

1 前言 syncthing可以用来同步文件夹里的所有文件&#xff0c;并且有不错的版本管理&#xff0c;基本每次更改文件&#xff0c;20-40秒就被扫描到了&#xff0c;非常丝滑&#xff1b;这次以此来同步obsidian的插件和文件&#xff0c;达到多端同步&#xff1b; 我家里有一台台…

自定义横向思维导图,横向组织架构图,横向树图。可以自定义节点颜色,样式,还可以导出为图片

最近公司设计要求根据目录结构&#xff0c;横向展示。所以做了一个横向的思维导图&#xff0c;横向的树结构&#xff0c;横向的组织架构图&#xff0c;可以自定义节点颜色&#xff0c;样式&#xff0c;还可以导出为图片 话不多说&#xff0c;直接上图片&#xff0c;这个就是一…

Django自定义命令

Django自定义命令 我们知道&#xff0c;Django内部内置了很多命令&#xff0c;例如 python manage.py runserver python manage.py makemigrations python manage.py migrate我们可以在python控制台中查看所有命令 我们也可以自定义命令&#xff0c;让python manage.py执行…

如何使用甘特图来做任务管理?zz-plan甘特图的实践指南

在项目管理和任务调度中&#xff0c;甘特图是一种非常实用的工具&#xff0c;它可以帮助团队成员清晰地规划、执行和跟踪项目进度。然而&#xff0c;如何有效利用甘特图进行任务管理&#xff0c;对于许多团队来说仍然是一个挑战。本文将结合 zz-plan https://zz-plan.com/ 甘特…

彻底搞懂JavaScript原型和原型链

基于原型编程 在面向对象的编程语言中&#xff0c;类和对象的关系是铸模和铸件的关系&#xff0c;对象总是从类创建而来&#xff0c;比如Java中&#xff0c;必须先创建类再基于类实例化对象。 而在基于原型编程的思想中&#xff0c;类并不是必须的&#xff0c;对象都是通过克隆…