仿造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...