国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

利用 JavaScript 數(shù)據(jù)綁定實現(xiàn)一個簡單的 MVVM 庫

hzx / 2637人閱讀

摘要:和刷新函數(shù)是一對多的關系,即一個可以有任意多個處理它的回調(diào)函數(shù)刷新函數(shù),比如和兩個指令共用一個數(shù)據(jù)模型字段。添加數(shù)據(jù)訂閱實現(xiàn)方式為建立緩存回調(diào)函數(shù)的數(shù)組緩存回調(diào)函數(shù)當數(shù)據(jù)模型的字段發(fā)生改變時,就會觸發(fā)緩存數(shù)組中訂閱了的所有回調(diào)。

MVVM 是 Web 前端一種非常流行的開發(fā)模式,利用 MVVM 可以使我們的代碼更專注于處理業(yè)務邏輯而不是去關心 DOM 操作。目前著名的 MVVM 框架有 vue, avalon , angular 等,這些框架各有千秋,但是實現(xiàn)的思想大致上是相同的:數(shù)據(jù)綁定 + 視圖刷新。出于好奇和一顆愿意折騰的心,我自己也沿著這個方向寫了一個最簡單的 MVVM 庫 ( mvvm.js ),總共 2000 多行代碼,指令的命名和用法與 vue 相似,在這里分享一下實現(xiàn)的原理以及我的代碼組織思路。

思路整理

MVVM 在概念上是真正將視圖與數(shù)據(jù)邏輯分離的模式,ViewModel 是整個模式的重點。要實現(xiàn) ViewModel 就需要將數(shù)據(jù)模型(Model)和視圖(View)關聯(lián)起來,整個實現(xiàn)思路可以簡單的總結成 5 點:

實現(xiàn)一個 Compiler 對元素的每個節(jié)點進行指令的掃描和提取;

實現(xiàn)一個 Parser 去解析元素上的指令,能夠把指令的意圖通過某個刷新函數(shù)更新到 dom 上(中間可能需要一個專門負責視圖刷新的模塊)比如解析節(jié)點

時先取得 Model 中 isShow 的值,再根據(jù) isShow 更改 node.style.display 從而控制元素的顯示和隱藏;

實現(xiàn)一個 Watcher 能將 Parser 中每條指令的刷新函數(shù)和對應 Model 的字段聯(lián)系起來;

實現(xiàn)一個 Observer 使得能夠對對象的所有字段進行值的變化監(jiān)測,一旦發(fā)生變化時可以拿到最新的值并觸發(fā)通知回調(diào);

利用 Observer 在 Watcher 中建立一個對 Model 的監(jiān)聽 ,當 Model 中的一個值發(fā)生變化時,監(jiān)聽被觸發(fā),Watcher 拿到新值后調(diào)用在步驟 2 中關聯(lián)的那個刷新函數(shù),就可以實現(xiàn)數(shù)據(jù)變化的同時刷新視圖的目的。

效果示例

首先粗看下最終的使用示例,與其他 MVVM 框架的實例化大同小異:

  • Rank: {{item.rank}}
var element = document.querySelector("#mobile-list");
var vm = new MVVM(element, {
    "title"   : "Mobile List",
    "showRank": true,
    "brands"  : [
        {"name": "Apple", "rank": 1},
        {"name": "Galaxy", "rank": 2},
        {"name": "OPPO", "rank": 3}
    ]
});

vm.set("title", "Top 3 Mobile Rank List"); // => 

Top 3 Mobile Rank List

模塊劃分

我把 MVVM 分成了五個模塊去實現(xiàn): 編譯模塊 Compiler 、解析模塊 Parser 、視圖刷新模塊 Updater 、數(shù)據(jù)訂閱模塊 Watcher 和 數(shù)據(jù)監(jiān)聽模塊 Observer 。流程可以簡述為:Compiler 編譯好指令后將指令信息交給解析器 Parser 解析,Parser 更新初始值并向 Watcher 訂閱數(shù)據(jù)的變化,Observer 監(jiān)測到數(shù)據(jù)的變化然后反饋給 Watcher ,Watcher 再將變化結果通知 Updater 找到對應的刷新函數(shù)進行視圖的刷新。

上述流程如圖所示:

下文就介紹下這五個模塊實現(xiàn)的基本原理(代碼只貼重點部分,完整的實現(xiàn)請到我的 Github 翻閱)

1. 編譯模塊 Compiler

Compiler 的職責主要是對元素的每個節(jié)點進行指令的掃描和提取。因為編譯和解析的過程會多次遍歷整個節(jié)點樹,所以為了提高編譯效率在 MVVM 構造函數(shù)內(nèi)部先將 element 轉成一個文檔碎片形式的副本 fragment 編譯對象是這個文檔碎片而不應該是目標元素,待全部節(jié)點編譯完成后再將文檔碎片添加回到原來的真實節(jié)點中。

vm.complieElement 實現(xiàn)了對元素所有節(jié)點的掃描和指令提取:

vm.complieElement = function(fragment, root) {
    var node, childNodes = fragment.childNodes;
    // 掃描子節(jié)點
    for (var i = 0; i < childNodes.length; i++) {
        node = childNodes[i];
        if (this.hasDirective(node)) {
            this.$unCompileNodes.push(node);
        }
        // 遞歸掃描子節(jié)點的子節(jié)點
        if (node.childNodes.length) {
            this.complieElement(node, false);
        }
    }
    // 掃描完成,編譯所有含有指令的節(jié)點
    if (root) {
        this.compileAllNodes();
    }
}

vm.compileAllNodes 方法將會對 this.$unCompileNodes 中的每個節(jié)點進行編譯(將指令信息交給 Parser ),編譯完一個節(jié)點后就從緩存隊列中移除它,同時檢查 this.$unCompileNodes.length 當 length === 0 時說明全部編譯完成,可以將文檔碎片追加到真實節(jié)點上了。

2. 指令解析模塊 Parser

當編譯器 Compiler 把每個節(jié)點的指令提取出來后就可以給到解析器解析了。每一個指令都有不同的解析方法,所有指令的解析方法只要做好兩件事:一是將數(shù)據(jù)值更新到視圖上(初始狀態(tài)),二是將刷新函數(shù)訂閱到 Model 的變化監(jiān)測中。這里以解析 v-text 為例描述一個指令的大致解析方法:

parser.parseVText = function(node, model) {
    // 取得 Model 中定義的初始值 
    var text = this.$model[model];
    // 更新節(jié)點的文本
    node.textContent = text;
    // 對應的刷新函數(shù):
    // updater.updateNodeTextContent(node, text);
    
    // 在 watcher 中訂閱 model 的變化
    watcher.watch(model, function(last, old) {
        node.textContent = last;
        // updater.updateNodeTextContent(node, text);
    });
}
3. 數(shù)據(jù)訂閱模塊 Watcher

上個例子,Watcher 提供了一個 watch 方法來對數(shù)據(jù)變化進行訂閱,一個參數(shù)是模型字段 model 另一個是回調(diào)函數(shù),回調(diào)函數(shù)是要通過 Observer 來觸發(fā)的,參數(shù)傳入新值 last 和 舊值 old , Watcher 拿到新值后就可以找到 model 對應的回調(diào)(刷新函數(shù))進行更新視圖了。model 和 刷新函數(shù)是一對多的關系,即一個 model 可以有任意多個處理它的回調(diào)函數(shù)(刷新函數(shù)),比如:v-text="title"v-html="title" 兩個指令共用一個數(shù)據(jù)模型字段。

添加數(shù)據(jù)訂閱 watcher.watch 實現(xiàn)方式為:

watcher.watch = function(field, callback, context) {
    var callbacks = this.$watchCallbacks;

    if (!Object.hasOwnProperty.call(this.$model, field)) {
        console.warn("The field: " + field + " does not exist in model!");
        return;
    }

    // 建立緩存回調(diào)函數(shù)的數(shù)組
    if (!callbacks[field]) {
        callbacks[field] = [];
    }
    // 緩存回調(diào)函數(shù)
    callbacks[field].push([callback, context]);
}

當數(shù)據(jù)模型的 field 字段發(fā)生改變時,Watcher 就會觸發(fā)緩存數(shù)組中訂閱了 field 的所有回調(diào)。

4. 數(shù)據(jù)監(jiān)聽模塊 Observer

Observer 是整個 mvvm 實現(xiàn)的核心基礎,看過有一篇文章說 O.o (Object.observe) 將會引爆數(shù)據(jù)綁定革命,給前端帶來巨大影響力,不過很可惜,ES7 草案已經(jīng)將 O.o 給廢棄了!目前也沒有瀏覽器支持!所幸的是還有 Object.defineProperty 通過攔截對象屬性的存取描述符(get 和 set) 可以模擬一個簡單的 Observer :

// 攔截 object 的 prop 屬性的 get 和 set 方法
Object.defineProperty(object, prop, {
    get: function() {
        return this.getValue(object, prop);
    },

    set: function(newValue) {
        var oldValue = this.getValue(object, prop);
        if (newValue !== oldValue) {
            this.setValue(object, newValue, prop);
            // 觸發(fā)變化回調(diào)
            this.triggerChange(prop, newValue, oldValue);
        }
    }
});

然后還有個問題就是數(shù)組操作 ( push, shift 等) 該如何監(jiān)測?所有的 MVVM 框架都是通過重寫該數(shù)組的原型來實現(xiàn)的:

observer.rewriteArrayMethods = function(array) {
    var self = this;
    var arrayProto = Array.prototype;
    var arrayMethods = Object.create(arrayProto);
    var methods = "push|pop|shift|unshift|splice|sort|reverse".split("|");
    
    methods.forEach(function(method) {
        Object.defineProperty(arrayMethods, method, function() {
            var i = arguments.length;
            var original = arrayProto[method];
            
            var args = new Array(i);
            while (i--) {
                args[i] = arguments[i];
            }
            
            var result = original.apply(this, args);

            // 觸發(fā)回調(diào)
            self.triggerChange(this, method);

            return result;
        });
    });
    
    array.__proto__ = arrayMethods;
}

這個實現(xiàn)方式是從 vue 中參考來的,覺得用的很妙,不過數(shù)組的 length 屬性是不能夠被監(jiān)聽到的,所以在 MVVM 中應避免操作 array.length

5. 視圖刷新模塊 Updater

Updater 在五個模塊中是最簡單的,只需要負責每個指令對應的刷新函數(shù)即可。其他四個模塊經(jīng)過一系列的折騰,把最后的成果交給到 Updater 進行視圖或者事件的更新,比如 v-text 的刷新函數(shù)為:

updater.updateNodeTextContent = function(node, text) {
    node.textContent = text;
}

v-bind:style 的刷新函數(shù):

updater.updateNodeStyle = function(node, propperty, value) {
    node.style[propperty] = value;
}
雙向數(shù)據(jù)綁定的實現(xiàn)

表單元素的雙向數(shù)據(jù)綁定是 MVVM 的一個最大特點之一:

其實這個神奇的功能實現(xiàn)原理也很簡單,要做的只有兩件事:一是數(shù)據(jù)變化的時候更新表單值,二是反過來表單值變化的時候更新數(shù)據(jù),這樣數(shù)據(jù)的值就和表單的值綁在了一起。

數(shù)據(jù)變化更新表單值 利用前面說的 Watcher 模塊很容易就可以做到:

watcher.watch(model, function(last, old) {
    input.value = last;
});

表單變化更新數(shù)據(jù) 只需要實時監(jiān)聽表單的值得變化事件并更新數(shù)據(jù)模型對應字段即可:

var model = this.$model;
input.addEventListenr("change", function() {
    model[field] = this.value;
});

其他表單 radio, checkbox 和 select 都是一樣的原理。

以上,整個流程以及每個模塊的基本實現(xiàn)思路都講完了,語言表達能力不太好,如有說的不對寫的不好的地方,希望大家能夠批評指正!

結語

折騰這個簡單的 mvvm.js 是因為原來自己的框架項目中用的是 vue.js 但是只是用到了它的指令系統(tǒng),一大堆功能只用到四分之一左右,就想著只是實現(xiàn) data-binding 和 view-refresh 就夠了,結果沒找這樣的 javascript 庫,所以我自己就造了這么一個輪子。

雖說功能和穩(wěn)定性遠不如 vue 等流行 MVVM 框架,代碼實現(xiàn)可能也比較粗糙,但是通過造這個輪子還是增長了很多知識的 ~ 進步在于折騰嘛!

目前我的 mvvm.js 只是實現(xiàn)了最本的功能,以后我會繼續(xù)完善、健壯它,如有興趣歡迎一起探討和改進~

源代碼傳送門: https://github.com/tangbc/sugar

文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/79080.html

相關文章

  • Vue核心50講 | 第一回:Vue 與 MVVM 之間那些事兒

    摘要:在說真正的內(nèi)容之前,咱們還要先來說說與之間的那些事兒。的核心庫只關注視圖層,不僅易于上手,還便于與第三方庫或既有項目整合。高效核心庫文件壓縮之后只有,遠比的壓縮版文件小得多。這么說還是會比較抽象,接下來咱們用代碼來進一步解釋和之間的關系。 書接上文,上一回咱們說到了如今的前端江湖早已是框架三分天下的格局。接下來,咱們就要說到主角 Vue 了。在說真正的 Vue 內(nèi)容之前,咱們還要先來說...

    chanthuang 評論0 收藏0
  • 淺談MVC,MVP,MVVM漸進變化及React與Vue比較

    摘要:將注意力集中保持在核心庫,而將其他功能如路由和全局狀態(tài)管理交給相關的庫。此示例使用類似的語法,稱為。執(zhí)行更快,因為它在編譯為代碼后進行了優(yōu)化。基于的模板使得將已有的應用逐步遷移到更為容易。 前言 因為沒有明確的界定,這里不討論正確與否,只表達個人對前端MV*架構模式理解看法,再比較React和Vue兩種框架不同.寫完之后我知道這文章好水,特別是框架對比部分都是別人說爛的,而我也是打算把...

    DrizzleX 評論0 收藏0
  • 說說MVVM

    摘要:寫在前面關于軟件架構模式確切的說是一種軟件編碼規(guī)范或者軟件開發(fā)模式,這幾年罵戰(zhàn)不斷。由微軟架構師和開發(fā),通過利用微軟圖形系統(tǒng)和的互聯(lián)網(wǎng)應用派生品的特性來簡化用戶界面的事件驅動程序設計。微軟的和架構師之一于年在他的博客上發(fā)表了。寫在前面 關于軟件架構模式(確切的說是一種軟件編碼規(guī)范或者軟件開發(fā)模式),這幾年罵戰(zhàn)不斷。爭論的焦點主要是在MVC、MVVM、MVP哪種架構最好,哪種架構才是最牛逼的、...

    kid143 評論0 收藏0
  • 淺析 web 前端 MVVM

    摘要:它由微軟架構師和開發(fā),通過利用微軟圖形系統(tǒng)和的互聯(lián)網(wǎng)應用派生品的特性來簡化用戶界面的事件驅動程序設計。微軟的和架構師之一于年在他的博客上發(fā)表了。更改時會得到提醒這個情況是一個單向流。 前言 記得四個月前有一次面試,面試官問我 MVVM 是什么,MVVM 的本質是什么。我大腦一片混亂,那時我對 MVVM 的認知就只是雙向綁定和Vue,以這個關鍵字簡單回答了幾句,我反問 MVVM 的本質是...

    VincentFF 評論0 收藏0

發(fā)表評論

0條評論

hzx

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<