原文地址:https://zhuanlan.zhihu.com/p/28326328
之前写过一篇开发一个简单指令理解 Vue 的 v-model 语法糖,今天根据 SF 上的一个问题再来说说 v-model 的本质。
SF 上有人提出一个问题,对 iView 的 slider 组件进一步封装,如何方便地在封装后的组件上直接使用 v-model。
从 Components — Vue.js 文档可知,v-model 只是个语法糖,通过设置一个名为 value 的 prop 并且在数据发生变化时 $emit 一个带新值的 input 事件,就可以在该自定义组件中使用 v-model 进行双向绑定。
要在进一步封装的组件中实现 v-model 绑定,需要设置一个 value prop,并且需要在必要的时机 $emit 带新值的 input 事件,问题是这个数据如何再传递给 slider 组件,以及什么是必要的时机?
iView 中的 slider 也是通过这样的 value 加上 $emit input 事件来实现 v-model 双向绑定的,同时当用户在 slider 上通过 v-model 进行数据双向绑定时,其本质是通过绑定的实例数据向 slider 的 value 传递相应的数据,并且在响应 input 自定义事件时使用事件的 value 更新该实例数据。
因此在进行进一步封装时,只需要将 slider 上的 v-model 绑定拆开来,变成 value 绑定和 input 事件的响应,其中 value 透传来自父组件通过 v-model 绑定的数据,而在 slider 的 input 事件上绑定一个方法,直接将由 slider 带过来的新值通过 $emit 到封装组件的 input 事件上,这就是在这个组件中 $emit 带新值的 input 事件的时机。
相关组件选项如下:
let nestedSlider = {
props: ['value'],
template: `<div>
<div>
This is a nested slider:
</div>
<slider
v-bind:value="value"
v-on:input="value => $emit('input', value)">
</slider >
</div>
`
}
即可在 nested-slider 组件中直接使用 v-model 绑定数据:
<nested-slider v-model="value"></nested-slider>
这个思路的盲点在于,知道 v-model 是个语法糖,却看不透子组件的 v-model 也是通过一个名为 value 的 prop 并且在数据发生变化时 $emit 一个带新值的 input 事件来实现的;即使在官方示例的货币编辑组件中 input 原生 DOM 元素中并没有使用 v-model,却不知道在子组件中直接单向绑定 value 并响应其 input 自定义事件。
在线示例: