准备工作
我们来手动实现一个 v-model 的功能。
首先定义了一个component组件,里面有一个template。
1 2 3 4 5 6 7 8
| const CompOne = { props: ['value'], template: ` <div> <input type="text"></input> </div> `, }
|
然后再定义一个vue对象,里面引用了该组件。
1 2 3 4 5 6 7 8 9 10
| new Vue({ components: { CompOne, }, template: ` <div> <comp-one></comp-one> </div> `, }).$mount(root)
|
好了,准备工作完成。
实现

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| const CompOne = { props: ['value'], template: ` <div> <input type="text" @input="handleInput" :value="value"></input> // 添加一个input事件 // 接收父组件传递的value </div> `, methods: { handleInput (e) { this.$emit('input', e.target.value) } } }
|

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| new Vue({ components: { CompOne, }, data () { return { value: 'vue' } }, template: ` <div> // value 为传递给子组件的数据 // @input 接收子组件通过 $emit 传递的参数 <comp-one :value="value" @input="value = arguments[0]"></comp-one> </div> `, }).$mount(root)
|
效果

大功告成,我们实现了 v-model 的功能!
拓展
默认情况下,一个组件上的 v-model 会把 value 用作 prop 且把 input 用作 event。
但是像单选框、复选框等类型的输入控件可能会将 value attribute 用于不同的目的。model 选项可以用
来避免这样的冲突。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| new Vue({ components: { CompOne, }, data () { return { value: 'vue' } }, template: ` <div> <comp-one v-model="value"></comp-one> // 使用v-model 满足语法糖规则:属性必须为value,方法名必须为:input </div> `, }).$mount(root)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| const CompOne = { props: ['value1'], model: { prop: "value1", event: "change" }, template: ` <div> <input type="text" @input="handleInput" :value="value1"></input> </div> `, methods: { handleInput (e) { this.$emit('change', e.target.value) } } }
|
这样就可以让 v-model 变得更灵活,属性和方法名可以自定义。
总结
v-model 时一个语法糖,它做了:
绑定数据value
触发输入事件input
data 更新触发重新渲染