pinia组件
状态管理组件, pinia 比vuex 更轻量级、更方便, pinia也是官方推荐的..
# pinia的基本使用
pinia实现了 所有组件之间可以在内存方面共享数据
我们可以把pinia想象成一个代理.. 该代理可以存储一系列的变量..(是存储在内存中的)
所有的组件都从该代理中取变量, 修改变量.
当某个组件修改了变量, 使用到该变量的所有组件都会自动同步修改后的变量的值..
一旦刷新页面, pinia就会重新初始化, 数据全部回到初始值, 相当于没有修改过, 会造成数据的丢失..
因而 pinia 绝对会与 本地存储(localStorage、cookie) 搭配食用. 以本地存储的持久化来解决刷新后数据丢失的问题.
(详看后面小节的 登陆示例)pinia由三个部分组成: state状态值、getter计算属性、action定义函数
state状态值 -- 就理解成 所有组件都可以取的全局变量 v1=123 v2={id:1,name:'wpq',token:'xxxx'}
getter计算属性
-- 可理解成 计算属性对原始的变量进行处理
很多组件取到v2变量后,都要进一步取 v2.id v2.token -- 计算属性可以将这个重复的操作归纳到此处
action定义函数 -- 通常用于 取state中的数据进行业务逻辑处理
1
2
3
4
5
2
3
4
5
菜单1修改了pinia中的变量,菜单2以及根组件App.vue中使用了该变量,会同步进行改变!
但注意,一旦刷新后,pinia中的数据就会回归初始值!!
-- 综上: 当前组件、当前组件的父组件、其他组件 中共享状态的数据!!
- 菜单1 > M1组件
- 菜单2 > M2组件
- 账户余额 > 根组件
1
2
3
4
5
6
2
3
4
5
6
关键代码如下:
# pinia登陆
该示例是在 vue-router章节的 导航守卫小节 的登陆登出 的示例上 进行的补充修改..
先回顾下, 示例的需求和所用到的知识点..
现已经实现
1.登陆不含顶部,是单独的页面 - router路由嵌套结构
2.登陆成功,跳转首页;退出登陆,跳转登陆页面 - 编程式导航/即js跳转
3.未登录不能访问后台,应自动重定向登陆页面 - 路由守卫/即中间件
具体来说
1.> 登陆组件应是一级路由,后台组件也是一个一级路由,一系列菜单组件嵌套到后台组件中
2.> 登陆时,拿到表单数据,向后端发送请求进行验证,验证成功,获得json数据,里面包含用户信息以及token
将其保存到本地缓存localStorage中,router.push跳转首页
> 退出登陆时,清除本地缓存localStorage,router.push跳转登陆页
3.> 访问登录页面,该页面不需要登录就可以直接去查看;
通过localStorage检查用户登录状态(登录成功,继续往后走next();未登录,重定向登录页面)
To do:接下来需实现
1.登陆成功后,退出登陆的按钮左侧应显示当前登陆用户的名字. -- pinia
2.待续: 补充,任何组件都可以取到pinia中的token登陆凭证,然后通过axios携带token向后端发送请求!!
思考一个问题:
Q: 是否可以仅用localstorage来实现接下来需实现的需求,而不用pinia.
A: - 对于不变的数据确实可以,但是当两个组件共用一个数据源(对象或数组)时.
如果其中的一个组件改变了该数据源,希望另一个组件响应该变化时,pinia才是首选,loaclstorage是无法做到的.
- 而且在pinia中,对于数据的修改可以先做一系列的验证! 有解藕的功效!!
- pinia中的数据在内存里,loaclstorage的数据在本地文件里,从内存中读取的速度更快.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
关键 新增和 改动的代码如下:
新增 - src/stores/counter.js
import {ref, computed} from 'vue'
import {defineStore} from 'pinia'
export const userInfoStore = defineStore('userInfo', () => {
// 基于localStorage
// state部分
// userString的值要么是null 要么是'{id: 1, name:"123e", token: "xxyakaxlod123d"}'
const userString = ref(localStorage.getItem("info"))
const userDict = computed(() => userString.value ? JSON.parse(userString.value) : null)
const userId = computed(() => userDict.value ? userDict.value.id : null)
const userName = computed(() => userDict.value ? userDict.value.name : null)
const userToken = computed(() => userDict.value ? userDict.value.token : null)
function doLogin(info) {
// 基于localStorage
localStorage.setItem("info", JSON.stringify(info));
// ★★★ 注意:若不写这行代码,登陆成功后,压根跳转不过去
// 因为程序一开始就读取了state部分的变量,页面不刷新的话,是不会重新读取state的!! 即刷新后,state中才会有值
userString.value = JSON.stringify(info)
}
function doLogout() {
// 基于localStorage
localStorage.clear()
userString.value = null
}
// return啥,外部才能用啥,不使用的不给外部暴露,像userDict就没有暴露给外部.
return {userId, userName, userToken, doLogin, doLogout}
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
改动 - src/router/index.js
import {createRouter, createWebHistory} from 'vue-router'
import {userInfoStore} from "@/stores/counter.js";
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/login',
name: 'login',
component: () => import('../views/LoginView.vue'),
},
{
path: '/',
name: 'admin',
component: () => import('../views/AdminView.vue'),
children: [
{
path: '',
name: 'home',
component: () => import('../views/HomeView.vue'),
},
{
path: '/about',
name: 'about',
component: () => import('../views/AboutView.vue'),
},
]
},
],
})
router.beforeEach((to, from, next) => {
//1.白名单 eg:访问登录页面,该页面不需要登录就可以直接去查看
if (to.name === "login" || to.name === "Index") {
next()
return
}
//2.检查用户登录状态(登录成功,继续往后走next(); 未登录,跳转到登录页面)
/* 原先代码
let username = localStorage.getItem("name")
if (username) {
next()
} else{
next({name: "login"})
}
*/
const store = userInfoStore()
if (store.userId) {
next()
} else {
next({name: "login"})
}
})
export default router
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
改动 - src/views/LoginView.vue
<template>
<div>
<input type="text" placeholder="用户名" v-model="username">
<input type="text" placeholder="密码" v-model="pwd">
<input type="button" @click="doLogin" value="登陆">
</div>
</template>
<script setup>
import {ref} from "vue";
import {useRouter} from "vue-router";
import {userInfoStore} from "@/stores/counter.js";
const router = useRouter()
const store = userInfoStore()
const username = ref("")
const pwd = ref("")
function doLogin() {
// 1.获取数据 Todo-携带数据向后端发送请求进行验证
/* 原先代码
console.log(username.value, pwd.value)
localStorage.setItem("name", username.value)
*/
let info = {id: 1, name: username.value, token: "xxyakaxlod123d"}
store.doLogin(info)
// 3.跳转到首页
router.push({name: "home"})
}
</script>
<style scoped></style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
改动 - src/views/AdminView.vue
<template>
<RouterLink to="/">首页</RouterLink>
|
<RouterLink to="/about">关于</RouterLink>
--
{{ store.userName}}
<span @click="doLogout" style="cursor: pointer;">退出</span>
<RouterView/>
</template>
<script setup>
import {useRouter} from "vue-router";
import {userInfoStore} from "@/stores/counter.js";
let router = useRouter()
const store = userInfoStore()
function doLogout() {
/* 原先代码
localStorage.clear()
*/
store.doLogout()
// 跳转登陆页
router.push({name: 'login'})
}
</script>
<style scoped></style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
补充, 为啥 pinia 中 本地缓存持久化时, 需要json序列化一下 localStorage.setItem("info", JSON.stringify(info));
不序列化, 就是一个对象集合.. 不好取值.
> info = {id:1,name:'wpq',token:'xxxxx'}
{id: 1, name: 'wpq', token: 'xxxxx'}
> localStorage
Storage {length: 0}
> localStorage.setItem('info',info)
undefined
> localStorage.getItem('info')
'[object Object]' // 看这就明白了.
> localStorage.setItem('info',JSON.stringify(info))
undefined
> v1 = localStorage.getItem('info')
'{"id":1,"name":"wpq","token":"xxxxx"}'
> JSON.parse(v1)
{id: 1, name: 'wpq', token: 'xxxxx'}
> JSON.parse(v1).id
1
> JSON.parse(v1).token
'xxxxx'
> localStorage.getItem('abcde')
null
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21