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

本文介绍了如何在Vue项目中使用Pinia进行状态管理,包括安装、持久化配置以及在登录功能中的应用。通过Axios接口获取数据,实现了登录验证,并利用Pinia保存用户信息。同时,文章详细展示了如何改造权限路由,动态加载路由组件,并结合本地存储确保刷新后数据不丢失。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在第四篇中我们学习了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(</