vue cli3 + typescript 如何进行开发?以下是开发方式小记,还未配置的先看vue cli3+typescript 项目(配置篇)
组件开发:vue-property-decorator
在我们使用vue cli3
的vue create
命名创建了包含typescript依赖的项目之后,打开app.vue
,我们会发现以前熟悉的代码变样了:
<template>
<div id="app"></div>
</template>
<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
import HelloWorld from "./components/HelloWorld.vue";
@Component({
components: {
HelloWorld
}
})
export default class App extends Vue {}
</script>
可以看到项目自动引入了vue-property-decorator这个库,默认使用这个库来进行ts开发。
它把vue的语句用对应的“装饰器”或方法来实现,有以下装饰器/方法:
@Prop
@PropSync
@Model
@Watch
@Provide
@Inject
@ProvideReactive
@InjectReactive
@Emit
@Ref
-
@Component
(由 vue-class-component提供 ) -
Mixins
(the helper function namedmixins
provided by vue-class-component)(这是一个方法,不是一个装饰器)
这里挑常用的记录一下
数据定义
以前的:
<template>
<div>{{msg}}</div>
</template>
<script>
export default {
data() {
return {
msg: "这是一条测试数据"
};
}
};
</script>
<style lang="scss" scoped>
</style>
现在的:
<template>
<div class="hello">{{ msg }}</div>
</template>
<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
@Component
export default class HelloWorld extends Vue {
msg: string = "这是一条测试数据";
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss"></style>
组件与子组件
子组件传参用到@prop
装饰器:
以前的:
<template>
<div>{{msg2}}</div>
</template>
<script>
export default {
props: {
msg1: {
type: Number
},
msg2: {
type: string,
default: "default value"
},
msg3: {
type: string | boolean
}
}
};
</script>
<style lang="scss" scoped>
</style>
对应现在的:
<template>
<div class="hello">{{ msg2 }}</div>
</template>
<script lang="ts">
//引入Prop
import { Component, Prop, Vue } from "vue-property-decorator";
@Component
export default class HelloWorld extends Vue {
@Prop(Number) readonly msg1: number | undefined;
@Prop({ default: "default value" }) readonly msg2!: string;
@Prop([String, Boolean]) readonly msg3: string | boolean | undefined;
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss"></style>
父组件引用子组件的方式:
以前的
<template>
<div>
<HelloWorld :msg1="msg1" msg3="第二条信息"></HelloWorld>
</div>
</template>
<script>
import HelloWorld from "./components/HelloWorld.vue";
export default {
components: {
HelloWorld
},
data() {
return {
msg: 1
};
}
};
</script>
<style lang="scss" scoped>
</style>
对应现在的
<template>
<div id="app">
<HelloWorld :msg1="msg1" msg3="第二条信息"></HelloWorld>
</div>
</template>
<script lang="ts">
//引入Component
import { Component, Vue } from "vue-property-decorator";
import HelloWorld from "./components/HelloWorld.vue";
//使用装饰器声明
@Component({
components: {
HelloWorld
}
})
export default class App extends Vue {
msg1: number = 1;
}
</script>
监视 : watch
watch方法以前的:
<template>
<div>
<HelloWorld :msg1="msg1" msg3="第二条信息"></HelloWorld>
</div>
</template>
<script>
import HelloWorld from "./components/HelloWorld.vue";
export default {
components: {
HelloWorld
},
data() {
return {
msg: 1,
person: {
name: "Amy",
age: 11
}
};
},
watch: {
msg(newValue, oldValue) {},
person: {
hander(newValue, oldValue) {},
immediate: true,
deep: true
}
}
};
</script>
<style lang="scss" scoped>
</style>
对应现在的:
<template>
<div id="app">
<HelloWorld :msg1="msg1" msg3="第二条信息"></HelloWorld>
</div>
</template>
<script lang="ts">
//引入Watch
import { Component, Vue, Watch } from "vue-property-decorator";
import HelloWorld from "./components/HelloWorld.vue";
interface Person {
name: string;
age: number;
}
@Component({
components: {
HelloWorld
}
})
export default class App extends Vue {
msg1: number = 1;
person: Person = {
name: "Amy",
age: 11
};
//使用
@Watch("msg1")
onChildChanged(val: string, oldVal: string) {}
@Watch("person", { immediate: true, deep: true })
onPersonChanged1(val: Person, oldVal: Person) {}
mounted() {}
}
</script>
计算属性 computed
以前的:
<template>
<div>{{msg2}}</div>
</template>
<script>
export default {
props: {
msg1: {
type: Number
}
},
computed: {
msg2() {
return this.msg1*2
}
},
};
</script>
<style lang="scss" scoped>
</style>
等同于现在:
<template>
<div class="hello">{{ msg2 }}</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from "vue-property-decorator";
@Component
export default class HelloWorld extends Vue {
@Prop({ default: 1 }) readonly msg1!: number;
//设置计算属性,使用get
get msg2() {
return this.msg1 * 2;
}
}
</script>
事件:emit
emit事件的写法也有了不同
以前:
export default {
data() {
return {
count: 0
}
},
methods: {
addToCount(n) {
this.count += n
this.$emit('add-to-count', n)
},
resetCount() {
this.count = 0
this.$emit('reset')
},
returnValue() {
this.$emit('return-value', 10)
},
onInputChange(e) {
this.$emit('on-input-change', e.target.value, e)
},
promise() {
const promise = new Promise(resolve => {
setTimeout(() => {
resolve(20)
}, 0)
})
promise.then(value => {
this.$emit('promise', value)
})
}
}
}
现在:
import { Vue, Component, Emit } from 'vue-property-decorator'
//不解释了,官网例子
@Component
export default class YourComponent extends Vue {
count = 0
@Emit()
addToCount(n: number) {
this.count += n
}
@Emit('reset')
resetCount() {
this.count = 0
}
@Emit()
returnValue() {
return 10
}
@Emit()
onInputChange(e) {
return e.target.value
}
@Emit()
promise() {
return new Promise(resolve => {
setTimeout(() => {
resolve(20)
}, 0)
})
}
}
不过,直接使用以前的写法也是完全没有问题的。
过滤器:filter
过滤器用法和以前一样,无改变
mixin
mixin的写法:
以前的:
mixins写法:
const test = {
methods:{
test(str){
console.log(str)
}
}
}
export default test;
引入:
<template>
<div>{{ msg2 }}</div>
</template>
<script>
import test from "@/mixins/test";
export default {
mixins: [test],
props: {
msg1: {
type: Number
}
},
computed: {
msg2() {
return this.msg1 * 2;
}
},
mounted() {
this.test("这是一个mixins");
}
};
</script>
<style lang="scss" scoped></style>
等同于现在的:
mixins写法:
//test.ts
import { Vue, Component } from "vue-property-decorator";
@Component
export default class test extends Vue {
test(str: string) {
console.log(str);
}
}
mixins引入:
<template>
<div class="hello">{{ msg2 }}</div>
</template>
<script lang="ts">
import { Component, Prop, Vue, Mixins } from "vue-property-decorator";
import test from "@/mixins/test.ts";
//注意,不加Component无法引入
@Component
export default class HelloWorld extends Mixins(test) {
@Prop({ default: 1 }) readonly msg1!: number;
get msg2() {
return this.msg1 * 2;
}
mounted() {
this.test("这是一个mixins");
}
}
</script>
引入多个mixins:
<div class="hello">{{ msg2 }}</div>
</template>
<script lang="ts">
import { Component, Prop, Vue, Mixins } from "vue-property-decorator";
import test from "@/mixins/test.ts";
import test1 from "@/mixins/test1.ts";
@Component
export default class HelloWorld extends Mixins(test,test1) {
@Prop({ default: 1 }) readonly msg1!: number;
get msg2() {
return this.msg1 * 2;
}
mounted() {
this.test("这是一个mixins");
}
}
</script>
指令
指令的引入方式改变了
以前的引入方式:
<template>
<div>{{ msg2 }}</div>
</template>
<script>
import test from "@/mixins/test";
import clickfocus from "@/directives/clickfocus";
export default {
mixins: [test],
directives: { clickfocus },
props: {
msg1: {
type: Number
}
},
computed: {
msg2() {
return this.msg1 * 2;
}
},
mounted() {
this.test("这是一个mixins");
}
};
</script>
现在的:
<template>
<div class="hello">{{ msg2 }}</div>
</template>
<script lang="ts">
import { Component, Prop, Vue, Mixins } from "vue-property-decorator";
import test from "@/mixins/test.ts";
import clickfocus from "@/directives/clickfocus";
//引入指令
@Component({
directives: { clickfocus }
})
export default class HelloWorld extends Mixins(test) {
@Prop({ default: 1 }) readonly msg1!: number;
get msg2() {
return this.msg1 * 2;
}
mounted() {
this.test("这是一个mixins");
}
}
</script>
vuex 数据管理
vuex-class
使用vuex-class来进行vuex数据管理
安装:
npm i vuex-class -D
编辑store:
image.png//store例子:/store/modules/test.ts
const state: any = {
name: "测试store"
};
const mutations: any = {
setName(state: any, name: string) {
state.name = name;
}
};
const actions: any = {};
export default {
//namespaced为false的时候,state,mutations,actions全局可以调用
//为true,生成作用域,引用时要声明模块名称
namespaced: true,
state,
mutations,
actions
};
/store/index.ts
import Vue from "vue";
import Vuex from "vuex";
import testStore from "./modules/test";
Vue.use(Vuex);
export default new Vuex.Store({
modules: { testStore }
});
引用:
<template>
<div class="hello">{{ msg2 }}</div>
</template>
<script lang="ts">
import { Component, Prop, Vue, Mixins } from "vue-property-decorator";
import test from "@/mixins/test.ts";
import { State, Getter, Action, Mutation, namespace } from "vuex-class";
//使用namespace具名引入store
const testStore = namespace("testStore");
@Component
export default class HelloWorld extends Mixins(test) {
//导入store :testStore中state的name
@testStore.State(state => state.name) name: any;
@testStore.Mutation("setName") setName: any;
readonly msg1!: number;
get msg2() {
return this.msg1 * 2;
}
mounted() {
console.log(this.name);
this.setName("Jake");
console.log(this.name);
}
}
</script>
vuex-module-decorators
除了vuex-class,还可以使用vuex-module-decorators管理store
安装:
npm i vuex-module-decorators -D
store分模块:
//store/modules/test.ts
import { Module, VuexModule, Mutation } from "vuex-module-decorators";
@Module({ name: "testStore", namespaced: true })
export default class User extends VuexModule {
name = "测试store";
@Mutation
setRight(name: string) {
this.name = name;
}
}
//store/index.ts
import Vue from "vue";
import Vuex from "vuex";
import testStore from "./modules/test";
Vue.use(Vuex);
export default new Vuex.Store({
modules: { testStore }
});
引用:
<template>
<div class="hello">{{ testName }}</div>
</template>
<script lang="ts">
import { Component, Prop, Vue, Mixins } from "vue-property-decorator";
import test from "@/mixins/test.ts";
import store from "@/store";
import { getModule } from "vuex-module-decorators";
import testStore from "@/store/modules/test";
const test1: any = getModule(testStore, store);
@Component
export default class HelloWorld extends Mixins(test) {
//使用计算属性获取store变量,用来在模板中使用
get testName() {
return test1.name;
}
@Prop({ default: 1 })
readonly msg1!: number;
get msg2() {
return this.msg1 * 2;
}
mounted() {
console.log(test1.name);
//调用mutation方法
test1.setName("Amy");
console.log(test1.name);
}
}
</script>
如果你觉得这样做比较麻烦,也可以引用时通过vuex-class管理:
<template>
<div class="hello">{{ name}}</div>
</template>
<script lang="ts">
import { Component, Prop, Vue, Mixins } from "vue-property-decorator";
import test from "@/mixins/test.ts";
import { State, Getter, Action, Mutation, namespace } from "vuex-class";
//使用namespace具名引入store
const testStore = namespace("testStore");
@Component
export default class HelloWorld extends Mixins(test) {
//导入store :testStore中state的name
@testStore.State(state => state.name) name: any;
@testStore.Mutation("setName") setName: any;
readonly msg1!: number;
get msg2() {
return this.msg1 * 2;
}
mounted() {
console.log(this.name);
this.setName("Jake");
console.log(this.name);
}
}
</script>
效果一样
接口发送:axios
axios的安装配置看vue cli3+typescript 项目(配置篇)。
使用axios进行接口发送:
<template>
<div class="hello">{{ msg1}}</div>
</template>
<script lang="ts">
import { Component, Prop, Vue, Mixins } from "vue-property-decorator";
import test from "@/mixins/test.ts";
@Component
export default class HelloWorld extends Mixins(test) {
$get: any;
$post: any;
path: string = "api";
readonly msg1: number = 1;
get msg2() {
return this.msg1 * 2;
}
getData() {
this.$get(`${this.path}/getData`, {}).then((d: any) => {
//返回数据处理
});
}
postData() {
this.$post(`${this.path}/postData`, {}).then((d: any) => {
//返回数据处理
});
}
mounted() {
this.getData();
this.postData();
}
}
</script>
ts声明
关于ts声明,声明对象类型:
interface Data{
a:string,
b:number
}
对于需要有动态变量的对象,即键值名称不固定,声明如下:
interface Data{
[key: string]: any;
}
对于对象中非必有得值,声明中要加问号:
interface Data{
a:string,//必有,没有会报错
b?:number//非必有
}
对于你实在控制不了类型的变量,直接加any:
let a:any
网友评论