aspaccess做網站站長平臺百度
???????狀態(tài)管理
????????我們知道組件與組件之間可以傳遞信息,那么我們就可以將一個信息作為組件的獨立狀態(tài)(例如,單個組件的顏色)或者共有狀態(tài)(例如,多個組件是否顯示)在組件之傳遞,這樣的話我們希望這個信息在所有組件中共享,這樣就可以監(jiān)控所有組件的狀態(tài),但是一般的信息傳遞方式想要在所有組件傳遞一個信息會形成一個復雜的關系網,不利于管理且中間組件若產生異常,這個關系網就會斷裂,整個網頁的組件就會變的無法監(jiān)控,
所以我們需要一個工具來管理所有組件的狀態(tài),他需要以下幾點功能
1.能夠注冊一個全局狀態(tài)(store),形成一個中間件,讓所有組件都能訪問到,
2.當這個全局狀態(tài)被某一個組件影響改變時,它能夠讓其他組件更新這個狀態(tài),
3.將信息獨立出來,不因為一個組件錯誤,產生全局錯誤
vuex和pinia
vuex和pinia都是vue的狀態(tài)管理工具,它們的作用相同,用法幾乎沒有區(qū)別,但是pinia的結構更加簡潔,同時對Ts的兼容性更強。
vuex和pinia的核心
vuex | pinia |
state --- 狀態(tài)信息 | state --- 狀態(tài)信息 |
getter --- 選擇性的讀取信息 | getter --- 選擇性的讀取信息 |
mutation ---?可以執(zhí)行同步操作 | action --- 可以執(zhí)行同步和異步操作 |
action --- 可以執(zhí)行異步操作 返回一個mutation |
vuex和pinia的關系
Pinia 起源于一次探索 Vuex 下一個迭代的實驗,因此結合了 Vuex 5 核心團隊討論中的許多想法。最后,我們意識到 Pinia 已經實現了我們在 Vuex 5 中想要的大部分功能,所以決定將其作為新的推薦方案來代替 Vuex。
這兩個工具相似度很高,作用也一致,當你熟練掌握其中一個時,另一個也能夠輕松使用,這里我們還是使用pinia作為項目的狀態(tài)管理器
pinia的基本使用
手動引入pinia
新建一個vue項目
npm create vue@latest
輸入完項目名稱后一路回車即可,對于是否引入pinia的選項我們暫時不選則,?
?
這里我們在src的目錄下新建一個文件夾store,并在store下新建一個index.js,然后刪除components文件夾的原內容,并新建兩個vue文件
安裝pinia包
npm install pinia
安裝完成后可以在package中看到,然后我們開始導入pinia
main.js:
import './assets/main.css'import { createApp } from 'vue'
import App from './App.vue'
import { createPinia } from 'pinia'createApp(App).use(createPinia()).mount('#app')
?導入完成后我們在index.js中配置pinia
index.js:
import {defineStore} from 'pinia'export const useStore = defineStore('counter', {state: () => {return {// 定義狀態(tài)counter: 0}},// 定義計算屬性getters: {// 定義計算屬性getCounter: (state) => {return state.counter>=5?state.counter:"數據不足"}},// 定義操作actions: {// 定義操作addCounter() {this.counter++}}// 定義其他選項// ...
})
?注意 :第一個參數counter是返回store的一個標識,在一個項目中,我們可以新建多個store來表示多個狀態(tài),每個狀態(tài)都有一個標識;第二個參數是一個對象,里面包含了state定義狀態(tài)可以返回多個值(任意類型)表示狀態(tài),getter定義了一個屬性運算的方法,可以用來過濾數據,只拿需要的數據(外部使用這個方法時不帶括號),action定義了一個操作(可以 是異步操作,外部調用是要帶括號);
然后我們再對App.vue,myComA.vue,myComB.vue引入store中間件
App.vue,
<script setup>
import myComA from './components/myComA.vue'
import myComB from './components/myComB.vue'
import { useStore } from './store/index.js'
const store = useStore()</script><template><p>{{ store.getCounter }}</p><button @click="store.addCounter()">counter = {{ store.counter }}</button><myComA/><myComB/>
</template>
myComA.vue,
<script setup>//組合式API
import { useStore } from '../store/index'
const store = useStore()</script><template><div>myComA</div><p>{{ store.counter }}</p>
</template>
myComB.vue
<script setup>//組合式API
import { useStore } from '../store/index'
const store = useStore()</script><template><div>myComB</div><p>{{ store.counter }}</p>
</template>
這里要注意import引入index文件的路徑有所不同
完整這些后我們啟動項目
npm run dev
????????點擊一次按鈕,store的counter值就加一,當這個值大于等于5時,會在App.vue中顯示出來,否則顯示數據不足,App.vue,myComA.vue,myComB.vue? 3個組件中均有顯示,說明3個組件都訪問到了數據,它們綁定了一個共同的信息,即便我們移除了myComB.vue其他組件也沒有受到影響
這樣我們就為每個組件都設置了一個狀態(tài),
系統(tǒng)引入pinia
掌握了手動引入pinia后,我們可以再新建一個項目查看以下系統(tǒng)的pinia
npm create vue@latest
我們可以看到它是有一個stores文件夾的,同時再main.js,counter.js,package.json中也是有對應的配置的
我們可以觀察到,它的配置方式和我們手動配置的方式有所不同,
其實這個pinia的配置類似于setup函數的結構,有選擇式風格和組合式風格,這里采用的是組合式風格,2者的效果是完全一致的,可以自行對比兩種方法
我們可以引入之前項目中App.vue,myComA.vue,myComB.vue? 3個組件(注意這里的方法和文件名稱有所改變)再啟動項目查看
app.vue:
<script setup>
import myComA from './components/myComA.vue'
import myComB from './components/myComB.vue'
import { useCounterStore } from './stores/counter.js'
const store =useCounterStore()</script><template><p>{{ store.doubleCount }}</p><button @click="store.increment()">counter = {{ store.count }}</button><myComA/><myComB/>
</template>myComA.vue:
<script setup>//組合式API
import { useCounterStore } from '../stores/counter.js'
const store = useCounterStore()</script><template><div>myComA</div><p>{{ store.count }}</p>
</template>myComB.vue:
<script setup>//組合式API
import { useCounterStore } from '../stores/counter.js'
const store = useCounterStore()</script><template><div>myComB</div><p>{{ store.count }}</p>
</template>
npm run dev
可以看到實現了狀態(tài)共享,在實際應用中我們使用系統(tǒng)引入pinia后,可以自己手動的將pinia的相關文件調整成我們需要的結構
擴展:pinia數據持久化
登錄狀態(tài)的數據問題
????????pinia的狀態(tài)共享功能最常見的使用就是登錄狀態(tài)的共享,它可以保存當前頁面的一個登錄狀態(tài),這樣當你在登錄頁面登錄成功后,其他頁面可以共享這個登錄狀態(tài),在一個頁面退出登錄后,其他頁面也能夠共享,這樣網頁就能區(qū)分用戶和游客了。
????????但是,pinia是基于內存實現的,當你刷新頁面后,pinia保存的可共享數據就會刷新,這樣我們就需要重新登錄,我們希望用戶登錄后登錄狀態(tài)應該由網絡請求返回的token(一段有時間限制會過期的數據)保存,所以我們需要實現pinia的數據持久化,讓頁面刷新后仍可以保留登錄狀態(tài),
實現數據持久化
? ? ? ? 想在瀏覽器內存下一串數據不會因為刷新而清空,我們可以想到localStorage就有這個功能,
pinia提供了一個插件,基于localStorage實現了數據的緩存,這樣頁面刷新后,pinia會先從localStorage中讀取數據(一般是token)驗證用戶的登錄狀態(tài),這樣就不用反復登錄了
pinia-plugin-persistedstate
安裝插件:快速開始 | pinia-plugin-persistedstate (prazdevs.github.io)
npm i pinia-plugin-persistedstate
安裝完成后可以在package.json中查看?
?注冊插件:
在main.js中注冊引入
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import {piniaPluginPersistedstate} from 'pinia-plugin-persistedstate'const app = createApp(App)
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)app.use(pinia)
app.mount('#app')
在store下創(chuàng)建pinia對象的文件內啟用插件
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'export const useCounterStore = defineStore('counter', () => {const count = ref(0)const doubleCount = computed(() => count.value * 2)function increment() {count.value++}return { count, doubleCount, increment }},{persist: true,//開啟路由緩存},
)
?App.vue
<script setup>
import {useCounterStore} from '@/stores/counter'const {count,increment} = useCounterStore();
increment();//action方法,使用pinia的數據
console.log(count);
</script>
<template></template>
<style scoped></style>
這個counter存儲的數據就會被保留在本地了
這樣每次打開執(zhí)行這個自增的 方法時會先從原來保存的數據執(zhí)行,而不會因為刷新內存丟失掉數據,從0開始執(zhí)行
總結
????????pinia是一個狀態(tài)管理工具,它可以保存一個狀態(tài)(數據),和一些方法,提供給給全局的組件共享。簡單來說,pinia可以設置全局的響應量和方法,所有組件都可以訪問到這些響應量和方法,并產生對應的變化