Vue
中数据双向绑定的实现原理是面试过程中经常被问到的问题,因为聊这部分问题的时候,面试官可以通过你的表达,大概了解你对 Vue
的研究到达了哪个程度。
当然对这个问题,不同的面试官可能会有不同的问法,比如,直接提问 Vue
中数据双向绑定的原理是什么,提问 v-model
的实现原理是什么,提问 Vue
是如何实现当我们更新数据时能够实现页面响应式渲染的,等等。
简单理解
表单元素中可以使用 v-model
来实现数据双向绑定,或者组件上也可以使用 v-model
来创建双向绑定。当然 v-model
是语法糖,在内部为不同的表单元素使用不同的属性并绑定不同的事件处理程序来实现双向绑定,如 text
与 textarea
元素使用 value
属性与 input
事件,checkbox
与 radio
元素使用 checked
属性与 change
事件,select
元素使用 value
属性与 change
事件来实现双向绑定。
如果是在组件上使用 v-model
来创建双向绑定,则 v-model
相当于是这样的:
v-bind:value="searchText" v-on:input="searchText = $event">
为了让这个组件正常工作,组件内的 必须:
- 将其
value
属性绑定到一个名叫value
的 prop 上 - 在其
input
事件被触发时,将新的值通过自定义的input
事件抛出
即组件定义的代码应该是:
Vue.component('custom-input', { props: ['value'], template: ` v-bind:value="value" v-on:input="$emit('input', $event.target.value)" > `})
这就实现了组件中 v-model
的双向绑定:
<custom-input v-model="searchText">custom-input>
当然,以上这些是对双向绑定的简单的理解,如果这么回答,不一定会让面试官满意,可能你只是对 Vue
的文档比较熟悉一点而已。
所以如果这不是面试官想要知道的结果,可能他会停顿一会,让你继续说下去,或是也可能会追问:然后呢?
然后我们就可以深层次的聊聊,比如数据劫持,发布-订阅模式了。
底层原理
Vue
实现数据双向绑定的底层原理主要是:采用数据劫持结合发布-订阅模式的方式,通过 Object.defineProperty()
来劫持各个属性的 getter/setter
,在数据变动时发布消息给订阅者,触发相应监听回调。
当把一个普通的 JavaScript
对象传入 Vue
实例作为 data
选项时,Vue
将遍历此对象所有的 property
,并使用 Object.defineProperty
把它们全部转为 getter/setter
。
这些 getter/setter
对用户来说是不可见的,但是在内部它们让 Vue
能够追踪依赖,在 property
被访问和修改时通知变更。
每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property
记录为依赖,之后当依赖项的 setter
触发时,会通知 watcher
,从而使它关联的组件重新渲染。
上图是 Vue
官方深入响应式原理中关于如何追踪变化的示意图,当中有些原理的细节还未完全体现,但如果能够将这张图解释清楚,对双向绑定的原理的理解自然也会更深入了。
当然对于原理深层次的实现,不是三言两语能够说清楚的,下面是实际实现的大概流程:
对该流程中具体的实现,可参考我的博客中《自定义 MVVM 库》一文详细了解。大家可以访问 http://itrainhub.github.io/ 查看。