Appearance
❤pinia的使用
先来看看pinia的标志
1、Pinia简介
Pinia官网:https://pinia.vuejs.org/
Pinia起始于 2019 年 11 月左右的一次实验,目的是设计一个拥有组合式 API 的 Vue 状态管理库。
认识Pinia
Pinia是什么:
Pinia 是一个为 Vue 3 设计的状态管理库,vue3建议使用pinia代替vuex进行状态管理。
Pinia旨在提供简洁、强大且易于使用的 API,用于在 Vue 应用程序中管理状态。它提供了一种基于 Vue 3 的响应式系统的方式来管理全局和局部的状态,同时也与 TypeScript 很好地集成在一起。
vue2的都知道vuex状态管理,所谓状态管理,简单来说就是一个存储数据的地方,存放在Vuex中的数据在各个组件中都能访问到,它是Vue生态中重要的组成部分。
而pinia同理也是起到状态管理的作用,但是它又不完全同于vuex,相比有如下优点:
- Vue2和Vue3都支持,这让我们能很快上手
- pinia中只有state、getter、action,抛弃了Vuex中的Mutation,Vuex中mutation一直都不太受待见,pinia直接抛弃。
- pinia中action支持同步和异步
- 良好的Typescript支持,Vue3推荐使用TS来编写
- 无需再创建各个模块嵌套了,Vuex中如果数据过多,我们通常分模块来进行管理,而pinia中每个store都是独立的,互相不影响。
- 体积非常小,只有1KB左右。
- pinia支持插件来扩展自身功能。
- 支持服务端渲染。
🌂 理念上我觉得是对组合式API的扩展和衍生:
组合式API(Composable API)是一种设计和构建API的方式,思想就是让不同的API端的点和功能可以像积木一样组合,实现更复杂和定制化的功能。主要强调的其实是模块化、复用性、灵活性。
组合式API核心思想:
JS
1. **模块化设计**:API被设计成独立的、可复用的模块,每个模块提供特定的功能或资源。低耦合度。
2. **高内聚低耦合**:每个API模块分管不同单一性功能,高度内聚。
3. **灵活组合**:开发者可以根据需求自由组合模块构建出新功能。,这种组合可以是静态的(编写代码时确定)或者动态的(运行时确定)。
4. **标准接口**:定义一些标准化的接口和协议确保模块顺利组合。这些标准化接口使模块之间不需要了解对方的内部实现细节。
5. **扩展性和可维护性**:由于组合式API的模块化设计,添加新功能或修改现有功能风险更小。提高了系统的可扩展性和可维护性。
Pinia特点
- 基于 Vue 3 的响应式系统:Pinia 利用了 Vue 3 的响应式系统,使得在应用中管理状态变得非常直观和高效。
- 使用 Vue Composition API:Pinia 鼓励开发者使用 Vue 3 的 Composition API 来定义状态和逻辑,这使得代码更清晰和可维护。
- 零依赖:Pinia 是一个轻量级的库,不依赖于其他状态管理库或类似的工具,使得它具有很高的灵活性。
- 支持 TypeScript:Pinia 提供了对 TypeScript 的内置支持,包括类型推导、接口定义和类型安全等功能,这使得使用 TypeScript 进行开发变得更加顺畅。
- 插件系统:Pinia 提供了插件系统,使得开发者可以根据项目的需要进行功能扩展和定制,例如增加中间件、开发工具等。
2、安装使用
安装
js
yarn add pinia
3、Vue3使用pinia
(1)store案例
创建一个 store,例如 counterStore
js
// src/stores/counterStore.js
import { defineStore } from 'pinia';
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0,
}),
actions: {
increment() {
this.count++;
},
decrement() {
this.count--;
},
},
});
在需要使用 store 的组件中导入并使用它
js
<template>
<div>
<p>Count: {{ counterStore.count }}</p>
<button @click="counterStore.increment()">Increment</button>
<button @click="counterStore.decrement()">Decrement</button>
</div>
</template>
<script>
import { useCounterStore } from '@/stores/counterStore';
export default {
setup() {
const counterStore = useCounterStore();
return { counterStore };
},
};
</script>
到这里我们就可以先去搭建我们的注册登录等模块了,等搭建好了再来进行我们的
(2)使用js-cookie
接下来我们就在开源项目Nexus之中把这部分的pinia使用尝试一下,并且利用pinia实现我们的登录部分
首先我们获取一下用户的权限,这部分我们需要用到一个东西,这个东西就是js-cookie,拿来存储我们的cookie信息
👉 在 utils=> auth.js ,然后我们使用这个部分把token都放入Cookies部分
js
import Cookies from 'js-cookie'
const TokenKey = 'Admin-Token'
export function getToken() {
return Cookies.get(TokenKey)
}
export function setToken(token) {
return Cookies.set(TokenKey, token)
}
export function removeToken() {
return Cookies.remove(TokenKey)
}
(3)项目使用
👉 新建src = > store => index.js
这里主要导出我们的store
js
const store = createPinia()
export default store
👉 新建store=> modules=> user.js
在store之中我们简单封装一下user的信息,用来存储关于用户的token信息,并且简单的封装一下我们的用户登录信息
这里我们主要是对于用户的账号密码进行传递,然后传递我们的token,默认带一张我们默认的头像部分
js
import { login, logout, getInfo } from '@/api/login'
import { getToken, setToken, removeToken } from '@/utils/auth'
import defAva from '@/assets/images/defaulte_avatar.png'
const useUserStore = defineStore(
'user',
{
state: () => ({
token: getToken(),
name: '',
avatar: '',
roles: [],
permissions: []
}),
actions: {
// 登录
login(userInfo) {
const username = userInfo.username.trim()
const password = userInfo.password
const code = userInfo.code
const uuid = userInfo.uuid
return new Promise((resolve, reject) => {
login(username, password, code, uuid).then(res => {
setToken(res.token)
this.token = res.token
resolve()
}).catch(error => {
reject(error)
})
})
},
// 获取用户信息
getInfo() {
return new Promise((resolve, reject) => {
getInfo().then(res => {
const user = res.user
const avatar = (user.avatar == "" || user.avatar == null) ? defAva : import.meta.env.VITE_APP_BASE_API + user.avatar;
if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组
this.roles = res.roles
this.permissions = res.permissions
} else {
this.roles = ['ROLE_DEFAULT']
}
this.name = user.userName
this.avatar = avatar;
resolve(res)
}).catch(error => {
reject(error)
})
})
},
// 退出系统
logOut() {
return new Promise((resolve, reject) => {
logout(this.token).then(() => {
this.token = ''
this.roles = []
this.permissions = []
removeToken()
resolve()
}).catch(error => {
reject(error)
})
})
}
}
})
export default useUserStore
👉 使用我们的用户信息
js
<script setup>
import useUserStore from '@/store/modules/user'
const userStore = useUserStore()
console.log(userStore,'userStore信息');
</script>
测试一下,效果如下,可以继续完善了
接下来完善我们的登录部分
js
import useUserStore from '@/store/modules/user'
const userStore = useUserStore()
// 处理表单提交的函数
const handleSubmit = async (event) => {
event.preventDefault();
// 在实际应用中,这里可以发送注册请求到服务器进行用户注册
// 这里简单地假设密码和确认密码相同才能注册成功
if (form.value.username === '' || form.value.password === '') {
ElMessage.error('用户名和密码不能为空');
return;
}else{
console.log(form.value, 'form.value');
try {
const res:any = await login(form.value);
if(res.code==200){
ElMessage.success(res.message);
// 调用action的登录方法
userStore.login(loginForm.value).then(() => {
const query = route.query;
const otherQueryParams = Object.keys(query).reduce((acc, cur) => {
if (cur !== "redirect") {
acc[cur] = query[cur];
}
return acc;
}, {});
router.push({ path: redirect.value || "/", query: otherQueryParams });
}).catch(() => {
loading.value = false;
});
}else{
ElMessage.error(res.message);
}
} catch (error) {
// console.log('获取数据详情失败,请重试!',error);
} finally {
// console.log('完!');
}
}
return;
};
这里看看我们的登录接口部分
js
import request from '@/utils/request.js'
// 登录方法
export function login(username, password, code, uuid) {
const data = {
username,
password,
code,
uuid
}
return request({
url: '/api/login',
headers: {
isToken: false,
repeatSubmit: false
},
method: 'post',
data: data
})
}
尝试调用一下看看
这里记得完善一下我们token部分
js
import { getToken } from '@/utils/auth'
权限部分记得更改一下
if (whiteList.indexOf(to.path) !== -1||getToken()) {
console.log('白名单或者token账号进入1!');
next();
}
点击登录ok!