目前,对于Vue3来说,TypeScript的支持已经相当成熟,但公司的老项目一直处于迭代和维护无法从v2重构成v3,并且重构的成本也是很大的一个问题,所以记录一下vue2如何去搭配TypeScript。
目录
一、脚手架创建项目
二、vue-property-decorator
(1)变量
(2)方法
(3) watch
(4)计算属性
(5)生命周期
(6) 组件
(1)注册组件
(2) 父传子
(3)子传父
(7)ref引用
三、vuex-class
(1)全局使用
(2)模块化
四、mixin
一、脚手架创建项目
通过vue-cli进行安装
vue create v2ts
以下是脚手架的配置,仅供参考
二、vue-property-decorator
vue-property-decorator
是一个 Vue.js 的装饰器库,它提供了一些装饰器来让你在 Vue 组件中定义属性、计算属性、方法、事件等。使用这些装饰器可以让 Vue 组件的代码更加清晰简洁,同时也提高了代码的可读性和可维护性。
tip:引入Component是将类组件转换成Vue组件。
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'@Component
export default class HomeView extends Vue {}
</script>
(1)变量
由于使用的class-component,所以定义变量也是比较简单,只需要把变量写在class里,使用private和public可以更好的区分私有还是共有。
<template><div id="app">{{ a }}{{ b }}</div>
</template><script lang="ts">
import { Vue } from 'vue-property-decorator'
export default class HomeView extends Vue {private a = 1public b = 2
}
</script>
tip:注意 不要初始化不赋值或赋值为undefined,否则会识别不到这个变量,如果你只想定义这个变量也可以采取data函数的形式。
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'@Component
export default class HomeView extends Vue {data () {return {d: undefined}}
}
(2)方法
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
@Component
export default class HomeView extends Vue {private a = 1private add () {console.log(this.a)this.a++}
}
</script>
(3) watch
语法:
@Watch('监听属性', { immediate, deep })private 方法名 (新值,旧值) {console.log(v)}
示例:
<template><div id="app">{{ obj.a }}<button @click="add">+1</button></div>
</template><script lang="ts">
import { Component, Vue, Watch } from 'vue-property-decorator'@Component
export default class HomeView extends Vue {private obj = { a: 1 };private add () {this.obj.a++}@Watch('obj', { immediate: true, deep: true })private updateA (v: { a: number }) {console.log(v)}
}
</script>
(4)计算属性
计算属性 在方法名前 加一个get就好了
<template><div id="app">{{ obj.a }}<button @click="add">+1</button>{{ doubleA }}</div>
</template> <script lang="ts">
import { Component, Vue } from 'vue-property-decorator'@Component
export default class HomeView extends Vue {private obj = { a: 1 };private add () {this.obj.a++}get doubleA () {return this.obj.a * 2}
}
</script>
(5)生命周期
和之前区别不大 使用对应的函数名称
<script lang="ts">
@Component
export default class HomeView extends Vue {created () {console.log(123)}mounted () {console.log(456)}
}
</script>
(6) 组件
(1)注册组件
<template><div id="app"><Son /></div>
</template><script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import Son from '@/components/Son.vue'@Component({components: {Son}
})
</script>
(2) 父传子
父
<Son text="哈哈" />
子
<template><div>{{ text }}</div>
</template><script lang="ts">
import { Component, Vue, Prop } from 'vue-property-decorator'@Component
export default class Son extends Vue {@Prop({ type: String, default: '' }) text!:string
}</script>
(3)子传父
子
<template><div><button @click="emit">子传父</button></div>
</template><script lang="ts">
import { Component, Vue } from 'vue-property-decorator'@Component
export default class Son extends Vue {emit () {this.$emit('update', 123)}
}</script>
父
<template><div id="app"><Son @update="updateHandler"/></div>
</template><script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import Son from '@/components/Son.vue'@Component({components: {Son}
})
export default class HomeView extends Vue {updateHandler (val:number) {console.log(val, '接受了')}
}
</script>
也可以通过vue-property-decorator的形式 导出Emit 调用emit的方法即可
<template><div class="hello"><button @click="send">传值</button></div>
</template><script lang="ts">
import { Component, Vue, Emit } from 'vue-property-decorator'@Component
export default class HelloWorld extends Vue {@Emit()send ():number {return 20}
}
</script>
(7)ref引用
<template><div id="app">{{ a }}<Son ref="son" /></div>
</template><script lang="ts">
import Son from '@/components/Son.vue'
import { Component, Vue } from 'vue-property-decorator'interface SonComponent extends Vue {logHello: ()=>void
}@Component({components: { Son }
})
export default class App extends Vue {a = 1;mounted () {(this.$refs.son as SonComponent).logHello()}
}
</script>
三、vuex-class
为了更好的搭配vue-class-component 在使用vuex的时候可以安装 vuex-class 插件 帮助我们更好的使用装饰器开发
npm i vuex-class
(1)全局使用
store.ts
import Vue from 'vue'
import Vuex, { Commit } from 'vuex'Vue.use(Vuex)interface state {username: string
}export default new Vuex.Store({state: {username: 'default'},getters: {getUserName (state: state) {return '姓名' + state.username}},mutations: {SET_USERNAME (state: state, val: string) {state.username = val}},actions: {async requestUserName (context: { commit: Commit }, id: number) {const users = [{ id: 1, name: 'Ulrtraman' },{ id: 2, name: 'Monsters' }]return new Promise((resolve) => {setTimeout(() => {const username = users.find(it => it.id === id)?.namecontext.commit('SET_USERNAME', username)resolve(username)}, 1000);})}},modules: {}
})
组件调用:
<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
import { State, Mutation, Action, Getter } from "vuex-class";@Component
export default class Sister extends Vue {@State("username")private username!:string;@Mutation("SET_USERNAME")private setUserName!:(name:string) => void@Action("requestUserName")private requestUserName!:(id:number) => void@Getter("getUserName")private getUserName!:stringasync created () {// 获取state的usernameconsole.log(this.username);// 调用mutation的方法this.setUserName('abcd')// 调用actions的方法this.requestUserName(2)// 获取getterconsole.log(this.getUserName);}
}
</script>
四个模块的导入使用大致相同
@模块("模块的属性命名")private 新名字!:类型;
(2)模块化
在开发中模块vuex的场景还是比较多的 达到 清晰 易维护。
store/user/user.ts
import { Commit } from 'vuex';interface state {username: string
}const state: state = {username: 'default'
}const mutations = {SET_USERNAME (state: state, val: string) {state.username = val}
}const getters = {getUserName (state: state) {return '姓名' + state.username}
}const actions = {async requestUserName (context: { commit: Commit }, id: number) {const users = [{ id: 1, name: 'Ulrtraman' },{ id: 2, name: 'Monsters' }]return new Promise((resolve) => {setTimeout(() => {const username = users.find(it => it.id === id)?.namecontext.commit('SET_USERNAME', username)resolve(username)}, 1000);})}
}export default {state, getters, mutations, actions, namespaced: true
}
tip: 要加namespace 命名空间
store/index.ts
import Vue from 'vue'
import Vuex from 'vuex'
import user from './user/user'Vue.use(Vuex)export default new Vuex.Store({modules: {user}
})
组件调用:
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import { namespace } from 'vuex-class';const user = namespace('user');@Component({components: { Son, Sister }
})
export default class App extends Vue {@user.Stateprivate username!: number;@user.Mutationprivate SET_USERNAME!: (name:string) => void;@user.Actionprivate requestUserName!: (id:number) => void;@user.Getterprivate getUserName!: number;async beforeMount () {// stateconsole.log('state:', this.username);// getterconsole.log('getter:', this.getUserName);// mutationthis.SET_USERNAME('helloworld')// actionawait this.requestUserName(1);}
}
</script>
使用方法:
import { namespace } from 'vuex-class';
const 变量 = namespace('文件名');..@变量.模块private 新名字!: 类型;
四、mixin
src/mixins/mixin.ts
import { Component, Vue } from 'vue-property-decorator'@Component
export default class HelloWorld extends Vue {created () {console.log('mixin的created');}
}
使用mixin
<script lang="ts">
import { Component, Mixins } from 'vue-property-decorator'
import mixin from '@/mixins/mixin'@Component
export default class HelloWorld extends Mixins(mixin) {
}
</script>