Данная статья является оригинальной статьей, просьба указывать источник цитаты, добро пожаловать в сбор и распространение💐💐
открытие
Привет всем, я считаю, что если вы используете проект экологической разработки Vue, вы будете правы.Pinia
Библиотека управления состоянием должна быть услышана или использована.Если вы еще не прикоснулись к Pinia, эта статья поможет вам быстро приступить к работе и узнать, как инкапсулировать и более элегантно использовать ее в корпоративных проектах.
В этой статье сначала объясняется, как понимать и использовать Pinia, и, наконец, как интегрировать Pinia в проект, что подходит для большинства читателей.Что касается передовой науки, такой как изучение исходного кода Pinia, будет подробно раскрыта другая статья. Кроме того, все демки в этой статье специально открываютсяGitHub-проектЧтобы сэкономить, нуждающиеся учащиеся могут снять его и попрактиковаться. 🌹🌹
Познакомьтесь с Пинией
Pinia
Произношение: ['piːnə], которое вместо этого рекомендуется официальной командой Vue.Vuex
Облегченная библиотека управления состоянием.Первоначально он был разработан с идеей, что Vue Store будет иметьComposition APIОн одновременно поддерживает Option API версии Vue2.x и режим разработки API-интерфейса настройки версии Vue3 и полностью совместим с методом написания Typescript (это также один из важных факторов, превосходящих Vuex). подходит для всех проектов vue.
По сравнению с Vuex у Pinia есть следующие преимущества:
- Полная поддержка TypeScript: добавить TypeScript проще, чем добавить TypeScript в Vuex.
- Чрезвычайно легкий (размером около 1 КБ)
- Действия хранилища отправляются как обычные вызовы функций, а не с использованием метода диспетчеризации или помощника MapAction, который распространен в Vuex.
- Поддержка нескольких магазинов
- Поддержка Vue devtools, разделения кода SSR и webpack.
Механизм разделения кода Pinia и Vuex
Часть вышеупомянутой легкости Pinia отражена в ее механизме разделения кода.
Например: проект имеет3 магазина "пользователь, работа, оплата", в дополнение к2 страницы маршрутизации "домашняя страница, персональная центральная страница",Домашняя страница использует хранилище вакансий, а страница личного центра использует хранилище пользователей., используйте Pinia и Vuex для управления их состоянием соответственно.
Сначала посмотрите на разделение кода Vuex:При упаковке vuex объединяет и упаковывает три хранилища.Когда домашняя страница использует Vuex, этот пакет будет введен на домашнюю страницу и упакован вместе, и, наконец, будет выведен фрагмент js. Проблема в том, что, по сути, на главной странице нужен только один из магазинов, но два других несвязанных магазина тоже запакованы, что приводит к пустой трате ресурсов.
Разделение кода для Pinia:При упаковке Pinia будет проверять эталонные зависимости.Когда домашняя страница использует хранилище заданий, упаковка будет объединять только используемый магазин и страницу для вывода одного js-чанка, а два других хранилища в нем не связаны. Pinia может это сделать, потому что ее конструкция предусматривает разделение магазина, что решает проблему сопряжения проектов.
Общее использование Пинии
Без лишних слов, приступайтеPinia
«В этой статье по умолчанию используется режим разработки Composition API Vue3».
Если вы знакомы с Pinia, можете пропустить эту часть👻
1. Установка
yarn add pinia
# or with npm
npm install pinia
2. Смонтируйте глобальный экземпляр
import { createPinia } from 'pinia'
app.use(createPinia())
3. Создайте первый магазин
существуетsrc/store/counterForOptions.ts
Создайте свой магазин. Определено 2 типа режимов хранения:
-
Используйте определение режима API параметров, которое похоже на компонентную модель vue2, а также является более дружественным режимом программирования для разработчиков стека технологий vue2.
import { defineStore } from 'pinia'; // 使用options API模式定义 export const useCounterStoreForOption = defineStore('counterForOptions', { // 定义state state: () => { return { count1: 1 }; }, // 定义action actions: { increment() { this.count1++; } }, // 定义getters getters: { doubleCount(state) { return state.count1 * 2; } } });
-
Используйте определение режима установки, которое соответствует режиму программирования установки Vue3, чтобы сделать структуру более плоской.Я лично рекомендую этот метод.
import { ref } from 'vue'; import { defineStore } from 'pinia'; // 使用setup模式定义 export const useCounterStoreForSetup = defineStore('counterForSetup', () => { const count = ref<number>(1); function increment() { count.value++; } function doubleCount() { return count.value * 2; } return { count, increment, doubleCount }; });
Приведенные выше два определения имеют одинаковый эффект, мы используемdefineStore
Метод определяет хранилище, которое определяет по 1 каждомуcount
состояние, 1increment
действие и 1doubleCount
добытчики. Состояние — это глобальное состояние для совместного использования, действие — это запись, которую деловая сторона вызывает для изменения состояния, а геттеры — это результаты вычисления состояния.
Причина, по которой он определяется первым способом, состоит в том, чтобы дополнительно написатьgetters
,action
ключевое слово для различения, потому что в режиме API опций его можно передать черезmapState()
,mapActions()
и другие способы получения соответствующего предмета, но второй способ можно получить напрямую (подробно описан ниже).
4. Бизнес-компонент вызывает магазин
существуетsrc/components/PiniaBasicSetup.vue
Создайте компонент в каталоге.
<script setup lang="ts" name="component-PiniaBasicSetup">
import { storeToRefs } from 'pinia';
import { useCounterStoreForSetup } from '@/store/counterForSetup';
// setup composition API模式
const counterStoreForSetup = useCounterStoreForSetup();
const { count } = storeToRefs(counterStoreForSetup);
const { increment, doubleCount } = counterStoreForSetup;
</script>
<template>
<div class="box-styl">
<h1>Setup模式</h1>
<p class="section-box">
Pinia的state: count = <b>{{ count }}</b>
</p>
<p class="section-box">
Pinia的getters: doubleCount() = <b>{{ doubleCount() }}</b>
</p>
<div class="section-box">
<p>Pinia的action: increment()</p>
<button @click="increment">点我</button>
</div>
</div>
</template>
<style lang="less" scoped>
.box-styl {
margin: 10px;
.section-box {
margin: 20px auto;
width: 300px;
background-color: #d7ffed;
border: 1px solid #000;
}
}
</style>
- Механизм вызова Pinia в режиме настройки:Сначала установите, а потом звоните.
- установка пишется так:
const counterStoreForSetup = useCounterStoreForSetup();
,вuseCounterStoreForSetup
это переменная, которую вы определяете для хранения;
- назовите это напрямую
counterStoreForSetup.xxx
(xxx включает в себя: состояние, геттеры, действие) просто отлично. - Состояние получается в коде путем деструктурирования присваивания.Чтобы сохранить отзывчивый характер состояния, необходимо использовать
storeToRefs
обернуть.
Метод вызова Options API, совместимый с Vue2, можно найти по адресуздесь.
5. Хорошие привычки программирования
Изменение состояния передается действию для обработки:Вышеприведенный пример,counterStoreForSetup
Существует свойство экземпляра pinia, называемое$state
Можно напрямую изменить значение состояния, но делать это не рекомендуется. Один сложно поддерживать, в случае многих компонентов, если будет сделано скрытое изменение состояния, вся команда разработчиков поможет вам проверить, другой — уничтожить пакет магазина, который трудно пересадить в другие места. Так что ради вашей репутации и безопасности, пожалуйста, прекратите программировать за пределами своей родины😇😇.
Используйте хуки вместо свойств экземпляра pinia:после установкиcounterStoreForSetup
В объекте много$
Методы в начале, на самом деле, большинство из этих методов можно ввести и заменить хуками.
Другие мысли, чтобы добавить...
Стратегия упаковки корпоративных проектов
Глобальная регистрационная машина
Проблема дублирования упаковки
В приведенном выше примере мы можем знать, что при использовании хранилища мы должны сначала импортировать определение хранилища, а затем выполнить функцию определения, чтобы создать его экземпляр. Однако после того, как проект станет больше, нужно ли создавать каждый компонент при его использовании? Как упоминалось в начале статьи, механизм разбиения кода pinia заключается в объединении и упаковке страниц, которые на него ссылаются.В следующем примере будет проблема, на пользователя ссылаются несколько страниц, и, наконец, хранилище пользователя упаковано. неоднократно.Для решения этой проблемы мы можем ввести«Глобальная регистрация»Концепция чего-либо. Метод заключается в следующем:
Создать общую запись
существуетsrc/store
Создать запись в каталогеindex.ts
, который содержит функцию регистрацииregisterStore()
, его роль заключается в том, чтобы заранее зарегистрировать хранилище всего проекта и, наконец, повесить все экземпляры хранилища наappStore
Передайте это. Таким образом, если мы хотим использовать pinia в любом компоненте проекта, нам нужно только импортировать appStore и взять соответствующий экземпляр магазина.
// src/store/index.ts
import { roleStore } from './roleStore';
import { useCounterStoreForSetup } from '@/store/counterForSetup';
import { useCounterStoreForOption } from '@/store/counterForOptions';
const appStore: any = {};
/**
* 注册app状态库
*/
export const registerStore = () => {
appStore.roleStore = roleStore();
appStore.useCounterStoreForSetup = useCounterStoreForSetup();
appStore.useCounterStoreForOption = useCounterStoreForOption();
};
export default appStore;
регистрация автобуса
существуетsrc/main.ts
Шина проекта выполняет операцию регистрации:
import { createApp } from 'vue';
import App from './App.vue';
import { createPinia } from 'pinia';
import { registerStore } from '@/store';
const app = createApp(App);
app.use(createPinia());
// 注册pinia状态管理库
registerStore();
app.mount('#app');
Прямое использование в бизнес-компонентах
// src/components/PiniaBasicSetup.vue
<script setup lang="ts" name="component-PiniaBasicSetup">
import { storeToRefs } from 'pinia';
import appStore from '@/store';
// setup composition API模式
const { count } = storeToRefs(appStore.useCounterStoreForSetup);
const { increment, doubleCount } = appStore.useCounterStoreForSetup;
</script>
<template>
<div class="box-styl">
<h1>Setup模式</h1>
<p class="section-box">
Pinia的state: count = <b>{{ count }}</b>
</p>
<p class="section-box">
Pinia的getters: doubleCount() = <b>{{ doubleCount() }}</b>
</p>
<div class="section-box">
<p>Pinia的action: increment()</p>
<button @click="increment">点我</button>
</div>
</div>
</template>
Упаковка и развязка
Здесь недостаточно, чтобы позволитьappStore
Экземпляр отделен от проекта, иappStore
Извлечено в общедоступный блок, вvite.config.ts
Выполните следующую настройку
export default defineConfig(({ command }: ConfigEnv) => {
return {
// ...其他配置
build: {
// ...其他配置
rollupOptions: {
output: {
manualChunks(id) {
// 将pinia的全局库实例打包进vendor,避免和页面一起打包造成资源重复引入
if (id.includes(path.resolve(__dirname, '/src/store/index.ts'))) {
return 'vendor';
}
}
}
}
}
};
});
После этой инкапсуляции государственная библиотека pinia отделяется, и окончательная схема структуры проекта выглядит следующим образом:
2. Управление группой магазинов
Анализ сценария
Вы часто сталкиваетесь с ситуацией, когда методу необходимо обновить несколько хранилищ в вашем проекте? Например: если вы хотите сделать игру, есть 3 профессии "воин, маг, даосский жрец", кроме того, у персонажа игрока есть 3 магазина для управления "атрибутами персонажа, экипировкой, навыками", есть "перенос" кнопку на странице, вы можете перенести другие профессии. Когда игрок меняет карьеру, необходимо изменить состояние трех магазинов, как это сделать?
- Способ 1. Создайте функцию в бизнес-компоненте и нажмите «Перенести», чтобы получить 3 магазина и обновить их значения.
- Способ 2:абстрактный новый магазин пиния, В магазине есть акция "перевод" Когда игрок меняет карьеру, отреагируйте на это действие и обновите значения 3х магазинов в акции.
Напротив, независимо от инкапсуляции или разделения бизнеса, метод 2 явно лучше. Для этого он также выигрывает от независимой функции управления хранилищем пинии.Нам нужно только использовать абстрактное хранилище в качестве родительского хранилища и три хранилища «атрибутов персонажа, снаряжения и навыков» в качестве хранилища единиц, и пусть действия родительского хранилища управляют ими.
Создание магазина на уровне группы
Продолжить по талантам, родительский магазин:src/store/roleStore/index.ts
import { defineStore } from 'pinia';
import { roleBasic } from './basic';
import { roleEquipment } from './equipment';
import { roleSkill } from './skill';
import { ROLE_INIT_INFO } from './constants';
type TProfession = 'warrior' | 'mage' | 'warlock';
// 角色组,汇聚「人物属性、装备、技能」3个store统一管理
export const roleStore = defineStore('roleStore', () => {
// 注册组内store
const basic = roleBasic();
const equipment = roleEquipment();
const skill = roleSkill();
// 转职业
function changeProfession(profession: TProfession) {
basic.setItem(ROLE_INIT_INFO[profession].basic);
equipment.setItem(ROLE_INIT_INFO[profession].equipment);
skill.setItem(ROLE_INIT_INFO[profession].skill);
}
return { basic, equipment, skill, changeProfession };
});
Единичный магазин
3-местный магазин:
вызов бизнес-компонента
<script setup lang="ts" name="component-StoreGroup">
import appStore from '@/store';
</script>
<template>
<div class="box-styl">
<h1>Store组管理</h1>
<div class="section-box">
<p>
当前职业: <b>{{ appStore.roleStore.basic.basic.profession }}</b>
</p>
<p>
名字: <b>{{ appStore.roleStore.basic.basic.name }}</b>
</p>
<p>
性别: <b>{{ appStore.roleStore.basic.basic.sex }}</b>
</p>
<p>
装备: <b>{{ appStore.roleStore.equipment.equipment }}</b>
</p>
<p>
技能: <b>{{ appStore.roleStore.skill.skill }}</b>
</p>
<span>转职:</span>
<button @click="appStore.roleStore.changeProfession('warrior')">
战士
</button>
<button @click="appStore.roleStore.changeProfession('mage')">法师</button>
<button @click="appStore.roleStore.changeProfession('warlock')">
道士
</button>
</div>
</div>
</template>
<style lang="less" scoped>
.box-styl {
margin: 10px;
.section-box {
margin: 20px auto;
width: 300px;
background-color: #d7ffed;
border: 1px solid #000;
}
}
</style>
Эффект
Закрытие
Для проекта важную роль играет хорошая схема управления статусами, которая не только делает проектное мышление ясным, но и облегчает сопровождение и итерацию проекта в будущем.
Портал проектов
Напоследок еще раз упомяну, что все демки в этой статье специально открываются.GitHub-проектЧтобы сэкономить, нуждающиеся учащиеся могут снять его и попрактиковаться. 🌹🌹