Quasar CLI with Webpack - @quasar/app-webpack

使用 Pinia 管理状态

在大型应用程序中,由于多个组件都有自己的状态并且相互依赖,使得状态管理变得很复杂。

如果组件之间想要共享同一个状态,我们推荐您使用 Pinia。开始之前我们希望您已经了解了 Pinia 的文档Vue dev-tools 还对 pinia 作了特性支持。

我们不会详细讨论如何配置或使用 Pinia,因为它有很棒的文档。相反,我们将向您展示在 Quasar 项目中使用它时,目录结构是什么样子的:

.
└── src/
    └── stores/       # Pinia
        ├── index.js  # Pinia initialization
        ├── <store>   # Pinia store...
        └── <store>   # Pinia store...

当您使用 Quasar CLI 创建项目时,它会询问是否要添加 Pinia 并为您准备好所有必要的配置,包括帮您创建好上述的 src/stores 目录结构,在其中包括了与 Pinia 相关的必要的代码。

如果您在创建项目时未选择添加 Pinia,但想要为已有项目添加 Pinia 支持,那么您需要做的只是参考下一节中的步骤并创建 src/stores/index.[js|ts] 文件。

添加一个 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] 文件:

.
└── src/
    └── stores/
        ├── index.js     # Pinia initialization
        └── 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>
    <q-toggle v-model="store.counter" />
  </div>
</template>

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

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

    return {
      // 您可以将整个 strore 实例返回供  template 使用
      store
    }
  }
}
</script>

关于定义一个 Pinia store 的更多参考.

在 Pinia stores 中访问 router

我们可以简单的在 Pinia stores 中使用 this.router 来访问 router

示例:

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

译者批注

可以使用 this.router 的原因是 quasar 在生成的 app.js 中添加了类似这样的语句:

const store = typeof createStore === 'function'
  ? await createStore({})
  : createStore

  app.use(store)

const router = markRaw(
typeof createRouter === 'function'
  ? await createRouter({store})
  : createRouter
)

// make router instance available in store
store.use(({ store }) => { store.router = router })

您可以在项目运行时,查看项目根目录下的 .quasar/app.js 文件以验证这一点,同理,我们也可以像这样注入更多的变量。

例如我们也可以将 i18n 注入到 Pinia 中以方便使用:

// boot/i18n.js

import { boot } from 'quasar/wrappers';
import { createI18n } from 'vue-i18n';

import messages from 'src/i18n';

export default boot(({ app, store }) => {
  const i18n = createI18n({
    locale: 'en-US',
    legacy: false,
    messages,
  });
  // Set i18n instance on app
  app.use(i18n);
  // 将 i18n 的实例添加到 pinia 中
  store.use(({ store }) => {
    store.i18n = i18n;
  });
});

此时。我们可以像这样简单的使用 this.i18n 在 Pinia store 中访问到 i18n:

import { defineStore } from 'pinia';

export const useGlobalStore = defineStore('counter', {
  actions: {
    changeLang(tar: string) {
      this.i18n.global.locale = tar;
      // 根据您设置的 legacy ,您可能还需要像下面这样添加一个 .value
      // 参考: https://vue-i18n.intlify.dev/guide/essentials/scope.html#locale-changing
      // this.i18n.global.locale.value = tar;
    },
  },
});