我的GitHub
0%

无星的前端之旅(一)-vue-自定义组件使用v-model.sync

背景:

正常情况下,vue是由父到子的单向数据流。但总会碰到一些操蛋的需求,想直接在子组件去修改对应数据。这时候就会发现,报警告️了。只能写子组件通知父组件修改对应数据,代码就又大又不优雅。

这时候就会想,v-model怎么实现的,自己封装的组件能不能用?还有没有别的方式。

于是乎有了这篇憨批文章。

其实相关文章也有很多了,但总觉得还是要自己总结一下比较好。

先上官网链接

自定义组件使用model

使用 JavaScript 代替模板功能

这里我想举好几个例子,但是又不知道怎么分点,因此我就随意分了

一.默认value和input的例子

子组件如下,test1.vue

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
39
40
41
42
43
44
45
46
47
48
49
50
51
<!--v-model:https://cn.vuejs.org/v2/api/#model-->
<template>
<div class="main">
<div @click="sub">
-
</div>
<input
v-model="value"
type="text"
style="width:160px"
@input="$emit('input', $event.target.value)"
/>
<!-- @input="$emit('input', $event.target.value)" -->
<div @click="add">
+
</div>
</div>
</template>

<script>
export default {
components: {},
props: {
value: {
type: [Number, String],
default: 0,
},
},
data: () => ({}),
computed: {},
watch: {},
// created() {},
mounted() {},
methods: {
add() {
// this.value = this.value + 1
this.$emit('input', Number(this.value) + 1)
},
sub() {
this.$emit('input', Number(this.value) - 1)
},
},
}
</script>
<style lang="less" scoped>
.main {
display: flex;
flex-direction: row;
}
</style>

父组件如下

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
<!---->
<!---->
<template>
<div class="main">
<Test1 v-model="nums1" />
<Test2 v-model="nums2" />
<p>num1:{{ nums1 }}</p>
<p>num2:{{ nums2 }}</p>
</div>
</template>

<script>
import Test1 from './test1.vue'
import Test2 from './test2.vue'
export default {
// import引入的组件需要注入到对象中才能使用
components: {
Test1,
Test2,
},
data: () => ({
nums1: 0,
nums2: 0,
}),
computed: {},
watch: {},
mounted() {},
// 方法集合
methods: {},
}
</script>
<style lang="less" scoped>
.main {
}
</style>


官网说明
从官网链接可以看到自定义组件,默认会把value这个key作为prop,默认有个input事件。(跟我用不用input这个dom没关系,可以换成<p></p>) 体现在代码中就是。

注释

效果如下图

演示
可以看到,跟随变化,且右边没有报警告

二.非默认值,自己写

因为value本身可能是某些组件的’关键字’,我们更需要的是能自定义的值

子组件test2.vue

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
39
40
41
42
<!--v-model:https://cn.vuejs.org/v2/api/#model-->
<template>
<div class="main">
<div @click="sub">
-
</div>
<p>{{ curvalue }}</p>
<div @click="add">
+
</div>
</div>
</template>

<script>
export default {
model: {
prop: 'curvalue',
event: 'updatecurvalue',
},
props: {
curvalue: {
type: [Number, String],
default: 0,
},
},
methods: {
add() {
this.$emit('updatecurvalue', Number(this.curvalue) + 1)
},
sub() {
this.$emit('updatecurvalue', Number(this.curvalue) - 1)
},
},
}
</script>
<style lang="less" scoped>
.main {
display: flex;
flex-direction: row;
}
</style>

如图

如上图,通过model下的prop接收对应的事件,去做当前值的绑定和当前值变更的事件绑定。

效果图

3.其实还有一种方式.sync

sync官方文档

test3.vue

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
<!--v-sync:https://cn.vuejs.org/v2/guide/components-custom-events.html#sync-%E4%BF%AE%E9%A5%B0%E7%AC%A6-->
<template>
<div class="main">
<div @click="sub">
-
</div>
<p>{{ curvalue }}</p>
<div @click="add">
+
</div>
</div>
</template>

<script>
export default {
props: {
curvalue: {
type: [Number, String],
default: 0,
},
},
methods: {
add() {
this.$emit('update:curvalue', Number(this.curvalue) + 1)
},
sub() {
this.$emit('update:curvalue', Number(this.curvalue) - 1)
},
},
}
</script>
<style lang="less" scoped>
.main {
display: flex;
flex-direction: row;
}
</style>

父组件

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
<!---->
<template>
<div class="main">
<Test3 :curvalue.sync="nums1" />
<p>num1:{{ nums1 }}</p>
</div>
</template>

<script>
import Test3 from './test3.vue'
export default {
// import引入的组件需要注入到对象中才能使用
components: { Test3 },
data: () => ({
nums1: 0,
nums2: 0,
}),
computed: {},
watch: {},
mounted() {},
// 方法集合
methods: {},
}
</script>
<style lang="less" scoped>
.main {
}
</style>

test3.vue
效果如下

如图

使用你封装的控件的人,一看到这个.sync就知道,肯定是绑定了。

我是阿星,阿星的阿,阿星的星!