為何捐款
API 瀏覽器
升級指南
新功能!
quasar.config 檔案
轉換為搭配 Webpack 的 CLI
瀏覽器相容性
支援 TypeScript
目錄結構
指令列表
CSS 預處理器
路由
延遲載入 - 代碼分割
處理資源
啟動檔案
預取功能
API 代理
處理 Webpack
處理 process.env
搭配 Pinia 的狀態管理
搭配 Vuex 的狀態管理
Linter
測試與稽核
開發行動應用程式
Ajax 請求
向公眾開放開發伺服器
Quasar CLI with Webpack - @quasar/app-webpack
使用 Pinia 進行狀態管理

在大型應用程式中,由於多個狀態分散在許多組件以及它們之間的交互,狀態管理通常變得複雜。人們常常忽略 Vue 實例中的事實來源是原始資料物件 - Vue 實例只是代理對它的訪問。因此,如果您有一個狀態應該由多個實例共享,則應避免重複它並通過身份共享它。

如果您希望組件共享狀態,建議的方法是 Pinia。在深入了解之前,請查看其文檔。當與 Vue 開發者工具 瀏覽器擴充功能(如 Time Travel 偵錯)一起使用時,它具有出色的功能。

我們不會詳細介紹如何配置或使用 Pinia,因為它有很棒的文檔。相反,我們將向您展示在 Quasar 專案中使用它時的資料夾結構。

index.js
# Pinia 初始化
<store>
# Pinia store...
<store>
# Pinia store...

當您搭建 Quasar 專案資料夾時,您可以選擇新增 Pinia。它將為您建立所有必要的配置。例如,建立 /src/stores,它處理您需要的所有 Pinia 相關程式碼。

如果您在專案建立期間未選擇 Pinia 選項,但稍後想要新增它,那麼您只需檢查下一節並建立 src/stores/index.[js|ts] 檔案(當您執行 quasar new store <name> 時,它會自動建立)。

/src/stores/index.js

import { store } from 'quasar/wrappers'
import { createPinia } from 'pinia'

/*
 * If not building with SSR mode, you can
 * directly export the Store instantiation;
 *
 * The function below can be async too; either use
 * async/await or return a Promise which resolves
 * with the Store instance.
 */

export default store((/* { ssrContext } */) => {
  const pinia = createPinia()

  // You can add Pinia plugins here
  // pinia.use(SomePiniaPlugin)

  return pinia
})

新增 Pinia store

通過 $ quasar new 命令,使用 Quasar CLI 可以輕鬆新增 Pinia store。

$ quasar new store <store_name> [--format ts]

它將在 /src/stores 中建立一個資料夾,名稱為上述命令中的“store_name”。它將包含您需要的所有樣板。

假設您要建立一個“counter” Pinia store。您發出 $ quasar new store counter。然後您會注意到新建立的 /src/stores/counter.[js|ts] 檔案。

index.js
# Pinia 初始化
counter.js
# Pinia store

Pinia store 範例

import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({
    counter: 0,
  }),
  getters: {
    doubleCount: (state) => state.counter * 2,
  },
  actions: {
    increment() {
      this.counter++;
    },
  },
})

我們已經建立了新的 Pinia store,但我們還沒有在我們的應用程式中使用它。在 Vue 檔案中

<template>
  <div>
    <!-- Option 1 -->
    <div>Direct store</div>
    <!-- Read the state value directly -->
    <div>{{ store.counter }}</div>
    <!-- Use getter directly -->
    <div>{{ store.doubleCount }}</div>

    <!-- Manipulate state directly -->
    <q-btn @click="store.counter--">-</q-btn>
    <!-- Use an action -->
    <q-btn @click="store.increment()">+</q-btn>
  </div>

  <div>
    <!-- Option 2 -->
    <div>Indirect store</div>
    <!-- Use the computed state -->
    <div>{{ count }}</div>
    <!-- Use the computed getter -->
    <div>{{ doubleCountValue }}</div>

    <!-- Use the exposed function -->
    <q-btn @click="decrementCount()">-</q-btn>
    <!-- Use the exposed function -->
    <q-btn @click="incrementCount()">+</q-btn>
  </div>

  <div>
    <!-- Option 3 -->
    <div>Destructured store</div>
    <!-- Use the destructured state -->
    <div>{{ counter }}</div>
    <!-- Use the destructured getter -->
    <div>{{ doubleCount }}</div>

    <!-- Manipulate state directly-->
    <q-btn @click="counter--">-</q-btn>
    <!-- Use an action -->
    <q-btn @click="increment()">+</q-btn>
  </div>
</template>

<script>
import { computed } from 'vue';
import { useCounterStore } from 'stores/counter';
import { storeToRefs } from 'pinia';

export default {
  setup() {
    const store = useCounterStore();

    // Option 2: use computed and functions to use the store
    const count = computed(() => store.counter);
    const doubleCountValue = computed(() => store.doubleCount);
    const incrementCount = () => store.increment(); // use action
    const decrementCount = () => store.counter--; // manipulate directly

    // Option 3: use destructuring to use the store in the template
    const { counter, doubleCount } = storeToRefs(store); // state and getters need "storeToRefs"
    const { increment } = store; // actions can be destructured directly

    return {
      // Option 1: return the store directly and couple it in the template
      store,

      // Option 2: use the store in functions and compute the state to use in the template
      count,
      doubleCountValue,
      incrementCount,
      decrementCount,

      // Option 3: pass the destructed state, getters and actions to the template
      counter,
      increment,
      doubleCount,
    };
  },
};
</script>

有關定義 Pinia store 的更多資訊,請參閱此處

在 Pinia store 中存取路由

只需在 Pinia store 中使用 this.router 即可存取路由。

這是一個範例

import { defineStore } from 'pinia'

export const useWhateverStore = defineStore('whatever', {
  // ...
  actions: {
    whateverAction () {
      this.router.push('...')
    }
  }
}