对于前端的开发,我一直有在关注,Vue的写法有点多,是好事还是坏事,我也搞不懂了,几种写法我也都试了一试,可能是TS的原因,觉得并不是很完美,默认的写法对TS兼容性应该是最好的,兼容的场景还是蛮多的,但是监听自定义事件的时候,没有提示。

<script setup lang="ts">的写法监听自定义事件的提示十分友好,但这种写法访问子组件里的属性时也不友好。但是转念想一想,组件之间应该是独立的,况且Vue也提供了父子组件交互的方法,父组件直接操作子组件这种行为并不推荐。这种写法代码的简洁度很高,按常理来说,代码越少越易维护。自己斟酌。

我是期望前端发展如后端的springboot一样,写法规范统一起来,不管从维护上,还是开发上都能减少一些没有必要的工作量。

默认组合式API写法

响应式

简单的响应式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<template>
<h3>{{ name}}</h3>
<h3>{{sum}}</h3>
</template>
<script lang="ts">
import { defineComponent, toRefs, reactive, computed, watch, ref } from 'vue';

export default defineComponent({
name: 'HelloWorld',

setup() {
// 定义
const sum = ref(200)
const name = ref('hahahahah')
// 使用第一步
return {
sum,name
}

}
})
</script>

复杂的响应式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<template>
<!-- 使用 -->
<h3>{{user.name}}</h3>
<h3>{{user.age}}</h3>
<h3>{{user.sex}}</h3>
</template>
<script lang="ts">
import { defineComponent, toRefs, reactive, computed, watch, ref } from 'vue';

export default defineComponent({
name: 'HelloWorld',
setup() {
// 定义一个变量
const user = reactive({
name: '小红',
age: 23,
sex: '男'
})
// 导出才能在模板中使用
return {
user
}
}
})
</script>
<style scoped>
</style>

一些小妙招

不想在return中写太多的感觉没啥意义的代码,这时候我们就可以这样写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<template>
<!-- 使用 -->
<h3>{{ user.name }}</h3>
<h3>{{ user.age }}</h3>
<h3>{{ user.sex }}</h3>

<h3>{{ sum }}</h3>

<button type="button" @click="sunc('233')">按钮</button>
</template>
<script lang="ts">
import { defineComponent, toRefs, reactive, computed, watch, ref } from 'vue';
export default defineComponent({
name: 'HelloWorld',
setup() {
const data = reactive({
user: {
name: '小红',
age: 23,
sex: '男'
},
// 可以写任意变量,就不需要在return中写了
sum: 200,
// 函数也可以在这里面写
sunc(id:string):void {
console.log('id=' + id);
},
// 计算属性也可以在这里写,就不需要在return里面写很多代码了。
})
return {
// 解构导出,访问的时候不需要带上data
...toRefs(data)
}
}
})
</script>
<style scoped>
</style>

监听事件

关于监听的API还挺多的,这里不过多介绍,只介绍常见的。

简单的监听

1
2
3
4
5
6
7
8
9
setup() {
const fastName = ref('3222')
watch(fastName,(newVal,oldVal)=>{
console.log(newVal +'---'+oldVal);
})
return {
fastName
}
}

侦听一个Getter函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
setup() {
// 使用reactive定义的不能直接data.user.name来监听。
const data = reactive({
user: {
name: '小红',
age: 23,
sex: '男'
},
// 可以写任意变量,就不需要在return中写了
sum: 200
})
// 使用这种方式就是可以监听得到。
watch(() => data.user.name, (newVal, oldVal) => {
console.log(newVal + '---' + oldVal);
})
return {
// 解构导出,访问的时候不需要带上data
...toRefs(data)
}
}

监听多个源

1
2
3
4
5
6
7
setup() {
const fooRef = ref("foo")
const barRef = ref("bar")
watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => {
console.log('newVal = ' + foo+ '-' + bar+',,,oldVal' + prevFoo+ '-' + prevBar);
})
}

定义Props

简单的定义

父组件传值时会有类型校验。

1
2
3
4
5
6
7
8
9
10
11
12
export default defineComponent({
name: 'HelloWorld',
props: {
msg: {
type: String,

},
},
setup(props,ctx) {
}
})

高端的定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
interface Book {
title: string
author: string
year: number
}
export default defineComponent({
name: 'HelloWorld',
props: {
// 普通变量
msg: {
type: String,
// 默认值
default: () => ('这是默认值'),
// 校验
validator: (msg: String) => {
return msg.length > 3
}
},
// 对象变量
book: {
// 要使用PropType来定义变量
type: Object as PropType<Book>,
// 请务必使用箭头函数
default: () => ({
title: '这是一个错误'
}),
validator: (book: Book) => !!book.title
}
},
})

自定义事件

props和自定义事件都属于组件化常用的,自定义事件的历史包袱过重,在setup的写法中得到了解决,这个组合式API中没啥好的办法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 这里传入第二个参数
setup(props, ctx) {
const aaaa = reactive({
changeTaa() {
// 抛出事件,事件名为del
ctx.emit('del', 233)
},
})
return {
...toRefs(aaaa)
}
}


<!-- 监听部分 -->
<HelloWorld ref="model" @del="testEmit"/>

// 当在子组件中抛出事件此方法就会被触发,我们还可以用这个方法返回值来给子组件传递数据。工欲善其事必先利其器,半吊子很难的啦。

testEmit(id:string) {
console.log('自定义事件触发了');
console.log('id='+id);
}

到这,常用的组合式API的写法其实就已经差不多了。

封面

封面
封面