Vue 进阶系列教程将在本号持续发布,一起查漏补缺学个痛快!若您有遇到其它相关问题,非常欢迎在评论中留言讨论,达到帮助更多人的目的。若感本文对您有所帮助请点个赞吧!
2013年7月28日,尤雨溪第一次在 GItHub 上为 Vue.js 提交代码;2015年10月26日,Vue.js 1.0.0版本发布;2016年10月1日,Vue.js 2.0发布。
最早的 Vue.js 只做视图层,没有路由, 没有状态管理,也没有官方的构建工具,只有一个库,放到网页里就可以直接用了。
后来,Vue.js 慢慢开始加入了一些官方的辅助工具,比如路由(Router)、状态管理方案(Vuex)和构建工具(Vue-cli)等。此时,Vue.js 的定位是:The Progressive Framework。翻译成中文,就是渐进式框架。
Vue.js2.0 引入了很多特性,比如虚拟 DOM,支持 JSX 和 TypeScript,支持流式服务端渲染,提供了跨平台的能力等。Vue.js 在国内的用户有阿里巴巴、百度、腾讯、新浪、网易、滴滴出行、360、美团等等。
Vue 已是一名前端工程师必备的技能,现在就让我们开始深入学习 Vue.js 内部的核心技术原理吧!
什么是vuex
vuex 是 vue 中用来做状态管理的一个仓库,一般较大型的项目才有必要使用它,因为如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。它主要包括state、mutations、actions、getters、modules 五个核心概念,有关具体的使用,我们这篇文章不做重点讲解,这里主要告诉大家如何在vuex中集成 typescript,做到代码提示功能。
最终效果预览
我们先看一下最终要达到的效果是什么样的:
1. 拿到 getters: 自动提示每个模块中定义的 getters,不用再回到定义的地方确认每一个 getters 的命名是否正确了
2. 调用 mutation:
3. 调用 actions
最终的效果就是,在我们输入引号的时候,编辑器会自动弹出提示,我们可以快速找到目标方法或者 getters 了,减少了代码出错的可能性。
实现步骤
1. 创建项目,选用 vue-ts 开发模版
npm init vite@latest
2. 引用 vuex
npm install vuex@next --save
3. 在 src 下新建 store 目录,然后 store 下新建 index.ts
// store.ts
import { InjectionKey } from 'vue'
import { createStore, useStore as baseUseStore, Store } from 'vuex'
// 引入tab模块
import tabs, { TabsState } from './modules/tabs'
// 引入menu模块
import menu, { MenuState } from './modules/menu'
// 引入vuex-ts自定义类型推断类,代码提示的核心
import { CommonStore } from './vuex_ts'
// 定义根级State类型
export type RootState = {
tabs: TabsState,
menu: MenuState
}
// 把多个模块聚合在一起
export const modules = {
tabs: tabs,
menu: menu
}
export const key: InjectionKey> = Symbol()
export const store = createStore({
modules
}) as CommonStore
// 定义自己的 `useStore` 组合式函数
export function useStore(): CommonStore {
return baseUseStore(key);
}
4. 在 store 文件夹下,新建 modules 文件夹,并新建两个 ts 文件,这里每个ts文件相当于一个 vuex 模块,分别是:tabs.ts、menu.ts
// menu.ts
import {RootState} from '@/store'
import { ActionContext } from 'vuex';
// 定义menu模块下的,state的类型
export type MenuState = {
count:number;
}
// 定义menu模块下的state
export const state: MenuState = {
count:0
}
// 定义menu模块下的mutations
export const mutations = {
setCount(state:MenuState, count:number):void{
state.count = count
}
}
// 定义menu模块下的actions
export const actions = {
setAsyncCount({commit}:ActionContext){
setTimeout(() => {
state.count++
}, 1000);
}
}
// 定义menu模块下的getters
export const getters = {
getCount(state:MenuState){
return state.count
}
}
export default {
namespaced:true, // 声明命名空间
state,
mutations,
actions,
getters
}
// tabs.ts
import { ActionContext } from "vuex"
import { RootState } from "@/store"
// 定义单个tab的类型
interface ITab{
title:string,
path:string
}
// 定义tabs模块下的,state的类型
export type TabsState = {
tabLists: Array
}
// 定义tabs模块下的state
export const state: TabsState = {
tabLists:[],
}
// 定义tabs模块下的mutations
export const mutations = {
addTab(state:TabsState, tab: ITab):void{
if(state.tabLists.some(item => item.path === tab.path)){return}
state.tabLists.push(tab);
}
}
// 定义tabs模块下的actions
export const actions = {
addAsyncTabs({commit}:ActionContext,tab:ITab){
if(state.tabLists.some(item => item.path === tab.path)){return}
state.tabLists.push(tab);
}
}
// 定义tabs模块下的getters
export const getters = {
getTabs(state:TabsState){
return state.tabLists
}
}
export default {
namespaced:true, // 声明命名空间
state,
mutations,
actions,
getters
}
5. 在store文件夹下,新建vuex_ts.ts文件
// vuex_ts.ts
import {modules,RootState} from './index'
import { CommitOptions, DispatchOptions, Store as VuexStore } from 'vuex'
// 获取modules的类型
type Modules = typeof modules
// 获取所有模块下的mutations
type GetMutation = T extends {mutations:infer G} ? G : never;
type GetMutations = {
[K in keyof T]:GetMutation
}
type mutationsObj = GetMutations
// 获取所有模块下的actions
type GetAction = T extends {actions:infer G} ? G : never;
type GetActions = {
[K in keyof T]:GetAction
}
type actionsObj = GetActions
// 获取所有模块下的getters
type GetGetter = T extends {getters:infer G} ? G : never;
type GetGetters = {
[K in keyof T]:GetGetter
}
type getterObj = GetGetters
// tabs/addTabs menu/setCount
type AddPrefix = `${prefix & string}/${keys & string}`
type GetKey = AddPrefix;
type Getkeys = {
[K in keyof T]:GetKey
}[keyof T];
type ss = Getkeys
// 获取当前模块下每个函数的返回值
type GetFunc = T[A & keyof T][B & keyof T[A & keyof T]]
type GetMethod = {
[K in Getkeys]:K extends `${infer A}/${infer B}` ? GetFunc : unknown
}
type GetMutationsFunc = GetMethod
type GetActionsFunc = GetMethod
type GetGettersFunc = GetMethod
// 去掉之前的,使用自己定义的
export type CommonStore = Omit, 'commit' | 'getters' | 'dispatch'> & {
commit[1]>(
key: K,
payload?: P,
options?: CommitOptions
): ReturnType
} & {
getters: {
[K in keyof GetGettersFunc]: ReturnType
}
} & {
dispatch(
key: K,
payload?: Parameters[1],
options?: DispatchOptions
): ReturnType
}
6. 代码目录:
这里给大家展示一下store文件夹下的代码目录,以便大家理解
效果查看
到这里,我们的vuex集成ts,生成代码提示就已经实现了,我们这里看下效果:
Vue 进阶系列教程将在本号持续发布,一起查漏补缺学个痛快!若您有遇到其它相关问题,非常欢迎在评论中留言讨论,达到帮助更多人的目的。若感本文对您有所帮助请点个赞吧!
叶阳辉
HFun 前端攻城狮
往期精彩:
Vue 进阶系列丨Object 的变化侦测
Vue 进阶系列丨Array 的变化侦测
Vue 进阶系列丨虚拟DOM和VNode
Vue 进阶系列丨Patch 和模板编译
Vue 进阶系列丨事件相关的实例方法
Vue 进阶系列丨生命周期相关的实例方法
Vue 进阶系列丨生命周期
Vue 进阶系列丨自定义指令
Vue 进阶系列丨最佳实践
Vue 进阶系列丨Mixin 混入
Vue 进阶系列丨权限控制 addRoute()
Vue 进阶系列丨插槽
Vue 进阶系列丨npm发布vue组件