动态

详情 返回 返回

web-compiler:mvvm 的實現思路 - 动态 详情

最近一段時間留意到一個叫Svelte的前端框架,它與Vue 等前端框架的最大不同是採用了編譯的方案進行的實現,這是官網的介紹

Svelte 是一種全新的構建用户界面的方法。傳統框架如 React 和 Vue 在瀏覽器中需要做大量的工作,而 Svelte 將這些工作放到構建應用程序的編譯階段來處理。

與使用虛擬(virtual)DOM 差異對比不同。Svelte 編寫的代碼在應用程序的狀態更改時就能像做外科手術一樣更新 DOM。

code

然後想了一下Svelte 組件 大體思路定義一套dsl,然後通過Svelte編譯成js css 代碼,html對應的dom通過js生成。
順着這個思路寫了一個最小化的 mvvm 的示例

<script>
    let a = 10;
    function handler(){
        a++;
    }
    let str = "hello";
</script>
<button @click="handler()">
    click me {{a}}
</button>

其對應的編譯後代碼可以是這個樣子

// watcher core
function createWatcher(){
    let watcher = {};
    function watch(key, cb){
        if(!watcher[key]){
            watcher[key] = [];
        }
        watcher[key].push(cb);
    }
    function trigger(key){
        watcher[key].forEach(cb => cb());
    }
    return {
        watch,
        trigger
    }
}
let {watch, trigger} = createWatcher();
let a = 10;
function handler(){
    a++;
    // 框架注入trigger
   trigger('a');
}

let btn = document.createElement('button')
btn.addEventListener('click', handler)
btn.innerHTML = 'Click me'+a;
// 框架注入watch
watch('a', () => {
    btn.innerHTML = 'Click me'+a;
})
document.body.appendChild(btn)

核心思路是實現一個watcher 觀察者,對於script 裏被依賴的變量 值發生變更觸發trigger, 獲取值的地方通過watch註冊, 當trigger 'a' 時 獲取到觀察'a'的callback函數列表 ,依次進行調用。

總結

編譯的過程就是植入watch,trigger和轉換的過程 如 handler 裏對a進行賦值變更 那麼有兩種方式實現 一種是對 ++ 或者説 = 進行重寫 拿到左值 進行 賦值與trigger 操作 , 另一種是分析有無依賴外部的頂層變量 然後進行代碼植入, 轉換則是把植入完後的代碼進行 二次加工 如 button html標籤 轉換成 js dom的形式。

補充 對a進行賦值變更也可以通過 proxy setter 方式實現

Add a new 评论

Some HTML is okay.