предисловие
Приехал Vue3,и новая версия Vuex тоже в бете.Прежде чем применить в проекте,пришлось сначала сдать воду.Я так разозлился,что чуть комп не разбил.Зачем ломать,начнем текст. ..
Установить
npm init vite-app vue3-vuex-ts
npm install
начать текст
1. Преобразуйте файл js в файл ts
- main.js -> main.ts
- Измените тип скрипта в файле vue на lang = "ts"
- Изменить index.html
<script type="module" src="/src/main.ts"></script>
2. Создайте объявление файла vue
- В среде ts нет объявления модуля vue
- Создайте файл vue.d.ts в src
declare module '*.vue' {
import { FunctionalComponent, defineComponent } from 'vue';
const component: ReturnType<typeof defineComponent> | FunctionalComponent;
export default component;
}
доступ к vuex
npm install vuex@next --save
установка, поговорим о vuex
Почему vuex2 может выполнять двустороннюю привязку?
let Vue;
class Store {
constructor(options) {
const { getters, state, mutations, actions } = options;
this._mutations = mutations;
this._actions = actions;
if (getters) {
this.handleGetters(getters);
}
this._vm = new Vue({
data: {
$$state: state,
},
});
this.commit = this.commit.bind(this);
this.dispatch = this.dispatch.bind(this);
}
get state() {
return this._vm.data.$$state;
}
commit(type, payload) {
const entry = this._mutations[type];
if (entry) {
entry(this.state, payload);
}
}
dispatch(type, payload) {
const entry = this._actions[type];
if (entry) {
entry(this, payload);
}
}
handleGetters(getters) {
this.getters = {};
Object.keys(getters).forEach(key => {
Object.defineProperty(this.getters, key, {
get: () => getters[key](this.state),
});
});
}
}
function install(_Vue) {
Vue = _Vue;
Vue.mixin({
beforeCreate() {
if (this.$options.store) {
Vue.prototype.$store = this.$options.store;
}
},
});
}
export default {
Store,
install,
};
- vuex сильно привязывает Vue (будет отслеживать данные new vue), поэтому vux не может использоваться другими штатами в качестве инструмента состояния.
- Повесьте $store на цепочку прототипов Vue через beforeCreate Vue.mixin Никакого выдувания, никакого распыления: Vue не может быть переработан, все состояния не могут быть переработаны, и все плагины Vue не могут быть переработаны. Каждый раз, когда вы используете компонент, вы проходите цепочку прототипов.В процессе рендеринга vue функция beforeCreate будет выполняться бесчисленное количество раз 😓
vuex3
- Используя реактивный и обеспечивающий двухстороннюю привязку, я не буду здесь вдаваться в подробности, но укажу на несколько ключевых моментов
store._state = reactive({
data: state
})
install (app, injectKey) {
app.provide(injectKey || storeKey, this)
app.config.globalProperties.$store = this
}
Будьте готовы приседать
1.main.ts
import { createApp } from 'vue';
import App from './App.vue';
import store from './store';
import './index.css';
createApp(App).use(store).mount('#app');
2. Создайте что-нибудь связанное с магазином
- index.ts
import { createStore } from 'vuex';
import modules from './modules';
import { userState } from './modules/user';
import { detailState } from './modules/detail';
export interface State {
user: userState;
detail: detailState;
}
export default createStore <
State >
{
modules,
};
- modules.ts
import user from './modules/user';
import detail from './modules/detail';
export default {
user,
detail,
};
- modules/user.ts
export type userState = {
isLogin: boolean,
};
const state: userState = {
isLogin: true,
};
export default {
namespaced: true,
state,
getters: {
loginInfo: (state: userState): string => {
return `${state.isLogin ? '已登陆' : '未登陆'}`;
},
},
mutations: {
setUserInfo(state: userState, payload: boolean): void {
console.log('数据请求', payload);
state.isLogin = payload;
},
},
actions: {
changeUserInfo({ commit }, payload: { data: boolean }): void {
console.log('action执行成功');
setTimeout(function () {
commit('setUserInfo', false);
}, 2000);
},
},
};
-
Detail.ts здесь опущен
-
HelloWorld.vue
<template>
<div>
<h1>{{ msg }}</h1>
<button @click="count++">count is: {{ count }}</button>
<div>{{ info1 }}</div>
<div>{{ info2 }}</div>
<button @click="logout">退出</button>
</div>
</template>
<script lang="ts">
import { useStore } from 'vuex';
import { defineComponent, computed } from 'vue';
import { State } from '../store';
export default defineComponent({
name: 'HelloWorld',
props: {
msg: String,
},
data() {
return {
count: 0,
};
},
setup(props) {
const { state, getters, dispatch, commit } = useStore<State>();
console.log('🍊', state.user.isLogin); // 🍊 true
console.log('🍎', state.detail.title); // 🍎 hello
console.log('🚀', getters['user/loginInfo']); // 🚀 已登陆
const info1 = computed(() => getters['user/loginInfo']);
const info2 = computed(() => getters['detail/detailInfo']);
const logout = () => commit('user/setUserInfo', false); // 数据请求 false
// dispatch()
return { info1, info2, logout };
},
});
</script>
Когда все закончилось, я чувствую себя таким милым 🐶
Нет.Нет.Нет, если командный проект это сделает, то предполагается, что мозги будут распроданы... 🤯
Это действительно конец?
- смотреть картинки и говорить
О, государство, я завернул слой, кончики грубые
Аксиба, какого черта, любого, у меня в это время сердце сжалось, не могу жаловаться...
Dispatch предлагает передать тип строкового типа, я знаю, что передать (коммит тоже является достоинством), так что я мог бы написать это напрямую в js.
Я столько предугадывал на ранней стадии, и оказалось, что надо передать тип строкового типа.Как я могу знать, что передать и оставить это на ts.В свою очередь, пусть я сделаю это сам.
Это как в клубе, прелюдия очень хорошая, а когда выходишь, то обнаруживаешь, что это кружево~ 😓
Должен ли я это сделать или я должен это сделать, безмолвный
начать восхождение
1. Исправить проблему с состоянием, modules/user.ts
const state = {
isLogin: true,
};
export type userState = typeof state;
export default {
// ....
};
Но это тоже не работает, я не могу обратиться к каждому состоянию компонента один раз, давайте сразу перейдем к следующему шагу.
2. Исправить проблему геттеров~
-
Vue обрабатывает состояние через такие хуки, как react, поэтому давайте также инкапсулируем целые хуки, useStore и исправим проблему в нем.
-
Необходимо предоставить комментарии, такие как «logininfo» в getters, отправка, коммитируют комментарии
-
- Пройдитесь по модулям, найдите все геттеры, действия, мутации и получите их тип
-
- раздать их через крючки
-
Изменить HelloWorld.vue
<script lang="ts">
// import { useStore } from 'vuex';
import { defineComponent, computed } from 'vue';
// import { State } from '../store';
import { useStoreHooks } from '../hooks';
export default defineComponent({
name: 'HelloWorld',
props: {
msg: String,
},
data() {
return {
count: 0,
};
},
setup(props) {
// const { state, getters, dispatch, commit } = useStore<State>();
const { state, getters, dispatch, commit } = useStoreHooks();
console.log('🍊', state.user.isLogin); // 🍊 true
console.log('🍎', state.detail.title); // 🍎 hello
console.log('🚀', getters['user/loginInfo']); // 🚀 已登陆
const info1 = computed(() => getters['user/loginInfo']);
const info2 = computed(() => getters['detail/detailInfo']);
const logout = () => commit('user/setUserInfo', false); // 数据请求 false
// dispatch()
return { info1, info2, logout };
},
});
</script>
- Создать хуки/index.ts
import { useStore } from 'vuex';
import { State } from '../store';
// 这几个玩意的type
import { Getters, Dispatch, Commit } from './utils';
interface UseStoreHooks {
state: State;
getters: Getters;
commit: Commit;
dispatch: Dispatch;
}
const useStoreHooks = (): UseStoreHooks => {
const store = useStore<State>();
console.log(store);
// return store;
// 自定义的进行输出结果
const { state, getters, dispatch, commit }: UseStoreHooks = store;
return {
state,
getters,
commit,
dispatch,
};
};
export { useStoreHooks };
export default useStoreHooks;
- hooks/utils.ts
-
- Пишите типа, это дело не js, каждый абзац нужно читать снизу вверх
-
- Установите последний машинописный текст, добавьте пряжу typescript@next (в настоящее время)
-
- vscode переключение версии TypeScrit
/* 拿到store的modules */
import modules from '../store/modules';
/* 获取到 getters 结构类型 */
// 匹配到 单个module 下的 getter,小技巧 infer 为某一项
type GetGetter<GetterType> = GetterType extends { getters: infer G } ? G : unknown;
// 获取 vuex 所有的 getters 模块
type GetGetters<GetterTypes> = {
[K in keyof GetterTypes]: GetGetter<GetterTypes[K]>;
};
type ModuleGetters = GetGetters<typeof modules>;
// --------------------
/* 获取到 mutations 结构类型 */
// 配到 单个 module 下的 mutations
type GetMutation<MutationType> = MutationType extends { mutations: infer M } ? M : unknown;
// 获取 vuex 所有的 mutations 模块
type GetMutations<MutationTypes> = {
[K in keyof MutationTypes]: GetMutation<MutationTypes[K]>;
};
type ModuleMutations = GetMutations<typeof modules>;
// --------------------
/* 获取到 actions 结构类型 */
// 配到 单个 module 下的 action
type GetAction<ActionType> = ActionType extends { actions: infer A } ? A : unknown;
// 获取 vuex 所有的 actions 模块
type GetActions<ActionTypes> = {
[K in keyof ActionTypes]: GetAction<ActionTypes[K]>;
};
type ModuleActions = GetActions<typeof modules>;
// --------------------
/* Getter/Commit/Dispatch 智能提示处理 */
// gettters[模块名/方法]、commit[模块名/方法]、dispatch[模块名/方法]
// ts4.1 以上支持 模板字符串语法,需要安装最新的 yarn typescript(目前yarn add typescript@next)
// 传入的是 keyof 有可能是symbol | number,所以 P & string 取其中的string
type AddPrefix<P, K> = `${P & string}/${K & string}`;
// 调换一下顺序:user: "user/loginInfo" => "user/loginInfo": user
type GetSpliceKey<Module, Key> = AddPrefix<Key, keyof Module>
/**
* { 'user/loginInfo': () => {} }
*/
// type GetSpliceKeys<Modules> = {
// [K in keyof Modules]: GetSpliceKey<Modules[K], K>
// }
// type xx = GetSpliceKeys<ModuleGetters>
type GetSpliceKeys<Modules> = {
[K in keyof Modules]: GetSpliceKey<Modules[K], K>
}[keyof Modules]
// type xx = GetSpliceKeys<ModuleGetters>
type GetFunc<T, A, B> = T[A & keyof T][B & keyof T[A & keyof T]];
type GetSpliceObj<T> = {
// K extends `${infer A}/${infer B}` 相当于 user/loginInfo A=>user B=>loginInfo
[K in GetSpliceKeys<T>]:K extends `${infer A}/${infer B}` ? GetFunc<T, A, B> : unknown
}
// --------------------
/* Getters/Mutations/Actons 拼接好 xxx/xxx 的格式 */
type GenGetters = GetSpliceObj<ModuleGetters>;
type Getters = {
[K in keyof GenGetters]:ReturnType<GenGetters[K]>
}
// --------------------
type GenMutations = GetSpliceObj<ModuleMutations>;
type Mutations = {
[K in keyof GenMutations]:ReturnType<GenMutations[K]>
}
// --------------------
type GenActions = GetSpliceObj<ModuleActions>;
type Actions = {
[K in keyof GenActions]:ReturnType<GenActions[K]>
}
// --------------------
// commit 获取 payload 参数类型
type MutationsPayload = {
// Parameters 获取函数参数
[K in keyof GenMutations]:Parameters<GenMutations[K]>[1]
}
interface GetCommit<T> {
// 可选参数类型,会自动加上undefined
<K extends keyof T>(mutation: K, payload?: T[K]): void;
}
type Commit = GetCommit<MutationsPayload>;
// --------------------
// dispatch 获取 payload 参数类型
type ActionPayload = {
// Parameters 获取函数参数
[K in keyof GenActions]:Parameters<GenActions[K]>[1]
}
interface GetDispatch<T> {
// 可选参数类型,会自动加上undefined
<K extends keyof T>(action: K, payload?: T[K]): Promise<unknown>;
}
type Dispatch = GetDispatch<ActionPayload>;
// --------------------
export {
Getters, Mutations, Actions, Dispatch, Commit
};
- взгляните на результаты
крючки, тип был получен в нем
Мой менталитет сломлен, я могу поймать добытчиков на крючок, но не могу вывести их наружу ~~
Как проснуться от сна, как всю жизнь
❤️ продырявлен
-
В тс можно, а во вью нет~
-
Ну, забирайте скриптовую часть, ничего страшного, терпение на исходе...
1. Поместите все части ts из HelloWorld.vue в HelloWorld.ts.
2. Измените HelloWorld.vue
<template>
<div>
<h1>{{ msg }}</h1>
<button @click="count++">count is: {{ count }}</button>
<div>{{ info1 }}</div>
<div>{{ info2 }}</div>
<button @click="logout">退出</button>
</div>
</template>
<script lang="ts" src="./HelloWorld.ts"></script>
- Перейдите на HelloWorld.ts, чтобы убедиться, что это, наконец, удалось
getters
commit
dispatch
Код этой статьи
конец
Глядя в окно, уже рассвело, и сигареты были докурены. Не рад, не грустен, устал...
Я действительно больше не могу учиться: я держу в руке зажигалку, где я не могу ее заказать, маме больше не нужно беспокоиться о моей учебе...
❤️ присоединяйтесь к нам
ByteDance · Команда счастья
Хороший лидер: старший технический эксперт, известный обозреватель Nuggets, основатель китайского сетевого сообщества Flutter, инициатор открытого проекта китайского сообщества Flutter, известный разработчик сообщества Github, автор многих известных проектов с открытым исходным кодом, таких как дио, муха, dsBridge
Мы с нетерпением ждем вашего присоединения и вместе используем технологии, чтобы изменить жизнь! ! !