# TSX 笔记
# 特殊类型
# JSX-Element
const testElemeng: JSX.Element = <span class={className[test]}>{1}</span>;
# 待补充。。。
# 常用标签
# v-if
<template>
<div class="warpper">
<div class="content" v-if="hello">hello</div>
</div>
</template>
render() {
return (
<div class = 'wrapper'>
{
this.hello && (
<div class = 'content'>hello</div>
)
}
</div>
)
}
# v-if ,v-else
<template>
<div class="wrapper">
<div class="content1" v-if="hello">content1</div>
<div class="content2" v-else>content2</div>
</div>
</template>
render() {
return (
<div class= 'wrapper'>
{
this.hello ?
(<div class ='content1'></div>) :
(<div class= 'content2'></div>)
}
</div>
)
}
# v-for
<template>
<div class="wrapper">
<ul>
<li v-for="item in items" :key="item.id">{{ item.name }}</li>
</ul>
</div>
</template>
render() {
return (
<div class= 'wrapper'>
<ul>
{
this.items.map(item => (
<li>{ item.name }</li>
))
}
</ul>
</div>
)
}
# v-model
<Component v-model="test"></Component>
<component
value={this.test}
onInput={val => {
this.test = val;
}}
></component>
# v-html
render (createElement) {
return (
<button domPropsInnerHTML={htmlContent}></button>
)
}
# Ref
this.$refs.
Vue3写法
setup() {
const testRef = ref<null | HTMLElement>(null)
return () => (
<div ref={testRef}></div>
)
}
# watch
const isOutSide = ref(false) //必须为响应式对象
watch(
isOutSide,
(neval,oldval) => {
},
{
...options
}
)
# Emit
写法一致,或者使用装饰器写法,传参就是 return
# 生命周期
无需写在 methods
,也没有了整个概念
private mounted() {}
private created() {}
private beforeCreate() {}
private beforeMount() {}
private beforeUpdate() {}
private updated() {}
private beforeDestory() {}
private destoryed() {}
# Watch
使用装饰器,装饰器内传入变量名称
import { Watch } from 'vue-property-decorator'
...
private demo: any
...
@Watch('demo')
private watchDemoVal(newVal: any, oldVal: any) {
console.log(newVal, oldVal)
}
# 事件
大部分事件由之前的 @
(v-bind
写法) 转变成了 onChange
写法
<span onClick={(e: MouseEvent) => this.handleClick(e)}></span>
发布订阅事件
子组件
import { Emit } from 'vue-property-decorator'
...
// ? 装饰器写法如何传递参数
@Emit('test')
private test() {
console.log('1')
}
父组件
<parent onTest={this.handleTest}></parent>
这里仍然可以使用
this.$emit('eventName',params)
# 传参
合理使用展开运算符
render (createElement) {
const inputAttributes = {
class: 'input-field has-outline', // class definition
onClick: this.handleClick // event handler
backdrop: false // custom prop
}
const inputMarkup = this.multiline
? <textarea {...inputAttributes}></textarea>
: <input {...inputAttributes}/>
return inputMarkup
}
Prop
import { Vue, Component, Prop } from 'vue-property-decorator'
@Component
export default class YourComponent extends Vue {
@Prop(Number) readonly propA: number | undefined
@Prop({ default: 'default value' }) readonly propB!: string
@Prop([String, Boolean]) readonly propC: string | boolean | undefined
}
// 可以视为以下 vue2代码
props: {
propA: {
type: Number,
},
propB: {
default: 'default value',
},
propC: {
type: [String, Boolean],
},
},
# Vuex
Vuex3.x+ 搭配 TS 写法规范和使用技巧
# 规范写法
文件规范(⭐ (opens new window)⭐ (opens new window))
-- store
-- modules
-- moduleTest
-- index.ts
-- types.ts
-- action-types.ts
-- actions.ts
-- getters.ts
-- mutation-types.ts
-- mutations.ts
-- namespaces.ts
-- state-types.ts
-- state.ts
-- store.ts
以下可以认为是按照 Vuex官方
建议顺序使用 Vuex
入口文件 store.ts
import Vue from "vue";
import Vuex from "vuex";
import state from "./state";
import { mutations } from "./mutations";
import { actions } from "./actions";
import { getters } from "./getters";
import moduleTest from "./modules/modules/moduleTest";
Vue.use(Vuex);
// 全局注册
const store = new Vuex.Store({
state,
mutations,
actions,
getters,
modules: { moduleTest }
});
// 动态注册方法,Vuex(2.3.0+)可以用store.registerModule方法在进入路由时进行注册,离开路由时候销毁 actions, mutations, getters, state,在一定范围内相同名称不会被覆写
const moduleNameList = new Set<string>();
const registerModule = store.registerModule.bind(store);
// 模块名去重
store.registerModule = (name: any, m: any) => {
const moduleName: string = Array.isArray(name) ? name.join(".") : name;
if (moduleNameList.has(moduleName)) {
console.log(`警告: ${name}已经被注册过`);
}
moduleNameList.add(moduleName);
registerModule(name, m);
};
export default store;
state-types.ts
数据常量类型
export const testType = 'testType'
...
states.ts
Vuex 数据变量定义入口
import * as stypes from './state-types'
// 变量类型用接口表示
export interface State {
[stypes.testType] : boolean
...
}
// 定义 state 对象
const state: State = {
// 设置默认值
[stypes.testType]: true
}
export default state
getters.ts
Vuex 取数据语法糖
// 这里需要使用到GetterTree这个泛型改造
import { GetterTree } from 'vuex'
import * as stypes from './state-types'
import { State } from './state'
export const getters: GetterTree<State, any> = {
[stypes.testType](state: State) {
return state[stypes.testType]
}
...
}
使用
GetterTree
改造原因,Vuex 初始化规范的getters
类型如下export interface Module<S, R> { namespaced?: boolean; state?: S | (() => S); getters?: GetterTree<S, R>; actions?: ActionTree<S, R>; mutations?: MutationTree<S>; modules?: ModuleTree<R>; }
使用
getters
语法糖取state
数据import * as stypes from "./state-types"; import { Getter } from "vuex-class"; @Component({}) export default class extends Vue { @Getter(stypes.testType) // 这里一定要用变量接受,非空断言符号代表此变量一定有初值,如果不打就要给定初始值 private testType!: boolean; }
mutation-types
同步更新数据方法类型
export const testMutation = "testMutation";
mutations
同步更新数据方法
import { MutationTree } from 'vuex'
import * as mtypes from './mutation-types'
import * as stypes from './state-types'
import { State } from './state'
export const mutations: MutationTree<any> = {
[mtypes.testMutation](state: State,payload: any) {
state[stypes.testType] = payload
}
...
}
使用该同步方法
import { Mutation } from `vuex-class`; import { Component, Vue } from "vue-property-decorator"; import * as mtypes from "./mutattion-types"; @Component({}) export default class Test extends Vue { @Mutation(mtypes.testMutation) private testMutation!: (...args: any) => void; }
action-types.ts
批量同步或异步操作方法类型
export const testAction = "testAction";
actions.ts
批量同步或异步操作方法
import { Commit, ActionTree } from 'vuex'
import * as mtypes from './mutation-types'
import * as atypes from './action-types'
import { State } from './state'
import $http from './request'
export const actions: ActionTree<State, any> = {
[atypes.testAction](context: { commit: Commit }, data: any) {
context.commit(mtypes.testMutation,data)
}
// 异步操作
async [atypes.testAction](context: { commit: Commit }) {
const {data,code} = await $http.getList()
if(code === 200) {
context.commit(mtypes.testMutation, data || {})
}
}
}
使用方法
import { Component, Vue } from "vue-property-decorator"; import { Action } from "vuex-class"; import * as atypes from "./action-types"; @Component({}) export default class Test extends Vue { @Action(atypes.testAction) private testAction!: (...args: any) => void; }
# 分命名空间写法
store
入口添加模块import testModule from "./modules/testModule"; const state = new Vuex.store({ modules: { testMoudle } });
编写全局
namespace
,使用别名后可在全局引用对应方法,可视为模块装饰器import { namespace } from "vuex-class"; // namespace参数为注册模块名 export const testNamespace = namespace("testMoudle");
编写对应模块代码
--- moudles --- testModule --- index.ts --- types.ts ...
types.ts; import { ActionContext } from "vuex"; import { State } from "./state"; export const TEST_TYPE = "TEST_TYPE"; // 导出state类型 export interface TestMoudleState { [TEST_TYPE]: boolean; } // 后续定义actions需要用到 context的类型 export type TestMoudlActionType = ActionContext<TestMoudleState, State>;
index.ts import { TestMoudleState, TEST_TYPE } from './types' // state const state: TestMoudleState = { [TEST_TYPE]: true ... } // getters const getters = { [TEST_TYPE]: (gstate: TestMoudleState) => gstate ... } // actions const actions = { // 解构出commit [TEST_TYPE]: ({ commit }: TestMoudlActionType, val: boolean) => commit(TEST_TYPE, val) ... } // mutations const mutations = { [TEST_TYPE]: (mstate: TestMoudleState, val: boolean) => (mstate[TEST_TYPE] = val) } export default { state, getters, actions, mutations, namespaced: true }
使用技巧
import { testNamespace } from "./namespaces"; import { TEST_TYPE } from "./types"; @Component({}) export default class Test extends Vue { @testNamespace.Action(TEST_TYPE) public testType!: (...args: any) => void; @testNamespace.Getter(TEST_TYPE) private testType!: boolean; }
# 从新增接口到 vuex 进行通信的全过程写法
- 不分模块:
state-types
==>state
==>mutation-types
==>mutations
==>action-types
==>actions
- 分模块:
namespace
==>modules
==> 正常写 Vuex 步骤
# Vue-Router
写法基本一致,4.x
待学习
# 编写组件
编写一个组件模板
@Component({})
export default ComponentName extends Vue {
// 接受上层组件参数
@Prop({ddefault: ''})
private test!: string // 非空断言符
// 定义变量已知默认值
private test1: boolean = false
// 定义变量未知默认值
private test2!: boolean
// 接受Vuex states,actions type型
@Getter(stypes.testType)
private testType!: any
@Action(atypes.testAction)
private testAction!: (...args: any) => void
// 接受Vuex states, actions namespace型
@TestNamespace.Getter(TEST_TYPE)
private test-type!: booean
@TestNamespace.Action(TEST_TYPE)
private testType!: (val:boolean) => void
// 定义方法
private methodName():any {
}
// 生命周期钩子
...
// render TSX
private render() {
return (
<tag></tag>
)
}
}
# 坑点
# 阻止事件冒泡
<div
onClick={(e) => {
e.stopropagation()
this.handleClick()
}}
></div>
# 获取dom
setup() {
const eRef = ref<null | HTMLElement>(null)
}
# 动态class写法
<div style={{display: 'block'}}></div>
<div class={['class1',this.condition && class2,this.condition ? 'class1' : 'class2']}></div>
# slots
//parent.tsx
setup(props,{slots}) {
return () => slots.default()
}
// child.tsx
...
// use
<parent>
<child></child>
<child></child>
</parent>