仿造VueJS資料綁定與頁面更新機制的仿造
by sj82516
HTML
<div id="demo">
<p>{{message}}</p>
<p>{{message}}</p>
<input v-model="message">
</div>
JavaScript
/*
這是一個基於getter/setter仿造VueJS資料綁定與頁面更新機制的仿造
說是仿造更應該說是我個人採用getter/setter,自行揣摩出來的解法
目前完成{{}}的字串解析與v-model雙向綁定
*/
// 用來儲存資料與對應更新的DOM元素
class DataItem {
constructor(v){
this.value = v;
this.elements = [];
}
}
// 仿造Vue
class Vue {
constructor({el, data}){
// dataStored單純儲存資料
this.dataStored = {};
for(let p in data){
this.dataStored[p] = new DataItem(data[p]);
}
// dataWithSetter為增設getter/setter的資料
this.dataWithSetter = {};
this._dataBindSetter(data);
this.rootEl = document.querySelector('#demo');
this._constructComponent();
}
// 將資料加入setter並於更新時帶動畫面更動
_dataBindSetter(data){
let vm = this;
if(!data instanceof Object){
throw("data should be object");
}
for(let p in data){
this.dataWithSetter = Object.defineProperty(data, p, {
get: function(){
// 注意,這裡不能用 this[p],這會產生getter call getter ....然後就爆了
return vm.dataStored[p].value;
},
set: function (newVal){
console.log("屬性 ", p, "將值從", vm.dataStored[p].value ,"更新為", newVal);
// 同理這裡不能設this[p] = newVal,所以才會特別設計兩個data{~}分開
vm.dataStored[p].value = newVal;
vm._updateView();
}
})
}
}
//內部更新函式
_updateView(){
console.log("開始重繪頁面");
// 將dataStored中所有的元素都更新
for(let p in this.dataStored){
for(let i=0; i < this.dataStored[p].elements.length; i++){
this.dataStored[p].elements[i].textContent = this.dataStored[p].value;
}
}
}
//渲染頁面
_constructComponent(){
if(!this.rootEl){
throw("根物件不存在");
}
let children = this.rootEl.children;
for(let i=0; i < children.length; i++){
let child = children[i];
let...