目前,对于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 = 1
public 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 = 1
private 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)?.name
context.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!:string
async created () {
// 获取state的username
console.log(this.username);
// 调用mutation的方法
this.setUserName('abcd')
// 调用actions的方法
this.requestUserName(2)
// 获取getter
console.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)?.name
context.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.State
private username!: number;
@user.Mutation
private SET_USERNAME!: (name:string) => void;
@user.Action
private requestUserName!: (id:number) => void;
@user.Getter
private getUserName!: number;
async beforeMount () {
// state
console.log('state:', this.username);
// getter
console.log('getter:', this.getUserName);
// mutation
this.SET_USERNAME('helloworld')
// action
await 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>