Vue官方文档解读系列(二):自定义组件上的 v-model

489 阅读3分钟

前言

本文主要根据官方文档中的自定义组件上的 v-model 一栏,阅读后加上自己的一些理解和例子的补充。因为在参阅Vue官方文档时,有一些内容作者没有加上例子配合解释(可能觉得太简单了),所以有些含糊不清,初学者不是很能理解,所以写了这个系列。在自己的理解上加上一些例子,希望能帮助你更好的理解。

什么是v-model?

本文核心是 v-model ,所以先让我们去了解下什么是 v-model 呢?借用官方文档对它的解释:

你可以用 v-model 指令在表单 <input><textarea> 及 <select> 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但 v-model 本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。

总的来说,他其实就是可以实现双向数据绑定的语法糖,用法如下:

<div id="demo">
  <input type="text" v-model="value">
</div>
var vm=new Vue({
  el:"#demo",
  data:{
  	value:'2'
  }
})

通过以上语句就可以实现 value 值和输入框输入值的双向绑定。 上文也提到 v-model 其实是一个语法糖,那他真正的实现是咋样的呢?如下所示:

<div id="demo">
  <input type="text" :value='value' @input="value=$event.target.value">
</div>

可以看到 v-model 拆成了两步:

  • 利用 v-bind 将输入框的值绑定在 value 变量上。当 value 变量改变,输入框的值也会变,实现单向数据绑定。
  • 利用输入框的 input 方法,当输入框值发生变化时将值传给 value 变量。至此双向数据绑定也就完成了。

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

在组件上使用 v-model 也如上文这么简单吗?让我们来试一试。

Vue.component('base-input',{
  template: `
  	<input type="text" >
  ` 
})
var vm=new Vue({
  el:"#demo",
  data:{
  	price:'2'
  }    
})
<div id="demo">
  <base-input v-model="price"></base-input>
</div>

运行后的结果却是根本没有成功的双向绑定。为什么呢?首先让我们把v-model转换成真实的实现代码会更方便理解。

<div id="demo">
  <base-input :value="price" @input="price=$event"></base-input>
</div>
  1. 很明显父组件已经把输入框的 value 值绑定到 price 变量,但还不够,此时应该将 value 值通过 props 传递给子组件,实现了父组件的 price 变量到子组件的 value 值的单向绑定
  2. 以及当子组件输入框值发生改变时就要主动通知父组件去改变 price 变量。

让我们试着改造下组件代码:

Vue.component('base-input',{
  props:['value'],
  template: `
  	<input type="text" :value="value" @input="$emit('input',$event.target.value)">
  ` 
})

至此输入框类型的自定义组件的双向数据绑定才算完成了。

单选框、复选框等类型的自定义组件使用v-model

在上文基础上再补充条必要的知识:一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件。这个条件对于输入框文本域这种改变value值的控件用起来会得心应手,但对单选框复选框等value值不会随用户操作而改变的类型就不是那么友好了。例如复选框,他关注的应该是 checked 属性和 change 事件。如果我们直接用v-model而不进行额外操作,那么这个组件其实没有任何作用。那额外的操作是什么呢?先拉上一段组件代码。

Vue.component('base-checkbox', {
  model:{
    prop: 'checked',
    event: 'change'
  },
  props:{
    'checked':Boolean
  },
  template: `
    <input
    	type="checkbox" :checked='checked' @change="$emit('change',$event.target.checked)"
    >
  `
})
<base-checkbox v-model="demoValue"></base-checkbox>

出现了陌生的一个选项:model。看看官方文档是怎么介绍的呢:

  • 类型{ prop?: string, event?: string }
  • 详细:允许一个自定义组件在使用 v-model 时定制 prop 和 event。默认情况下,一个组件上的 v-model 会把 value 用作 prop 且把 input 用作 event,但是一些输入类型比如单选框和复选框按钮可能想使用 value prop 来达到不同的目的。使用 model 选项可以回避这些情况产生的冲突。

这正是我们所要解决的问题,他可以修改默认的 value 属性和 input 事件。根据你的需求自己定义,如本例用的是复选框它需要的是 checked 属性和 change 事件,所以我们在 model 选项里修改了这一行为。所以其实上面引用组件的真实代码如下:

<base-checkbox :checked="demoValue" @change="demoValue=$event"></base-checkbox>

小结

所以当我们在自定义组件上使用 v-model 时,需要明确它默认的 prop event 分别是 valueinput 。需要根据实际情况做出改变。了解 v-model 是利用 v-bind 和事件监听来实现双向数据绑定的语法糖。