做者:孙辉,美团金融前端团队成员。15年毕业加入美团,相信技术,更相信技术只是大千世界里知识的一种,我的博客: sunyuhui.comjavascript
备注:文章内容和案例均基于Vue2(具体版本为Vue2.3.4)html
笔者最近在写组件的时候,遇到了 v-model
的使用问题,在 Vue 官方文档中,有两小端内容是关于 v-model
指令在组件中的使用,查阅文档后,依然不得要领,最后几番折腾,理论结合实践,终于领悟其精髓,遂成文分享之。前端
v-model
一般都是运用在表单组件中,在这里咱们以一个 select
组件为例,组件命名为 a-select
。vue
第一个问题就是 v-model
指令是写在子组件里仍是父组件里。java
我在最开始写组件时就遇到这个问题,归根结底是对在组件中使用 v-model
指令的了解还处于混沌的状态。git
文档中有提到github
要让组件的 v-model 生效,它应该 (在 2.2.0+ 这是可配置的):bash
- 接受一个 value 属性
- 在有新的值时触发 input 事件
因此咱们须要经过触发事件来实现 value
的更新,而 Vue 中:ide
父子组件的关系能够总结为 props down, events upui
那么很明显,咱们是在父组件里写 v-model
。
那在父组件中咱们能够这么写:
<a-select v-model="parentValue" ></a-select>复制代码
文档 告诉咱们,v-model
只是一个语法糖,实际的含义是:
<a-select
v-bind:value="parentValue"
v-on:input="parentValue = arguments[0]">
</a-select>复制代码
那在子组件中,怎么更新父组件的值(parentValue)呢?我翻遍了文档,也没找到,但我找到了一段看似相关的 定制组件的 v-model,由于其中说了:
默认状况下,一个组件的 v-model 会使用 value 属性和 input 事件,可是诸如单选框、复选框之类的输入类型可能把 value 属性用做了别的目的
一样,咱们的 select
组件的 value
值也被占用,并且没有 input事件
。
看来咱们须要定制 v-model
了, 开始以前,咱们先来把例子看懂。
Vue.component('my-checkbox', {
model: {
prop: 'checked',
event: 'change'
},
props: {
checked: Boolean,
// this allows using the `value` prop for a different purpose
value: String
},
// ...
})复制代码
新增的 model
属性值里有两个key,分别为 prop
、event
,值分别为 checked
、change
,看到这里,咱们弯起嘴角,会心一笑。
model
属性值(model这个名称真是取得简明扼要啊)里的两个key其实就是 v-model
这个语法糖所表明的 prop 和 event,分别表示 该表单元素的值 和 改变元素值时触发的事件, 在 input 中,这两个值是value
和 input
(默认值),在 checkbox 中表示 checked
和 change
。
以此类推,在 select 中就表示 selected
和 change
。
到这里,我就须要指出咱们上面说的一个错误了,此时的 v-model
在父组件中的实际含义是:
<a-select
v-bind:selected="parentValue"
v-on:change="parentValue = arguments[0]">
</a-select>复制代码
那么咱们能够这么来写子组件:
<select @change="emitChange($event.target.value)">
<template v-for="item in selectData">
<option :value="item.value">{{item.text}}</option>
</template>
</select>
export default() {
model: {
prop: 'selected',
event: 'change'
},
props: {
selectData: {
type: Array
},
},
methods: {
emitChange(value){
this.$emit('change', value);
}
}
}复制代码
惟一的问题在于,咱们须要在初始化时设置选中项,该怎么办?咱们还有一个 selected
属性值没有呢。甚至官网也舒适提示咱们:
注意你仍然须要显性声明 checked 属性。
因此这里咱们须要显性声明 selected 属性,不过,由于有 v-model
的存在,咱们能够不用在父组件里传入 selected
值,是否是少了一点工做量呢?
因此子组件里是这么写的:
<select :value="selected" @change="emitChange($event.target.value)">
<template v-for="item in selectData">
<option :value="item.value">{{item.text}}</option>
</template>
</select>
export default() {
model: {
prop: 'selected',
event: 'change'
},
props: {
selectData: {
type: Array
},
selected: {
type: [String,Number]
}
},
methods: {
emitChange(value){
this.$emit('change', value);
}
}
}复制代码
固然了,做为一个完整的 select 组件,上面的示例实际上是很简陋的。
完整的 select 组件代码能够看这里 , Demo 能够看这里。
done
最后,团队为了招聘方便,整了个公众号,主要是一些招聘信息,团队信息,全部的技术文章在公众号里也能够看到,对了,若是你想去美团其余团队,咱们也能够帮你内推哦 ~