关于v-model

Vue 里的双向绑定哈

参考链接

表单输入绑定
自定义组件的 v-model
Simple Todo App with Vue
vue.js 自定义组件上使用 v-model
关于 vue 组件 native 修饰
vue 自定义组件 v-model

一些说明

总听说 Vue 的双向绑定,真的看了好多文章才勉强理解了一点。
喜欢是不喜欢的,学还是要学的,下面的例子都是直接搬运的相关链接里的。

语法糖

v-model 就是 v-bind 和 v-on 配合使用的语法糖。

1
2
3
<input v-model="msg" />
<!-- 等同于 -->
<input :value="msg" @input="msg= \$event.target.value" />

基础使用

表单输入绑定

用于创建双向绑定。
主要分在表单上的使用以及在组件上的使用。

在 input/textarea/select 中的使用

v-model 会忽略所有表单元素的 value、checked、selected 特性的初始值而总是将 Vue 实例的数据作为数据来源。你应该通过 JavaScript 在组件的 data 选项中声明初始值。 – Vue 官网

  1. 在普通 input 以及 textarea 使用 value 属性并抛出 input 事件
  2. 在 checkbox 和 radio 使用 checked 属性和 change 事件
  3. 在 select 使用 value 属性和 change 事件
1
2
3
4
5
6
<!-- text -->
<input v-model="message" placeholder="edit me" />
<p>Message is: {{ message }}</p>
<!-- textarea -->
<p style="white-space: pre-line;">{{ message }}</p>
<textarea v-model="message" placeholder="add multiple lines"></textarea>

在普通的 input 以及 textaera 中直接使用 v-model 绑定需要的变量即可。

单个复选框可以绑定到布尔值

1
2
<input type="checkbox" id="checkbox" v-model="checked" />
<label for="checkbox">{{ checked }}</label>

若多个复选框要绑定到数组上

1
2
3
4
5
6
7
8
9
10
<div id="example-3">
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames" />
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames" />
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames" />
<label for="mike">Mike</label>
<br />
<span>Checked names: {{ checkedNames }}</span>
</div>
1
2
3
4
5
6
new Vue({
el: "#example-3",
data: {
checkedNames: []
}
});

最后 checkedNames 里的值会使选中的 checkbox 的 value。
单选框绑定的到字符串上。

1
2
3
4
5
6
7
<div id="example-4">
<input type="radio" id="one" value="One" v-model="picked" />
<label for="one">One</label>
<input type="radio" id="two" value="Two" v-model="picked" />
<label for="two">Two</label>
<span>Picked: {{ picked }}</span>
</div>
1
2
3
4
5
6
new Vue({
el: "#example-4",
data: {
picked: ""
}
});

单选 select 和 radio 一样,绑定在一个字符串变量上即可。

因为如果 v-model 的初始值未能匹配任何项,<select>会被渲染为未选中,在 IOS 中会使得用户无法选择第一项,所以建议第一个选项为空值的禁选项。

多选 select 与多选的 checkbox 一样,绑定到数组即可。

绑定值

上面提到的绑定除了单选的 checkbox 值可以是布尔值以外其他全是(在 Array 里的)字符串。

v-model 也可以绑定变量。

checkbox 还有 true-value/false-value 这两个特性。

1
<input type="checkbox" v-model="toggle" true-value="yes" false-value="no" />
1
2
3
4
// 当选中时
vm.toggle === "yes";
// 当没有选中时
vm.toggle === "no";

这里的 true-value 和 false-value 特性并不会影响输入控件的 value 特性,因为浏览器在提交表单时并不会包含未被选中的复选框。如果要确保表单中这两个值中的一个能够被提交,(比如“yes”或“no”),请换用单选按钮。

radio 绑定变量

1
<input type="radio" v-model="pick" :value="a" />
1
vm.pick === vm.a; // true

组件使用

其实不太理解这个部分
是父子组件沟通吗(
而且那个 model 选项的命名也真的很奇怪(看了半天搞不懂 san 值狂飙

自定义组件的 v-model
vue.js 自定义组件上使用 v-model
vue 自定义组件 v-model

↑ 两个 demo 帮助理解。

一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,但是像单选框、复选框等类型的输入控件可能会将 value 特性用于不同的目的。model 选项可以用来避免这样的冲突。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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)"
>
`
});
1
<base-checkbox v-model="lovingVue"></base-checkbox>

父组件调用子组件 base-checkbox 时,使用 v-model 绑定了 lovingVue 变量。
lovingVue 的值会传入子组件的名为 checked 的 prop,当子组件触发 change 事件时 lovingVue 的值也会更新。
然后官方有如下说明

注意你仍然需要在组件的 props 选项里声明 checked 这个 prop。
说明 lovingVue 的值传入的是 model 选项里的名为 checked 的 prop,同时需要在 props 里声明 checked 这个 prop。

不过为什么 lovingVue 的值传给的是 checked,为什么不统一命名。。。

修饰符

  1. .lazy
  2. .number
  3. .trim
  4. .native
  5. .sync

.lazy

input 的 v-model 默认是监听 input 事件,使用.lazy 修饰符之后切换为监听 change 事件。

.number

把绑定的值强转为 number 类型。
即使使用 type=’number’获取到的值也是字符串。
但是如果值无法被 parseFloat() 识别也会返回原始值,所以还是建议配合 type=’number’一起食用。

.trim

和 String.prototype.trim()的作用一致。
删除了输入值的开始/结束位置的空格。

.native

作用的话看着就够了↓

关于父子组件通讯的原则,父组件通过prop传递数据给子组件,子组件触发事件给父组件;但父组件想在子组件上监听自己的click的话,需要加上native修饰符。 – 关于vue组件native修饰

功能是将原生事件绑定到组件

可能会有些问题在上面的链接里提到了。

Simple Todo App with Vue
在这个链接里的例子里

BaseInputText.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
computed: {
listeners() {
return {
// Pass all component listeners directly to input
... $listeners,
// Override input listener to work with v-model
input: event => this.$emit("input", event.target.value)
};
}
}
// 替换为
computed: {
listeners() {
return {
// Override input listener to work with v-model
input: event => this.$emit("input", event.target.value)
};
}
}
1
2
3
4
5
6
7
8
9
10
11
<BaseInputText
v-model="newTodoText"
placeholder="New todo"
@keydown.enter="addTodo"
/>
<!-- 替换为 -->
<BaseInputText
v-model="newTodoText"
placeholder="New todo"
@keydown.enter.native="addTodo"
/>

能实现一样的效果。

0%