为什么捐赠
API 资源管理器
使用 Vite 的 Quasar CLI - @quasar/app-vite
使用 Pinia 进行状态管理

在大型应用程序中,由于多个状态片段分散在许多组件中以及它们之间的交互,状态管理通常会变得复杂。通常会忽略 Vue 实例中真相的来源是原始数据对象 - Vue 实例只是代理对其的访问。因此,如果您有一个应该由多个实例共享的状态片段,则应避免复制它并通过身份共享它。

如果您希望组件共享状态,建议的方法是使用 Pinia。在深入了解之前,请查看其 文档。当与 Vue 开发者工具 浏览器扩展一起使用时,它具有一个很棒的功能,例如时光倒流调试。

我们不会详细介绍如何配置或使用 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 CLI 通过 $ quasar new 命令添加 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('...')
    }
  }
}