VUE是一种MVVM开发模式,VUE 区别于React 等其他前端框架的重要特性之一是VUE 实现了 数据与视图的双向绑定。
一、双向绑定PK :
如果要实现一个输入特定信息的输入框的双向绑定,传统做法与VUE 框架下的示例:
<!DOCTYPE html>
<html>
<head>
<title>数据双向绑定实现</title>
<meta charset="UTF-8">
<script src="vue.js"></script> // 引入vue 模块,源码官网有下载地址,传送门:https://cn.vuejs.org/v2/guide/installation.html
</head>
<body>
<div id="traditionalDemo">
非框架 Demo<input id="city" value="YueYang"/>
<div id="debug">YueYang</div>
</div>
<div id="vueDemo">
VUE Demo<input v-model="city"/>
<div>{{city}}</div>
</div>
<script>
// 非框架下 js 示例
let cityDom = document.getElementById('city')
let debugDom = document.getElementById('debug')
// 方法一:将数据存储在字符串类型的变量中
// let city = 'YueYang'
// cityDom.value = city
// debugDom.innerHTML = city
// cityDom.oninput = function(e){
// city = e.target.value
// cityDom.value = city
// debugDom.innerHTML = city
// }
// 方法二:通常我们将这个数据与其他数据一起储存在对象中
let msg = {}
// 通过存储描述符定义对象属性
Object.defineProperty(msg, 'city', {
set: function(val){
cityDom.value = val
debugDom.innerHTML = val
},
enumerable: true,
configurable: true
})
// 通过数据描述符定义对象属性
// Object.defineProperty(msg, 'city',{
// value: 'Yue Yang',
// writable: true,
// enumerable: true,
// configurable: true
// })
// 通过字面量形式定义对象与对象属性
// let msg = {
// city: 'Yue Yang'
// }
cityDom.oninput=function(e){
msg.city = e.target.value
}
// Vue js 示例
new Vue({
el:'#vueDemo',
data:{
city: 'YueYang'
}
})
</script>
</body>
</html>
二、VUE 实现数据双向绑定原理分析
实现数据双向绑定思路: 数据变化后更新视图, 视图变化后更新数据。
视图变化更新数据
cityDom.oninput=function(e){
msg.city = e.target.value
}
从上面示例的非框架下的js 代码可以看出,可以通过触发视图的相关事件(oninput, onchange, onblur…)更新数据。
数据变化更新视图
Object.defineProperty(msg, 'city', {
set: function(val){
cityDom.value = val
debugDom.innerHTML = val
},
enumerable: true,
configurable: true
})
从上面示例的非框架下的js 代码可以看出,数据变化后可以通过属性的 set 方法更新视图。
VUE 采用发布订阅模式实现视图和数据的双向绑定,主要有以下功能模块:
监听器(Observer):负责监听所有对象属性的变化。其实现核心方法就是前文用到的的Object.defineProperty( )。通过递归遍历所有属性值,并对其属性定义实现对所有属性的监听。
消息订阅器(Dep):主要负责收集订阅者,然后当属性变化时执行对应订阅者的更新函数。
编译器(Compile):主要负责解析模板指令并替换模板数据,初始化视图、将模板指令对应的节点绑定对应的更新函数,初始化相应的订阅器。
订阅者(Watcher):负责接收属性的变化通知并执行相应的函数,然后更新视图。