【 Vue3 + Vite + setup语法糖 + Pinia + VueRouter + Element Plus 第五篇】【完结篇附源码】

news2024/11/30 4:59:48

在第四篇中我们学习了mixin 公共方法封装, VueRouter 的使用以及配置权限路由,本期我们将讲述 Pinia,并使用 PiniaAxios接口数据完成登录功能以权限路由改造

本期需要掌握的知识如下:

  • Pinia 在项目中的使用及 持久化
  • 使用 PiniaAxios 完成 登录 功能
  • 使用 Pinia 完成对权限路由改造

1. Pinia 安装及使用

$ npm install pinia 安装pinia
$ npm i pinia-plugin-persist --save 安装pinia 持久化插件

main.js 引入 pinia


import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router'

// pinia 部分
import { createPinia } from 'pinia';
import piniaPersist from 'pinia-plugin-persist'
const pinia = createPinia()
pinia.use(piniaPersist)

import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'

import 'nprogress/nprogress.css'

import axios from 'axios'
import VueAxios from 'vue-axios'


createApp(App).use(router).use(pinia).use(ElementPlus, { locale: zhCn }).use(VueAxios, axios).mount('#app')

scr目录下新建 store目录,并在该目录下新建 index.js

在这里插入图片描述


import { defineStore } from "pinia"
/**
 * 这个 第一个参数main,也称为 id,是必要的,Pinia 使用它来将 store 连接到 devtools。 
 * 将返回的函数命名为use...(更好的语义化) 是跨可组合项的约定,以使其符合你的使用习惯。
*/
export const useStore = defineStore('user', {

  state() {
    return {
      current_userInfo: {
        id: '',
        username: '',
        password: '',
        isOpen: '',
        apiToken: ''
      },
      animationRoute: [],
    }
  },
  /**
 * 用来封装计算属性 有缓存功能  类似于computed
   */
  getters: {
    getNum(state) {
      return `我是一个计数器${state.count}`
    }

    //或者不使用state传递参数直接使用this
    //getNum(){
    //    return `我是一个计数器${this.count}`
    // }

  },
  /**
 * 编辑业务逻辑  类似于methods
   */
  actions: {
    SAVE_USER_MESSAGE(val) {
      this.current_userInfo = val
    },
    SAVE_ANIMATION_ROUTER(val) {
      this.animationRoute = val
    }
  },
  persist: {
    enabled: true, // 开启数据缓存
    strategies: [
      {
        key: 'user',//存储key值
        storage: localStorage, // 默认是sessionStorage
      }
    ],
  }
})

Pinia 解释说明:

  • state 相当于 vuex 中的 data
  • getters 等同于 vuexgetters
  • actions 相当于 vuex 中的 methods、actions 的和
  • persist 持久化数据配置,防止 Pinia 刷新后数据丢失
  • Pinia 中是可以使用 this 关键字

2.登录功能实现

1.创建用户JSON文件和动态路由文件

在这里插入图片描述·

// user.json
{
  "data": [
    {
      "id": 1,
      "username": "admin",
      "password": "123456",
      "isOpen": "true",
      "apiToken": "token_assets"
    }
  ]
}
// router.json
{
  "data": [
    {
      "name": "admin",
      "path": "/admin",
      "hidden": false,
      "meta": {
        "title": "首页"
      },
      "children": [
        {
          "name": "admin/user",
          "path": "user",
          "hidden": false,
          "meta": {
            "title": "用户管理"
          }
        },
        {
          "name": "admin/role",
          "path": "role",
          "hidden": false,
          "meta": {
            "title": "角色管理"
          }
        }
      ]
    }
  ],
  "code": 200
}

2.创建 api 请求接口

在这里插入图片描述

// login.js
import request from '@/utils/request'
export const handleLogin = () => {
  return request({
    url: 'user.json',
    method: 'GET'
  })
}
// common.js
import request from '@/utils/request'

// 获取动态路由接口
export const animationRoute = () =>{
  return request({
    url:'router.json',
    method:'GET'
  })
}

3.页面搭建及接口请求

目录结构如下

  • index.vue 为父组件
  • components 目录下的 loginForm.vue 为子组件,包括 Form 表单

这样做的原因是:

  1. 减少每个页面的代码,使代码更简洁、方便后期维护
  2. 复习 组件传值

在这里插入图片描述

index.vue 代码

<template>
  <div class="login">
    <loginForm @LoginEmit="LoginEmit" />
  </div>
</template>
import { defineComponent, onMounted, ref } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
// 引入 pinia 方法
import { useStore } from '@/store/index.js'
// 引入 登录 api
import { handleLogin } from '@/api/login.js'
// 引入 权限路由 api
import { animationRoute } from '@/api/common.js'
// 引入 登录表单子组件
import loginForm from './components/loginForm.vue'

// 注册组件
const Component = defineComponent({
  loginForm
})


/**
 * @type data
 * @description 所有数据都在此体现
 * **/

const Router = useRouter()
const store = useStore()

/**
* @type methods
* @description 所有方法、事件都在此层中体现
* **/

// 登录按钮方法 由子组件触发并携带参数
const LoginEmit = async form => {
  const { username, password } = form
  let res = await handleLogin()
  // 以下三行代码是判断登录账号密码是否正确
  let currentUser = res.data.filter(item => { return item.username === username })
  if (currentUser.length < 1) return ElMessage.error('用户不存在')
  if (currentUser[0].password !== password) return ElMessage.error('密码错误')
  // 确保登录成功后 调用 Pinia 方法存储用户信息
  store.SAVE_USER_MESSAGE(currentUser[0])
  // 获取 权限路由
  let routerList = await animationRoute(username)
  // 调用 Pinia 存储权限路由方法 将路由信息存储到 store中
  store.SAVE_ANIMATION_ROUTER([...routerList.data])
  // 跳转到 首页
  Router.push('/home')
}

表单组件

<template>
  <div class="login-form">
    <div class="title">用户登录</div>
    <div class="login_content">
      <el-form ref="ruleLogin" :model="loginForm" :rules="rules">
        <el-form-item label="账号:" prop="username">
          <el-input v-model="loginForm.username" autocomplete="off" placeholder="请输入账号" />
        </el-form-item>
        <el-form-item label="密码:" prop="password">
          <el-input v-model="loginForm.password" type="password" autocomplete="off" placeholder="请输入密码" />
        </el-form-item>
      </el-form>
      <el-button type="primary" @click="handleLogin">登录</el-button>
    </div>
  </div>
</template>
import { ref } from 'vue'

/**
 * @type data
 * @description 所有数据都在此体现
 * **/

const loginForm = ref({
  username: '',
  password: ''
})
const ruleLogin = ref(null)
const rules = {
  username: { required: true, message: "账号不可为空", trigger: "blur" },
  password: { required: true, message: "密码不可为空", trigger: "blur" },
}


/**
* @type methods
* @description 所有方法、事件都在此层中体现
* **/

const emit = defineEmits(['LoginEmit'])

// 登录按钮点击事件
const handleLogin = async () => {
  try {
  	// 先判断表单校验是否通过,再去触发 父组件方法并传参
    await ruleLogin.value.validate()
    // 触发父组件登录方法
    emit('LoginEmit', loginForm.value)
  } catch (err) {
  }
}

4.权限路由改造

import { createRouter, createWebHistory } from 'vue-router'
import { homeRoutes } from './modules/home'
import { loginRoutes } from './modules/login'
import { getlocalstroage, clearSession, clearLocal, showNprogress, hideNprogress } from '@/mixin'
import { useStore } from '@/store'
import { storeToRefs } from "pinia"

// 首先把你需要动态路由的组件地址全部获取
let modules = import.meta.glob('../views/**/*.vue')
let flag = true

const router = createRouter({
  history: createWebHistory(),
  routes: [...loginRoutes, ...homeRoutes]
})

router.beforeEach((to, from, next) => {
  showNprogress()
  if (to.meta.title) {
    document.title = to.meta.title
  }

  const { animationRoute } = storeToRefs(useStore())
  addDynamicRoute(animationRoute.value)
  if (animationRoute.value.length > 0) {
    if (flag) {
      const NotFound = { path: '/:pathMatch(.*)*', redirect: '/404' }
      router.addRoute(NotFound)
      next({ ...to, replace: true })
      router.options.routes.push(JSON.parse(JSON.stringify(...animationRoute.value),NotFound))
      flag = false
    }
  }

  if (to.path != '/login') {
    let apiToken = getlocalstroage('user') ? JSON.parse(getlocalstroage('user'))?.current_userInfo?.apiToken : null
    if (!apiToken) {
      clearSession()
      clearLocal()
      next('/login')
    }
  }
  next()
})

router.afterEach(() => {
  hideNprogress()
})

// 添加动态路由,parent默认为home是首页最外层的路由name名
const addDynamicRoute = (useroute, parent) => {
  for (let i = 0; i < useroute.length; i++) {
    if (useroute[i].children && useroute[i].children.length > 0) {
      router.addRoute({ name: useroute[i].name, path: useroute[i].path, component: modules[`../views/${useroute[i].name}/index.vue`], meta: { title: useroute[i].meta.title }, hidden: useroute[i].hidden })
      // 递归添加动态路由
      addDynamicRoute(useroute[i].children, useroute[i].name);
    } else {
      router.addRoute(parent, { path: useroute[i].path, component: modules[`../views/${useroute[i].name}/index.vue`], meta: { title: useroute[i].meta.title }, hidden: useroute[i].hidden })
    }
  }
};

export default router

项目源码地址

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

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

相关文章

VIMA: General Robot Manipulation with Multimodal Prompts

Paper name VIMA: General Robot Manipulation with Multimodal Prompts Paper Reading Note URL: https://arxiv.org/pdf/2210.03094.pdf Project URL: https://vimalabs.github.io/ ICLR review URL: https://openreview.net/forum?idhzjQWjPC04A TL;DR ICLR 2023 在投…

动态 json 转化序表

【问题】Hi,I have a problem very similar tohttp://community.jaspersoft.com/questions/844023/need-help-looping-throu…,but I can’t just change the json file as done by the person asking that question.Any help would be greatly appreciated.----I am trying to…

深入学习IO多路复用select/poll/epoll实现原理

这里写自定义目录标题参考概述1. Linux 怎样处理网络请求1.1 阻塞 IO1.2 非阻塞 IO1.3 IO 多路复用2. 详解 select、poll、epoll 实现原理2.1 select 实现原理2.2 poll 实现原理3. 总结参考 深入学习IO多路复用select/poll/epoll实现原理 概述 Linux 服务器处理网络请求有三…

Java基础算法每日5道详解(4)

101. Symmetric Tree 对称树 Given the root of a binary tree, check whether it is a mirror of itself (i.e., symmetric around its center). Example 1: Input: root [1,2,2,3,4,4,3] Output: trueExample 2: Input: root [1,2,2,null,3,null,3] Output: falseleetco…

Linux常用命令——nl命令

在线Linux命令查询工具(http://www.lzltool.com/LinuxCommand) nl 在Linux系统中计算文件内容行号 补充说明 nl命令读取 file 参数&#xff08;缺省情况下标准输入&#xff09;&#xff0c;计算输入中的行号&#xff0c;将计算过的行号写入标准输出。在输出中&#xff0c;n…

牛啊~ 长这么大还是头一次见24W字的SpringBoot从入门到实战文档

牛啊&#xff01;长这么大还是头一次见24W字的SpringBoot从入门到实战文档&#xff01; 不服还真不行&#xff0c;因为这份文档包含的内容是又全又新&#xff0c;而且还特别高深&#xff0c;从入门到实战的内容全都有&#xff01;&#xff01; 继续往下看&#xff1a; 本文档从…

EMQ设定ACL规则来控制客户端对主题的订阅权限

实现原理&#xff1a;EMQ可以通过制订ACL规则&#xff0c;校验客户端每个发布(Publish)/订阅(Subscribe) 的权限 本次采用的是EMQ Mnesia ACL。使用 EMQ X 内置的 Mnesia 数据库存储 ACL 规则 测试过程&#xff1a; 1本次实验环境&#xff0c;1个服务端&#xff08;发布1个主…

NumPy一维数组、二维数组与Pandas的Series、DataFrame行列结构和横纵方向的统一说明

最近在这个问题上耽误了一些时间&#xff0c;原因是之前个人理解上出了一些偏差&#xff0c;又受到错误文章的误导&#xff0c;把这个问题搞复杂了&#xff0c;现在统一梳理一下。在展开之前&#xff0c;先明确说明的是&#xff1a;NumPy的二维数组与Pandas的DataFrame&#xf…

7、Javaweb_tomcatservlet

web相关概念 1. 软件架构 1. C/S&#xff1a;客户端/服务器端 2. B/S&#xff1a;浏览器/服务器端 2. 资源分类 1. 静态资源&#xff1a;所有用户访问后&#xff0c;得到的结果都是一样的&#xff0c;称为静态资源.静态资源可以直接被浏览器解析 * 如&am…

2023年最全盘点 | 16款跨平台应用程序开发框架

近年来小程序技术被微信及其生态应用带的如火如荼的&#xff0c;开发者的世界里&#xff0c;小程序的技术非常受关注&#xff0c;特别在流量承接及跨端开发方面&#xff0c;均受到不同规模的企业关注及积极实践。 2023年&#xff0c;小程序依然很火&#xff0c;但却有了一些不…

元宇宙产业委MCC|于佳宁:加密资产摆脱不了周期性规律

2022年&#xff0c;加密行业面临寒冬&#xff0c;加密货币市场总价值大量缩水&#xff0c;降逾1.45万亿美元&#xff0c;期间多家加密公司接连倒塌&#xff0c;引发市场连锁效应。 加密货币总市值降逾1.45万亿美元 根据CoinMarketCap数据&#xff0c;加密货币总市值(Total Cry…

【服务器数据恢复】某品牌DS系列服务器RAID5数据恢复案例

服务器数据恢复环境&#xff1a; 某单位一台某品牌DS系列服务器连接4个扩展柜&#xff1b; 50块磁盘组建两组RAID5&#xff0c;其中一组由27块磁盘组建的RAID5存放的是Oracle数据库文件&#xff1b; 上层一共划分11个卷。 服务器故障&#xff1a; 磁盘故障导致存放Oracle数据库…

JavaScript类和对象

1、面向对象与面向过程 1.1 面向过程编辑POP(Process-oriented programming) 面向过程就是分析出解决问题所需要的步骤&#xff0c;然后用函数把这些步骤一步一步实现&#xff0c;使用的时候再一个一个的依次调用就可以了。面向过程&#xff0c;就是按照我们分析好的步骤&…

20张图带你了解JVM运行时数据区

运行时数据区总览 内存是非常重要的系统资源&#xff0c;是硬盘和CPU的中间仓库及桥梁&#xff0c;承载着操作系统和应用程序的实时运行。JVM内存布局规定了Java在运行过程中内存申请、分配、管理的策略&#xff0c;保证了JVM的高效稳定运行。不同的JVM对于内存的划分方式和管…

C 程序设计教程(11)—— 字符数据的输入与输出

C 程序设计教程&#xff08;11&#xff09;—— 字符数据的输入与输出 该专栏主要介绍 C 语言的基本语法&#xff0c;作为《程序设计语言》课程的课件与参考资料&#xff0c;用于《程序设计语言》课程的教学&#xff0c;供入门级用户阅读。 目录C 程序设计教程&#xff08;11&…

【2004NOIP普及组】T2.花生采摘 试题解析

【2004NOIP普及组】T2.花生采摘 试题解析 时间限制: 1000 ms 内存限制: 65536 KB 【题目描述】 鲁宾逊先生有一只宠物猴,名叫多多。这天,他们两个正沿着乡间小路散步,突然发现路边的告示牌上贴着一张小小的纸条:“欢迎免费品尝我种的花生!——熊字”。 鲁宾逊先生…

Android---Chip

Chip Chip 代表一个小块中的复杂实体&#xff0c;如联系人。它是一个圆形按钮&#xff0c;由一个标签&#xff0c;一个可选的芯片图标和一个可选的关闭图标组成。如果 Chip 可检查&#xff0c;则可以点击或切换Chip 。 style"style/Widget.MaterialComponents.Chip.Action…

疫情在家搭建的简单易学的SLAM建图机器人

1 简介 Easy_mqOS 是我仿照ROS 搭建的基于MQTT的简易机器人分布式开发框架,是一种轻量级并且十分容易上手的框架&#xff0c;支持多个节点的主题的订阅和单topic发布,节点之间独立、解耦合。没有复杂的文件配置&#xff0c;一定的make编程基础&#xff0c;像正常启动服务一样&a…

Redis未授权访问漏洞(四)SSH key免密登录

前言 系列文章 Redis未授权访问漏洞(一)先导篇 Redis未授权访问漏洞(二)Webshell提权篇 Redis未授权访问漏洞(三)Redis写入反弹连接定时任务 SSH key免密登录 实战实验 环境准备 实验前我们先来复习一遍ssh-key免密登录的流程 攻击机&#xff1a; Centos7 IP:192.168.142.44 靶…

局部变量的特点以及成员变量的区别

1. 概念在上面的章节中&#xff0c;其实已经跟大家介绍了局部变量的概念。即&#xff1a;局部变量是在定义形参、方法或代码块内部的变量&#xff0c;该变量只在当前方法、代码块中有效。2. 特点局部变量具有如下特点&#xff1a;● 局部变量声明在方法、构造方法或者代码块、形…