vue + TS 使用的二三事

前言

离上一篇博客又过去了差不多10天的样子,然后上次里的flag又完美打脸了,主要是最近项目比较繁忙,所以也莫得时间整理,直到今天似乎闲了一点,于是决定随缘写篇博客。那就是分享在vue项目中使用ts的一些心得,这篇文章会长期不定期更新。

项目起手

从头配置ts项目比较困难,在这里我们可以使用vue脚手架自带的ts可选项,只要在新建项目时勾选ts,脚手架就可以自动帮我们完成相关配置,非常方便。

然后一路回车,等待几分钟,项目就好了。

这里会介绍vue中如何简单使用ts,想了解更多关于ts的知识,可以选择看看官方文档,当然,我其实挺觉得这个文档不是那么好懂,所以我推荐看这个入门,学习了更多TS的骚操作,你就可以玩的更Happy了。

下面先来讲讲一些常用功能的TS写法

组件写法

如图,组件的写法不再是导出一个对象,而是导出一个类,注意事项有两个,一个是要在类的上面使用Component装饰器装饰这个类,另一个是这个类要继承于Vue,这样就一个组件的声明就大功告成啦。接着我们来看看我们一些常用功能的写法。

数据

声明数据非常简单,你只需要使用下面的方法声明即可


export default class Parent extends Vue {
    // 声明数据
    name = SakuraSnow;
    age = 19;
}

该代码等效于


export default {
    date() {
        return {
           name : SakuraSnow,
           age : 19
       }
    }
}

当然这样就体现不出ts的优势了,你可以加点别的东西,比如数据类型和权限,


export default class Parent extends Vue {
    // 声明数据
    private readonly name = SakuraSnow;
    private readonly age = 19;
}

加上private和readonly后,这个属性就变成了私有属性,外部访问会报错,同时是只读的,想要修改它的值也会报错。(这里的报错均是指静态类型检查报错,要访问实际上还是可以访问的,要修改实际上也是可以修改的)

属性

声明会接收的属性需要使用Prop装饰器(从vue-property-decorator导入),可以传入一些配置项


export default class Parent extends Vue {
    // 声明会接收的属性
    @Prop({
        default() {
            return this is some message;
        },
        required : false
    })
    message : string | undefined;
}

以上代码等效于


export default {
    props : {
        message : {
           default() {
                return this is some message;
       },
           require : false
    }
    }
}

函数

直接把函数定义在类上即可


export default class Parent extends Vue {
    // 声明函数
    handleClick() {
        console.log(被点击了);
    }
}

该代码等效于


export default {
    methods : {
        handleClick() {
            console.log(被点击了)
        }
    }
}

计算属性

计算属性需要定义成一个访问器属性来使用,这不是TS的特有语法,在ES6的类中就已经出现。

export default class Parent extends Vue {
    private age = 19;
    // 声明一个计算属性
    get doubleAge() {
        return this.age * 2;
    }
    set doubleAge(val) {
        this.age = val / 2;
    }
}

该代码等效于


export default {
    data() {
        return {
            age : 16
        }
    },
    computed : {
        doubleAge : {
           get() {
               return this.age;
           },
           set(val) {
               this.age = val / 2;
           }
        }
    }
}

Watch

Watch需要使用Watch装饰器,同样要从 vue-property-decorator 导入


export default class Parent extends Vue {
    private age = 19;
    @Watch(age, {
        immediate : true
    })
    handleAgeUpdate(newVal : number, oldVal : number) {
        console.log(age的值更新了:, newVal, oldVal);
    }
}

该代码等效于


export default {
    data() {
        return {
            age : 16
            }
        },
    watch : {
        age : {
            handler(newVal, oldVal) {
        console.log(age的值更新了:, newVal, oldVal);
            },
            immediate : true
        }
    }
}

生命周期

直接定义方法即可


export default class Parent extends Vue {
    mounted() {
        console.log(挂载完成);
    }
}

等效于


export default {
    mounted() {
        console.log(挂载完成);
    }
}

想了解更多写法,点击这里查看文档]

vuex

首先我们需要先安装vuex-class

npm install vuex-class --save

不是module时

配置vuex

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
    state: {
        name : 'sena',
        age : 16
    },
    getters : {
        userInfo (state) {
            return {
                name : state.name,
                age : state.age
            }
        }
    },
    mutations: {
        updateName(state, payload) {
            state.name = payload;
        }
    },
    actions: {
        async updateNameAsync({commit}, payload) {
            setTimeout(() => {
                commit("updateName", payload)
            }, 3000)
        }
    },
})

在App.vue(可以是任何vue组件)中配置

import {Component, Prop, Vue, Watch} from "vue-property-decorator";
import {State, Getter, Action, Mutation, namespace} from 'vuex-class'

@Component({})
export default class App extends Vue {

    // root
    @State('name') vuexName : string;
    @State(state => state.age) vuexAge : number;
    @Getter('userInfo') vuexUserInfo : any;
    @Mutation('updateName') updateVuexName;
    @Action('updateNameAsync') updateVuexNameAsync;

    mounted() {
        // root
        console.log(this.vuexName);
        console.log(this.vuexAge);
        console.log(this.vuexUserInfo);

        // root
        setTimeout(() => {
            // commit
            console.log("修改name");
            this.updateVuexName("sakura");
            // dispatch
            console.log("4s后修改name");
            this.updateVuexNameAsync("snow");
        }, 1000);

    }

    @Watch("vuexName")
    watchVuexName(newVal) {
        console.log(`newVuexName更新为: ${newVal}`)
    }

}

运行结果
file

使用module时

配置vuex

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

export default new Vuex.Store({
    modules: {
        app : {
            namespaced : true,
            state : {
                appName : "app",
                a : 1,
                b : 2
            },
            getters : {
                appSum(state) {
                    return state.a + state.b;
                }
            },
            mutations : {
                updateAppName(state, payload) {
                    state.appName = payload;
                }
            },
            actions : {
                updateAppNameAsync({commit}, payload) {
                    setTimeout(() => {
                        commit("updateAppName", payload);
                    }, 3000)
                }
            }
        }
    }
})

在App.vue中配置

import {Component, Prop, Vue, Watch} from "vue-property-decorator";
import {State, Getter, Action, Mutation, namespace} from 'vuex-class'
const AppModule = namespace("app");
@Component({})
export default class App extends Vue {

    // app module
    @AppModule.State("appName") vuexAppName : string;
    @AppModule.Getter("appSum") vuexAppSum : number;
    @AppModule.Mutation("updateAppName") vuexUpdateAppName;
    @AppModule.Action("updateAppNameAsync") vuexUpdateAppNameAsync;

    mounted() {

        // app module
        console.log(this.vuexAppName);
        console.log(this.vuexAppSum);

        // app module
        setTimeout(() => {
            // commit
            console.log("修改appName");
            this.vuexUpdateAppName("sakura");
            // dispatch
            console.log("4s后修改appName");
            this.vuexUpdateAppNameAsync("snow");
        }, 1000);

    }

    @Watch("vuexAppName")
    watchVuexAppName(newVal) {
        console.log(`newVuexAppName更新为: ${newVal}`)
    }

}

运行结果
file

使用时的一些坑

导入图片报错


当你想引入某个本地图片时,发现ts会报个不能找到模块的错误,这是因为ts没有把图片识别成一个模块,所以需要一点声明,你可以在src下随便找个目录建个文件,后缀是.d.ts然后加上下面的代码


declare module '*.svg';
declare module '*.png';
declare module '*.jpg';
declare module '*.jpeg';
declare module '*.gif';
declare module '*.bmp';
declare module '*.tiff';


然后就不会报错了

在vue实例上挂自定义属性时会报错


在prototype上放了个$bus用作事件总线,然后使用时就会报错


没错,还是因为没有声明,后来我去element-ui的库里找到了它的声明文件,然后复制改了一下,就解决了这个问题。

同理随便建一个d.ts文件,然后导出一个声明,在上面定义你要的属性,然后就搞定了~

import vue from vue;
declare module 'vue/types/vue' {
    interface Vue {
        $bus : vue
    }
}

同理,如果你喜欢使用this.$http这种写法,你也可以整个这样的声明

后记

这篇文章从开写到发布,间隔一个月,其实这个月,我难得的很忙,项目每天脑壳疼,然后陷入人生的大思考,在一切告一段落后总算补完了这个博客,这个博客也会长期更新,因为项目还没完工2333,还可以记录很多东西,嘛,下次再见~

点赞

发表评论

昵称和uid可以选填一个,填邮箱必填(留言回复后将会发邮件给你)
tips:输入uid可以快速获得你的昵称和头像

Title - Artist
0:00