Vue的双向绑定原理鄙人认为就是给数据赋能------(自我检测能力)
HTML代码结构
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Vue双向绑定原理实现</title>
</head>
<body>
<div>埋埋最可爱</div>
<input placeholder="请输入" type="text" />
</body>
<script src="./releaseAndsub.js"></script>
<script src="./observer.js"></script>
<script>
const inputNode = document.querySelector('input')
const data = createData({
name: '埋埋',
gengder: 'female',
})
observer(inputNode, data)
</script>
</html>
一、怎么赋能
我们都知道,Vue的数据结构是对象键值对结构。那好,如果我们将对象内原本的键值对一一变成get/set
方法,这样我们就可以在get/set
方法中给数据赋予自我检测能力。OK,首先我们得知道怎么将原本的键值对改变成get/set
。我们可以利用Object.defineProperty
来对对象中的属性进行改造拦截,这就意味着对象中将没有实质性的key: value
形式,有的只有get/set
。
二、创造观察者observer对model和view进行监听
目前我们只是对数据对象进行了改造,使其拥有自我变化读取监听能力,这就意味着我们观察者中数据监听的部分已经完成。OK,那观察者还需要监听View的变化,那怎么做?对于我们的实验而言,我们便是利用各种相应的事件回调函数来监听View层的的变化,比如oninput
。好的,现在我们知道了model和view层的监听,我们就可以来编写我们的观察者了。
// observer.js
'use strict'
// 通知发布订阅模式改变视图
let [geted, changed] = [false, false]
// 观察者----view视图监测
function observer(changeNodes, data) {
const changeNodesArr = changeNodes instanceof NodeList ? [...changeNodes] : [changeNodes]
changeNodesArr.forEach(node => {
node.oninput = function () {
// 发布订阅者模式,更新model和视图相关操作代码
}
})
}
// 观察者----model数据监测
function createData(data) {
const keyArr = Object.keys(data)
keyArr.forEach(item => {
changeItem(data, item, data[item])
})
return data
}
// 观察者----数据内部单元改造
function changeItem(data, key, value) {
Object.defineProperty(data, key, {
get() {
geted = true
return value
},
set(newValue) {
value = newValue
changed = true
}
})
}
三、创建发布订阅者ReleaseAndsub对model和view进行更新
目前我们有了观察者监听model和view,但是我们还缺少发布订阅者对发布者相应的发布内容(model)和订阅者的相应状态(view)进行更新。OK,具体如何更新的实现方式,人各有异,但只要理解到这个原理真正的执行过程便可,在此我记录下本人的实现方法。
'use strict'
class ReleaseAndsub {
constructor(data, key, target, relies) {
this.data = data
this.key = key
this.target = target
this.relies = relies instanceof NodeList ? [...relies] : [relies] // 收集依赖项
}
// 视图改变model
viewToChangeModel() {
const self = this
self.data[self.key] = self.target.value
}
// model改变视图(根据观察者多提供的changed依据,决定是否改变视图层)
modelTochangeView() {
const self = this
self.relies.forEach(item => {
item.innerText = self.target.value
})
changed = false
geted = false
}
}
四、整合代码
现在我们有了各个组件,我们便可以进行代码的整合了。具体代码我就不贴了,需要者可点击下方本人的gitHub仓库。