0%

Vue:自定义组件的v-model

关于v-model的使用这件事

v-bind

v-bind可以把标签的某个属性和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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue-form</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="container">
<label>input
<input type="text" v-bind:value="text">
</label>
<p>{{ text }}</p>
</div>
</body>
<script>
const vm1 = new Vue({
el: '#container',
data: {
text: 'nothing to show'
}
});
</script>
</html>

效果:

如果我们在控制台去改变text的值,新的值会立即渲染到页面上:

但是反过来,如果在输入框改变input的valuetext并不会发生改变:

这就是所谓的单向绑定。那么如何实现双向绑定呢?

v-model

v-model可以用来实现双向绑定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue-form</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="container">
<label>input
<input type="text" v-model="text">
</label>
<p>{{ text }}</p>
</div>
</body>
<script>
const vm1 = new Vue({
el: '#container',
data: {
text: 'nothing to show'
}
});
</script>
</html>

初始效果:

改变输入框的值:

可以到变量textinputvalue已经牢牢地绑定在一起,不求同年同月同日生,但求同年同月同日死。

v-model到底做了些什么呢?

v-model本质是语法糖(没有v-model的时候可以通过更复杂一些的方法实现v-model的功能),他帮助我们做了两件事。

第一件事

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue-form</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="container">
<label>input
<input type="text" v-bind:value="text">
</label>
<p>{{ text }}</p>
</div>
</body>
<script>
const vm1 = new Vue({
el: '#container',
data: {
text: 'nothing to show'
}
});
</script>
</html>

v-bind将标签的value和指定变量单向绑定。

第二件事

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue-form</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="container">
<label>input
<input type="text" v-bind:value="text" v-on:input="text = $event.target.value">
</label>
<p>{{ text }}</p>
</div>
</body>
<script>
const vm1 = new Vue({
el: '#container',
data: {
text: 'nothing to show'
}
});
</script>
</html>

在第一步的基础上,用v-on监听input事件,进而通过JavaScript代码修改变量text的值,从而实现双向绑定。

在自定义组件上使用v-model

可见,使用v-model进行双向绑定很方便,但是,并非在任何情况下都可以直接使用v-model

一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,但是像单选框、复选框等类型的输入控件可能会将 value attribute 用于不同的目的。比如type=checkbox类型的input,应该去利用它的checked属性和change事件,这时就需要我们去使用model选项。

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue-form</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="container">
<base-checkbox v-model="choice"></base-checkbox>
<p>{{ choice }}</p>
</div>
</body>
<script>
Vue.component('base-checkbox', {
model: {
prop: 'checked',
event: 'change'
},
props: {
checked: Boolean
},
template: `<input type="checkbox" v-bind:checked="checked" v-on:change="$emit('change',$event.target.checked)">`
});

const vm1 = new Vue({
el: '#container',
data: {
choice: false
}
});
</script>
</html>

这样做即可实现双向绑定。

效果:

$emit(event,args)可以去触发一个事件并传入参数,如果有所迷惑,可以看下面的栗子:

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue-form</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="container">
<base-checkbox v-bind:checked="choice" v-on:change="sync"></base-checkbox>
<p>{{ choice }}</p>
</div>
</body>
<script>
Vue.component('base-checkbox', {
model: {
prop: 'checked',
event: 'change'
},
props: {
checked: Boolean
},
template: `<input type="checkbox" v-bind:checked="checked" v-on:change="$emit('change', $event.target.checked)">`
});

const vm1 = new Vue({
el: '#container',
data: {
choice: false
},
methods: {
sync: function (checked) {
console.log(checked);
// this指向当前Vue实例
this.choice = checked;
}
}
});
</script>
</html>

两种版本的效果完全一样,但通过对比,我们可以体会到v-model帮我们做了些什么。