云风网
云风笔记
云风知识库

在这个项目中采用pinia进行全局状态管理
Pinia符合直觉的 Vue.js 状态管理库

‌Pinia和‌Vuex的主要区别如下:

  1. 架构设计

Vuex采用了集中式的架构,将所有的状态存储在一个单一的全局状态树中,通过‌mutations和‌actions来修改和处理状态。‌
Pinia采用了去中心化的架构,将状态分布在多个模块中,每个模块拥有自己的状态、mutations和actions。

  1. 体积和复杂性:

Vuex是‌Vue.js的官方状态管理库,拥有庞大的生态系统,适合大型和复杂的项目。
Pinia是一个相对较新的库,较小且更简单,适合小型或简单的项目。

  1. TypeScript 支持:

Vuex从Vue 2.x版本开始引入了对TypeScript的支持,但需要使用额外的插件来实现类型检查。
Pinia在设计之初就对TypeScript提供了原生的支持,提供了更好的类型推导和类型检查的支持。

  1. 代码风格和语法:

Vuex使用了更传统的mutations和actions的方式来修改和处理状态。
Pinia更加倾向于直接操作状态,提供了更加灵活的状态管理方式。

  1. 具体例子和场景:

在小型项目中,Pinia由于其轻量级和简单性,可能更容易上手和使用。‌
在大型项目中,Vuex由于其更多的功能和更成熟的生态系统,可能更适合。
在Vue 3项目中,由于Pinia是基于Vue 3的‌Composition API构建的,因此更加灵活和可组合。
在TypeScript支持方面,Pinia提供了完整的TypeScript支持,而Vuex只是部分支持。
这些区别使得开发者在选择状态管理库时需要根据项目的具体需求和规模来做出决策。

一、安装依赖

npm install pinia

二、项目引入pinia

1、在vite.config.ts配置自动引入pinia

 plugins: [
     ...
    ViteAutoImport({
      // 引入一些公共的模块
      imports: ['vue', 'vue-router', 'pinia'],
      // dirs: [],
      // 可以选择自动导入的文件类型    .d.ts文件就是对ts做出类型定义
      dts: 'types/auto-imports.d.ts'
    })
]

2、pinia模块化搭建

在这里插入图片描述

store/index.ts内容如下

import { createPinia } from 'pinia'
const store = createPinia()

export default store

src/main.ts引入pinia

import store from './store'
app.use(store)//pinia全局状态管理

2、pinia子模块modules/*.ts

在store/modules文件夹新建settings.ts,用来管理项目主题样式状态

import defaultSettings from '@/settings'
import { useDynamicTitle } from '@/utils/dynamicTitle'

const { sideTheme, showSettings, topNav, tagsView, fixedHeader, sidebarLogo, dynamicTitle } = defaultSettings

const storageSetting = JSON.parse(localStorage.getItem('layout-setting')) || ''

const useSettingsStore = defineStore(
  'settings',
  {
    state: () => ({
      title: '',
      theme: storageSetting.theme || '#409EFF',
      sideTheme: storageSetting.sideTheme || sideTheme,
      showSettings: showSettings,
      topNav: storageSetting.topNav === undefined ? topNav : storageSetting.topNav,
      tagsView: storageSetting.tagsView === undefined ? tagsView : storageSetting.tagsView,
      fixedHeader: storageSetting.fixedHeader === undefined ? fixedHeader : storageSetting.fixedHeader,
      sidebarLogo: storageSetting.sidebarLogo === undefined ? sidebarLogo : storageSetting.sidebarLogo,
      dynamicTitle: storageSetting.dynamicTitle === undefined ? dynamicTitle : storageSetting.dynamicTitle
    }),
    actions: {
      // 修改布局设置
      changeSetting(data) {
        const { key, value } = data
        if (this.hasOwnProperty(key)) {
          this[key] = value
        }
      },
      // 设置网页标题
      setTitle(title) {
        this.title = title
        useDynamicTitle();
      }
    }
  })

export default useSettingsStore

其中defaultSettings 表示在src/settings.ts文件中定义的主题配置

export default {
  /**
   * 网页标题
   */
  title: import.meta.env.VITE_APP_TITLE,
  /**
   * 侧边栏主题 深色主题theme-dark,浅色主题theme-light
   */
  sideTheme: 'theme-light',
  /**
   * 是否系统布局配置
   */
  showSettings: true,

  /**
   * 是否显示顶部导航
   */
  topNav: false,

  /**
   * 是否显示 tagsView
   */
  tagsView: true,

  /**
   * 是否固定头部
   */
  fixedHeader: false,

  /**
   * 是否显示logo
   */
  sidebarLogo: true,

  /**
   * 是否显示动态标题
   */
  dynamicTitle: false,

  /**
   * @type {string | array} 'production' | ['production', 'development']
   * @description Need show err logs component.
   * The default is only used in the production env
   * If you want to also use it in dev, you can pass ['production', 'development']
   */
  errorLog: 'production'
}

useDynamicTitle 为动态修改标题封装的方法,dynamicTitle.ts内容如下

import defaultSettings from '@/settings'
import useSettingsStore from '@/store/modules/settings'

/**
 * 动态修改标题
 */
export function useDynamicTitle() {
  const settingsStore = useSettingsStore();
  if (settingsStore.dynamicTitle) {
    document.title = settingsStore.title + ' - ' + defaultSettings.title;
  } else {
    document.title = defaultSettings.title;
  }
}

三、pinia应用

例如控制项目主题切换的背景颜色变化

import useSettingsStore from '@/store/modules/settings'
const settingsStore = useSettingsStore()
const sideTheme = computed(() => settingsStore.sideTheme);

<el-menu
  :default-active="activeMenu"
  :background-color="sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground"
  :text-color="sideTheme === 'theme-dark' ? variables.menuColor : variables.menuLightColor"
  :unique-opened="true"
  :active-text-color="theme"
  :collapse-transition="false"
  mode="vertical"
>
  <sidebar-item
      v-for="(route, index) in sidebarRouters"
      :key="route.path + index"
      :item="route"
      :base-path="route.path"
  />
</el-menu>

如果想要切换设置全局状态,则调用action定义的方法,比如设置title

useSettingsStore().setTitle(to.meta.title)

云风
7 声望0 粉丝

独立开发者