[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vd57lnAa-1647002874040)(https://pinia.vuejs.org/logo.svg#pic_center)]
Vue3 新的发展方向(来源于尤大知乎)
-
Vue 3 将在 2022 年 2 月 7 日 成为新的默认版本
-
基于 Vite 的极速构建工具链
-
<script setup>
带来的开发体验更丝滑的组合式 API 语法 -
Volar 提供的单文件组件 TypeScript IDE 支持
-
vue-tsc 提供的针对单文件组件的命令行类型检查和生成
-
Pinia 提供的更简洁的状态管理
-
新的开发者工具扩展,同时支持
Vue 2/Vue 3
,并且提供一个插件系统来允许社区库自行扩展开发者工具面板。
一、Pinia 简介与基础
1.1 Pinia 简介
- 官方地址:[这里是代码003]
Pinia
是Vuex4
的升级版,也就是Vuex5
Pinia
极大的简化了Vuex
的使用,是Vue3
的新的状态管理工具Pinia
对ts
的支持更好,性能更优, 体积更小,无mutations
,可用于Vue2
和Vue3
Pinia
支持Vue Devtools
、 模块热更新和服务端渲染
1.2 Pinia 基础
Vuex 与 Pinia 对比
Vuex
中核心部分:State
、Getters
、Mutations
(同步) 和Actions
(异步)Pinia
中核心部分:State
、Getters
和Actions
(同步异步均支持)
Pinia 各部分作用
State
: 类似于组件中data
,用于存储全局状态Getters
: 类似于组件中的computed
,根据已有的State
封装派生数据,也具有缓存的特性Actions
: 类似于组件中的methods
,用于封装业务逻辑,同步异步均可以
Pinia 官方示例JS版本
import { defineStore } from 'pinia'
export const todos = defineStore('todos', {
state: () => ({
/** @type {{ text: string, id: number, isFinished: boolean }[]} */
todos: [],
/** @type {'all' | 'finished' | 'unfinished'} */
filter: 'all',
// type will be automatically inferred to number
nextId: 0,
}),
getters: {
finishedTodos(state) {
// autocompletion! ?
return state.todos.filter((todo) => todo.isFinished)
},
unfinishedTodos(state) {
return state.todos.filter((todo) => !todo.isFinished)
},
/**
* @returns {{ text: string, id: number, isFinished: boolean }[]}
*/
filteredTodos(state) {
if (this.filter === 'finished') {
// call other getters with autocompletion ?
return this.finishedTodos
} else if (this.filter === 'unfinished') {
return this.unfinishedTodos
}
return this.todos
},
},
actions: {
// any amount of arguments, return a promise or not
addTodo(text) {
// you can directly mutate the stat 00e
this.todos.push({ text, id: this.nextId++, isFinished: false })
},
},
})
二、Pinia 在Vue3-Vite中的使用
2.1 基础使用流程
-
① 创建一个
vue vite
项目PS C:UsersFORGETDesktopvue-pinia-demo> npm init vite@latest
Need to install the following packages:
create-vite@latest
Ok to proceed? (y) y
√ Project name: … pinia-demo
√ Select a framework: ? vue
√ Select a variant: ? vue-tsScaffolding project in C:UsersFORGETDesktopvue-pinia-demopinia-demo…
Done. Now run:
cd pinia-demo
npm install
npm run dev
PS C:UsersFORGETDesktopvue-pinia-demo> cd .pinia-demo
PS C:UsersFORGETDesktopvue-pinia-demopinia-demo> npm install -
② 安装
pinia
,-S
是为了将其保存至package.json
中,便于Git
管理给其他人的使用PS C:UsersFORGETDesktopvue-pinia-demopinia-demo> npm install pinia -S
package.json文件中
“dependencies”: {
“pinia”: “^2.0.9”,
“vue”: “^3.2.25”
}, -
③ 创建
pinia
实例并挂载到vue
中// main.ts 文件
import { createApp } from ‘vue’
import App from ‘./App.vue’
import {createPinia} from ‘pinia’
// 创建 Pinia 实例
const pinia = createPinia()
// 创建 Vue 实例
const app = createApp(App)
// 挂载到 Vue 根实例
app.use(pinia)
app.mount(’#app’) -
④ 在
src
文件下创建一个store
文件夹,并添加index.ts
// store/index.ts
import { defineStore } from ‘pinia’
// 1. 定义容器、导出容器
// 参数1:容器的ID,必须是唯一的,后面Pinia会把所有的容器挂载到根容器
// 参数2:一些选项对象,也就是state、getter和action
// 返回值:一个函数,调用即可得到容器实例export const useMainStore = defineStore(‘main’,{
// 类似于Vue2组件中的data,用于存储全局状态数据,但有两个要求
// 1. 必须是函数,目的是为了在服务端渲染的时候避免交叉请求导致的数据状态污染
// 2. 必须是箭头函数,这样是为了更好的 TS 类型推导
state:()=>{
return {
info:“pinia 可以使用”
}
},
getters:{},
actions:{}
})// 2. 使用容器中的 state
// 3. 通过 getter 修改 state
// 4. 使用容器中的 action 同步和异步请求 -
⑤ 在组件中使用
{{ mainStore.info}}
2.2 state 中数据的解构访问
-
状态管理中
// store/index.ts
state:()=>{
return {
info:“pinia 可以使用”,
count:10
}
}, -
组件中
{{ mainStore.count }}
{{ mainStore.info }}
{{ count }}
{{ info }}
2.3 state 中数据的修改方式(actions和组件中)
-
一般的修改
const alertData = () => {
// 方式一:最简单的方法,如下
// 解构后更改方式
// count.value += 10
// 结构前更改方式
// mainStore.count += 10
// 方式二:若要同时修改多个数据,建议使用 p a t c h 来 实 现 批 量 更 新 , 在 内 部 做 了 优 化 / / m a i n S t o r e . patch来实现批量更新,在内部做了优化 // mainStore. patch来实现批量更新,在内部做了优化//mainStore.patch({
// count: mainStore.count + 1,
// info: “hello”
// })
// 方式三:更好的批量更新方法,通过 p a t c h 传 递 一 个 函 数 来 实 现 , 这 里 的 s t a t e 就 是 u s e M a i n S t o r e 容 器 中 的 s t a t e m a i n S t o r e . patch传递一个函数来实现,这里的state就是useMainStore容器中的state mainStore. patch传递一个函数来实现,这里的state就是useMainStore容器中的statemainStore.patch(state => {
state.count += 10
state.info = “pinia批量更新”
})
} -
通过actions修改
// store/index.ts
// 类似于vue2组件的methods,用于封装业务逻辑,修改state
// // 注意:不能使用箭头函数来定义actions,因为箭头函数绑定外部的this
actions:{
changeState (){
this.count += 10
this.info = “actions修改数据”
},
changeStates (num:number){
this.count += num + 2
this.info = “actions修改数据”
}
}const alertData = () => {
// 方式一:最简单的方法,如下
// 解构后更改方式
// count.value += 10
// 结构前更改方式
// mainStore.count += 10
// 方式二:若要同时修改多个数据,建议使用 p a t c h 来 实 现 批 量 更 新 , 在 内 部 做 了 优 化 / / m a i n S t o r e . patch来实现批量更新,在内部做了优化 // mainStore. patch来实现批量更新,在内部做了优化//mainStore.patch({
// count: mainStore.count + 1,
// info: “hello”
// })
// 方式三:更好的批量更新方法,通过 p a t c h 传 递 一 个 函 数 来 实 现 , 这 里 的 s t a t e 就 是 u s e M a i n S t o r e 容 器 中 的 s t a t e / / m a i n S t o r e . patch传递一个函数来实现,这里的state就是useMainStore容器中的state // mainStore. patch传递一个函数来实现,这里的state就是useMainStore容器中的state//mainStore.patch(state => {
// state.count += 10
// state.info = “pinia批量更新”
// })
// 方式四:通过 actions 来修改数据
mainStore.changeState()
mainStore.changeStates(10)
}
2.4 getters 的使用
-
定义
// 类似于组件的computed,用来封装计算属性,具有缓存的功能
getters:{
// 函数接收一个可选参数:state状态对象
count10(state){
return state.count += 10
},
count10(state){
return this.count += 10
},
// 若使用this.count,则必须指明返回数据的类型
count11():number{
return this.count += 11
}
}, -
使用
{{ mainStore.count10 }}
三、Pinia 数据持久化
-
保存至localStorage中
import { defineStore } from ‘pinia’;
const useLoginStore = defineStore({
id: ‘login’,
// state: () => ({
// num: 1,
// }),
state: () => ({
info: ‘pinia 可以使用’,
}),
getters: {},
actions: {
alertInfo() {
this.info = ‘可以可以,这个秒’;
},
},
});// 数据持久化
// 1. 保存数据
const instance = useLoginStore();
instance.KaTeX parse error: Expected '}', got 'EOF' at end of input: …) { instance.state = JSON.parse(old);
}
export default useLoginStore; -
使用 插件 pinia-plugin-persist 可以辅助实现数据持久化功能
安装插件
pnpm install pinia-plugin-persist --save
// main.ts文件中
import { createPinia } from ‘pinia’;
import { createApp } from ‘vue’;
import App from ‘./App.vue’;
import router from ‘./router’;
import piniaPluginPersist from ‘pinia-plugin-persist’;
const pinia = createPinia();
pinia.use(piniaPluginPersist);
const app = createApp(App);
app.use(router);
app.use(pinia);
app.mount(’#app’);// 接着在对应的 store 里开启 persist 即可。数据默认存在 sessionStorage 里,并且会以 store 的 id 作为 key。
import { defineStore } from ‘pinia’;
import piniaPluginPersist from ‘pinia-plugin-persist’;
const useLoginStore = defineStore({
id: ‘login’,
// state: () => ({
// num: 1,
// }),
state: () => ({
info: ‘pinia 可以使用’,
}),
// 开启数据缓存
persist: {
enabled: true,
},
getters: {},
actions: {
alertInfo() {
this.info = ‘可以可以,这个秒’;
},
},
});
export default useLoginStore; -
其它设置,自定义保存名称,保存位置和需要保存的数据
// 开启数据缓存
persist: {
enabled: true,
strategies: [
{
// 自定义名称
key: ‘login_store’,
// 保存位置,默认保存在sessionStorage
storage: localStorage,
// 指定要持久化的数据,默认所有 state 都会进行缓存,你可以通过 paths 指定要持久化的字段,其他的则不会进行持久化。
paths: [‘age’],
},
],
},
,