源碼來源於vuejs的commit記錄:a5e27b1174e9196dcc9dbb0becc487275ea2e84cjavascript
做者在getset-revits-style.html
和getset.html
中簡單實驗了一下數據綁定。html
模板:vue
<div id="test"> <p>{{msg}}</p> <p>{{msg}}</p> <p>{{msg}}</p> <p>{{what}}</p> <p>{{hey}}</p> </div>
jsjava
var app = new Element('test', { msg: 'hello' })
和vue官網的例子幾乎一毛同樣。下面來看下實現源碼,我以爲能夠分爲如下幾個點:git
獲取須要進行數據綁定的domgithub
var self = this, el = self.el = document.getElementById(id)
模板解析替換,做者經過正則/\{\{(.*)\}\}/g
來找到那些被{{}}
標記的地方,而且替換成帶有標記的span
標籤, 而後將這些標記存在bindings
中。app
var bindingMark = 'data-element-binding' var content = el.innerHTML.replace(/\{\{(.*)\}\}/g, markToken) function markToken (match, variable) { bindings[variable] = {} return '<span ' + bindingMark + '="' + variable +'"></span>' } el.innerHTML = content
利用Object.defineProperty
劫持數據來進行數據綁定dom
for (var variable in bindings) { bind(variable) } function bind (variable) { bindings[variable].els = el.querySelectorAll('[' + bindingMark + '="' + variable + '"]') ;[].forEach.call(bindings[variable].els, function (e) { e.removeAttribute(bindingMark) }) Object.defineProperty(data, variable, { set: function (newVal) { [].forEach.call(bindings[variable].els, function (e) { bindings[variable].value = e.textContent = newVal }) }, get: function () { return bindings[variable].value } }) }
首先遍歷bindings
中的標記,而且在bindings
中記錄帶有標記的DOM節點,而後遍歷節點將標記刪除,最後就是劫持data
中對應的屬性了。
關於Object.defineProperty
的原理不做贅述,咱們只看看他set和get都分別做了什麼。this
set
: 遍歷含有當前標記的節點, 把新值賦值給當前dom的e.textContent
,並在bindings
中對應標記裏記錄這個值。spa
get
: 直接獲取內存中存儲的值。