1.pinia的簡單介紹
Pinia最初是在2019年11月左右重新設計使用Composition API的 Vue 商店外觀的實驗。
從那時起,最初的原則相同,但 Pinia 适用于 Vue 2 和 Vue 3 。
并且不需要你使用組合 API。
除了安裝和SSR之外,還有其他的 API是一樣的。
并且這些針對 Vue 3 ,并在必要時提供 Vue 2 的相關注釋。
以便 Vue 2 和 Vue 3 的使用者可以閱讀!
2.為什麼要使用Pina?
Pinia 是 Vue 的存儲庫,
允許您跨元件/頁面共享狀态。
如果您的組合 API,您可能會認為您可以使用簡單的export const state = reactive({})
這對于單頁應用程式來說是正确的,
但如果它是伺服器端的外觀,将您的應用程式顯示給安全漏洞。
但即使在小型單頁應用程式中,您也可以從使用 Pinia 中獲得好處:
1.開發工具支援
2.動作、追蹤的跟蹤
3.熱子產品更換
4.為 JS 使用者提供适當功能的 TypeScript 支援或自動完成
5.伺服器端渲染支援
安裝
npm install pinia --save
3.建立檔案夾和檔案-存放資料
在建立 src/store目錄并在其下面建立 index.ts檔案,并導出這個檔案
// src/store/index.ts下的代碼
import { createPinia } from 'pinia'
const store = createPinia()
export default store
在 main.ts 中引入
import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index'
<!-- 引入 -->
import store from "./store/index"
<!-- 使用store -->
createApp(App).use(router).use(store).mount('#app')
需求描述
假設我們現在有好幾個子產品。有user子產品。admin子產品。
我們想對這子產品中的資料進行管理。
為了管理友善,後面易于維護。我們決定将這些子產品進行拆分。
于是我們在store下建立 user.ts 檔案,管理這個user子產品的資料。
user.ts下的資料
//src/store/user.ts 檔案
import { defineStore } from 'pinia'
export const useUserStore = defineStore({
id: 'userkey', // id必填,且需要唯一
// state是存放資料的
state: () => {
return {
name: '于途',
likelist:[],
sex:'男',
work:'寫代碼',
heigt:'1.70cm'
}
},
})
defineStore的介紹
defineStore 接收兩個參數.
第一個參數:必須是唯一的,多個子產品千萬千萬不能重名。
因為Pinia 會把所有的子產品都挂載到根容器上
第二個參數是一個對象,裡面的選項state和 Vuex 差不多
4.擷取store中值的第一種方法
<template>
<div class="pinia">
<h2> 學習pinia </h2>
<div> {{ userStore }} </div>
<div>姓名:{{ userStore.name }}</div>
<div>性别:{{ userStore.sex }}</div>
<div>工作:{{ userStore.work }}</div>
<div>身高:{{ userStore.heigt }}</div>
</div>
</template>
<script setup lang='ts'>
// 引入store中暴露出去的方法
import { useUserStore } from '../../store/user'
const userStore = useUserStore()
</script>
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiATN381dsQWZ4lmZf1GLlpXazVmcvwFciV2dsQXYtJ3bm9CX9s2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xCMy81dvRWYoNHLwEzX5xCMx8FesU2cfdGLwMzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5COyYDN3EDM4EWOjJGM3ATMzYzXwQzM0YTMxAzLclDMyIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjLyM3Lc9CX6MHc0RHaiojIsJye.png)
擷取store中值的第二種方法-computed
<template>
<div class="pinia">
<h2> 學習pinia </h2>
<div>姓名:{{useStoreName}}</div>
<div>性别:{{useStoreSex}}</div>
</div>
</template>
<script setup lang='ts'>
// 引入store中暴露出去的方法
import { computed } from 'vue'
import { useUserStore } from '../../store/user'
const userStore = useUserStore()
// 使用 computed取擷取值
const useStoreName = computed(() => userStore.name)
const useStoreSex = computed(() => userStore.sex)
</script>
提出問題
如果對象上有多個屬性,可以進行結構嗎?
可以的!
使用 pinia 提供的 storeToRefs
我們來看下怎去使用
5.pinia 提供的 storeToRefs進行結構
<template>
<div class="pinia">
<h2> 學習pinia </h2>
<div>姓名:{{ asName }}</div>
<div>性别:{{ mysex }}</div>
<div>工作:{{ work }}</div>
<div>身高:{{ heigt }}</div>
</div>
</template>
<script setup lang='ts'>
import { storeToRefs } from 'pinia'
import { useUserStore } from '../../store/user'
const userStore = useUserStore()
// asName 和 mysex 是我取的别名
const { name : asName ,sex:mysex, work, heigt } = storeToRefs(userStore)
</script>
6.如何修改 state 中的資料
修改 state 中的資料,可以通過 actions 下的方法。
然後調用 updataName 就可以取修改 state中的name值了
//src/store/user.ts 檔案
import { defineStore } from 'pinia'
export const useUserStore = defineStore({
id: 'userkey', // id必填,且需要唯一
// state是存放資料的
state: () => {
return {
name: '于途',
likelist:[],
sex:'男',
work:'寫代碼',
heigt:'1.70cm'
}
},
// actions 可以修改state中的值,這裡面提供方法
actions:{
// 修改name中的資料
updataName(name:string){
this.name=name
},
},
})
調用方法,修改state中的name
<template>
<div class="pinia">
<h2> 學習pinia </h2>
<div>姓名:{{ asName }}</div>
<div>性别:{{ mysex }}</div>
<div>工作:{{ work }}</div>
<div>身高:{{ heigt }}</div>
<el-button type="primary" @click="changeHander">修改name</el-button>
</div>
</template>
<script setup lang='ts'>
import { storeToRefs } from 'pinia'
import { useUserStore } from '../../store/user'
const userStore = useUserStore()
// asName 和 mysex 是我取的别名
const { name : asName ,sex:mysex, work, heigt } = storeToRefs(userStore)
const changeHander=()=>{
userStore.updataName('小玉兔')
// 這樣我發現也可以,但是不推薦這樣使用。
// 統一通過 actions 中的方法去修改值
userStore.work='我換工作了'
}
</script>
7.getters的使用
//src/store/user.ts 檔案
import { defineStore } from 'pinia'
export const useUserStore = defineStore({
id: 'userkey', // id必填,且需要唯一
// state是存放資料的
state: () => {
return {
name: '于途',
likelist:[],
sex:'男',
work:'寫代碼',
heigt:'1.70cm',
age:26,
}
},
// actions 可以修改state中的值,這裡面提供方法
actions:{
// 修改name中的資料
updataName(name:string){
this.name=name
},
},
// Getter 完全等同于 Store 狀态的計算值
getters:{
// 将姓名進行更改
getName: (state) => {
return state.name + 'hahha~!'
}
}
})
//使用的頁面.vue
<template>
<div class="pinia">
<h2> 學習pinia </h2>
<div>姓名:{{ asName }}</div>
<div>性别:{{ mysex }}</div>
<div>工作:{{ work }}</div>
<div>身高:{{ heigt }}</div>
<div>身高:{{ age }}</div>
<!-- 這裡就直接使用了getters中的方法 -->
姓名:{{ userStore.getName }}
<el-button type="primary" @click="changeHander">修改name</el-button>
</div>
</template>
<script setup lang='ts'>
import { storeToRefs } from 'pinia'
import { useUserStore } from '../../store/user'
const userStore = useUserStore()
// asName 和 mysex 是我取的别名
const { name : asName ,sex:mysex,
work, heigt,age
} = storeToRefs(userStore)
const changeHander=()=>{
userStore.updataName('小玉兔')
}
</script>
對于getters的使用的說明
Getter 完全等同于 Store 狀态的計算值 computed.
并不會影響原始資料
9.異步actions-設定state中的值
//src/store/user.ts 檔案
import { defineStore } from 'pinia'
// 引入接口
import { getUser } from "../https/api";
export const useUserStore = defineStore({
id: 'userkey', // id必填,且需要唯一
// state是存放資料的
state: () => {
return {
name: '于途',
likelist:[],
}
},
// actions 可以修改state中的值,這裡面提供方法
actions:{
// 修改name中的資料 同步
updataName(name:string){
this.name=name
},
// 異步-擷取遠端的資料
loadUserList(){
getUser({}).then(res=>{
this.likelist = res
})
}
// 使用await和async 第二種方法
// async loadUserList(){
// const list = await getUser({})
// console.log('list',list)
// this.likelist = list
// }
},
})
使用的頁面
<template>
<div class="pinia">
<h2> 學習pinia </h2>
資料 {{ userStore.likelist}}
<el-button type="primary" @click="changeHander">擷取遠端資料</el-button>
</div>
</template>
<script setup lang='ts'>
import { storeToRefs } from 'pinia'
import { useUserStore } from '../../store/user'
const userStore = useUserStore()
const changeHander=()=>{
// 異步調用
userStore.loadUserList() // 加載所有資料
}
10.actions 中互相調用方法
很多時候,我們可能會出現 actions中互相去調用方法。
這個時候怎麼去處理呢?
通過this.方法名(參數)
//src/store/user.ts 檔案
import { defineStore } from 'pinia'
// 引入接口
import { getUser } from "../https/api";
export const useUserStore = defineStore({
id: 'userkey', // id必填,且需要唯一
// state是存放資料的
state: () => {
return {
name: '于途',
likelist:[],
}
},
// actions 可以修改state中的值,這裡面提供方法
actions:{
// 修改name中的資料 同步
updataName(name:string){
this.name=name
},
// 異步-擷取遠端的資料
loadUserList(){
getUser({}).then(res=>{
this.likelist = res
this.sayHi('互相調用方法')
})
},
sayHi(mess:string){
console.log('loadUserList方法中調用了sayHi',mess)
}
},
})
使用的頁面.vue
<template>
<div class="pinia">
<h2> 學習pinia </h2>
資料 {{ userStore.likelist}}
<el-button type="primary" @click="changeHander">擷取遠端資料</el-button>
</div>
</template>
<script setup lang='ts'>
import { storeToRefs } from 'pinia'
import { useUserStore } from '../../store/user'
const userStore = useUserStore()
const changeHander=()=>{
// 異步調用
userStore.loadUserList() // 加載所有資料
}
</script>
11.資料持久化-sessionStorage 或 localStorage
我們都知道,vuex重新整理後,資料會丢失。
這個時候我們需要将資料進行持久化。
我們可以考慮sessionStorage或者localStorage
//src/store/user.ts 檔案
import { defineStore } from 'pinia'
// 引入接口
import { getUser } from "../https/api";
export const useUserStore = defineStore({
id: 'userkey', // id必填,且需要唯一
// state是存放資料的
state: () => {
return {
// 資料持久化使用的是sessionStorage
name: sessionStorage.getItem('name') ? sessionStorage.getItem('name') : '于途',
likelist:[],
}
},
actions:{
// 修改name中的資料 同步
updataName(name:string){
sessionStorage.setItem('name', name)
this.name=name
},
},
})
<template>
<div class="pinia">
<h2> 學習pinia </h2>
姓名 {{ userStore.name}}
<el-button type="primary" @click="changeHander">該變值</el-button>
</div>
</template>
<script setup lang='ts'>
import { storeToRefs } from 'pinia'
import { useUserStore } from '../../store/user'
const userStore = useUserStore()
const changeHander=()=>{
// 異步調用
userStore.updataName('我改變了姓名')
}
</script>
12.跨子產品修改資料
雖然我不建議跨子產品修改資料。
因為這樣可能會導緻你的應用資料流向變得難以了解。
但是有些時候确實需要跨子產品修改資料。
那麼pinia怎麼去處理跨子產品修資料呢?
下面我們一起來探索跨子產品修改資料!
假設admin子產品需要去修改user子產品中的資料
admin.ts代碼如下
//src/store/admin.ts 檔案
import { defineStore } from 'pinia'
// 引入user子產品
import { useUserStore } from './user'
export const adminUserStore = defineStore({
id: 'adminkey',
actions:{
// 通過引入的useUserStore子產品,然後去觸發它裡面對應的方法。
editUserModuleValue(name:string){
// userStore可以看見整個user子產品中的資料和方法
let userStore=useUserStore()
console.log('userStore',userStore)
userStore.updataName(name)
}
},
})
user.ts代碼
//src/store/user.ts 檔案
import { defineStore } from 'pinia'
// 引入接口
export const useUserStore = defineStore({
id: 'userkey', // id必填,且需要唯一
// state是存放資料的
state: () => {
return {
name: '于途',
likelist:[],
sex:'男',
work:'寫代碼',
heigt:'1.70cm'
}
},
actions:{
// 修改name中的資料 同步
updataName(name:string){
this.name=name
},
},
})
頁面的使用
<template>
<div class="pinia">
<h2> 學習pinia </h2>
姓名 {{ userStore.name}}
<el-button type="primary" @click="changeHander">該變值</el-button>
</div>
</template>
<script setup lang='ts'>
import { storeToRefs } from 'pinia'
// 引入admin子產品
import { adminUserStore } from '../../store/admin'
// 引入user子產品
import { useUserStore } from '../../store/user'
const adminStore = adminUserStore()
const userStore = useUserStore()
// dmin子產品需要去修改user子產品中的資料
const changeHander=()=>{
adminStore.editUserModuleValue('資料資料')
}
</script>