模擬Vue之數據驅動3

来源:http://www.cnblogs.com/giggle/archive/2017/01/11/6262157.html
-Advertisement-
Play Games

在"模擬Vue之數據驅動2"中,我們實現了個Observer構造函數,通過它可以達到監聽已有數據data中的所有屬性。 但,倘若我們想在某個對象中,新增某個屬性呢? 如下: 那麼豈不是,新增的infor屬性,以及它的對象屬性,沒有得到監聽。 此時,應該怎麼處理呢? 通過走讀Vue源碼,發現他是採用另 ...


一、前言

在"模擬Vue之數據驅動2"中,我們實現了個Observer構造函數,通過它可以達到監聽已有數據data中的所有屬性。

但,倘若我們想在某個對象中,新增某個屬性呢?

如下:

那麼豈不是,新增的infor屬性,以及它的對象屬性,沒有得到監聽。

此時,應該怎麼處理呢?

通過走讀Vue源碼,發現他是採用另增屬性方法$set實現的。

就是說,如果我們採用常規方法為對象增加屬性(如上),我們沒法得知並監控它,所以,我們為每個對象擴展一個$set方法,用於另增屬性使用,即可,如下:

data.user.$set('infor', {msg: 'happy'});

好了,下麵,我們就一同實現這個$set方法吧。

二、$set方法實現

首先,我們得創建一個恆定extendObj對象,用於將$set方法綁定在其中。

你可能會想,為什麼我們需要一個extendObj對象呢?直接將$set函數賦值給每個需要監聽的對象不就完了麽?

是的,這樣也可以,但是隨著需求增長,倘若我們又想為每個監聽對象擴展其他方法呢?難道又要去Observer裡面為對象,一一賦值?

so,創建恆定extendObj對象,如下:

const extendObj = {};

因為,我們將$set綁定到extendObj中,且讓$set為不可枚舉型,所以會用到Object.defineProperty,固將其提取出來,作為一個方法如下:

function proxyObject(obj, key, val, enume){
    Object.defineProperty(obj, key, {
        value: val,
        enumerable: !!enume,
        writable: true,
        configurable: true
    });    
};

接下來,就是實現$set方法了,整體結構如下:

proxyObject(extendObj, '$set', function(key, val){
    //this指向extendObj
    if(this.hasOwnProperty(key)){
        return;
    }else{
        /*
          TODO:在extendObj中監聽key屬性,
          且,若key屬性值為對象,再次監聽key屬性值
        */          
    }    
});

看到上面的TODO註釋,是否似曾相識,不就是是在“模擬Vue之數據驅動2”遇見過的嘛,通過Observer.prototype.convert監聽key屬性,通過new Observer再次監聽key屬性值不就完啦。

的確,但是一旦這樣做了,不就和上面我們提到的“直接將$set賦予監聽對象”問題一樣嘛,耦合性太大,且隨著需求上漲,不易維護。

固而,在此需要一點小技巧:在observer模塊中為每個監聽對象賦予一個$Observer屬性,其值指向Observer自身實例,如下:

//observer.js
p.walk = function(data){
    let keys = Object.keys(data);
    keys.forEach( key => {
        let val = data[key];
        if(typeof val === 'object'){
            new Observer(val);
        }
        this.convert(key, val);
    });
    //$Observer屬性指向Observer自身實例
    data.$Observer = this;
}
//新增一個observe方法
p.observe = function(data){
    if(typeof data === 'object'){
        new Observer(data);    
    }    
}

好了,這樣之後,得$set整體實現如下:

proxyObject(extendObj, '$set', function(key, val){
    if(this.hasOwnProperty(key)){
        return;
    }else{
        proxyObject(this, key, val, true);
        let ob = this.$Observer;
        ob.observe(val);
        ob.convert(key, val);    
    }    
});

到此,一個簡單的$set方法構建完畢。

在上面我們提到,之所以需要一個恆定extendObj對象,是為了更好的代碼管理。且,到目前為止,需要監聽的對象上並沒有擴展$set方法呢,所以,下麵的事情就是為了達到以上效果,如下:

//observer.js
function Observer(data){
    if(!(this instanceof Observer)){
        return new Observer(data);
    }
    //將監聽對象的隱指針指向我們的extendObj對象
    data.__proto__ = extendObj;
    this.data = data;
    this.walk(data);    
}

好了,一切完畢,接下來就測試下吧:

<script src="./extendObj.js"></script>
<script src="./observer.js"></script>
<script>
    let data = {
        user: {
            name: 'Monkey',
            age: 24
        },
        lover: {
            name: 'Dorie',
            age: 23
        }
    };
    Observer(data);
</script>

效果如下:

Perfect,完整代碼見github 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 經測試,相容IE8 ...
  • 1.Html區塊元素 HTML可以通過<div>和<span>將元素組合起來 大多數HTML元素被定義為塊級元素或內聯元素, 而塊級元素在瀏覽器顯示時,通常會以新行來開始(或結束)。如:<h1>,<p>,<ul>,<table> 內聯元素在顯示時通常不會以新行開始。如:<b>,<td>,<a>,<i ...
  • 一、Bootstrap彈出框使用過JQuery UI應該知道,它裡面有一個dialog的彈出框組件,功能也很豐富。與jQuery UI的dialog類似,Bootstrap裡面也內置了彈出框組件。打開bootstrap 文檔可以看到它的dialog是直接嵌入到bootstrap.js和bootstr ...
  • Document 你的瀏覽器不支持canvas ...
  • 一、驗證二、過濾器2.1、內置過濾器2.1.1、在模板中使用過濾器2.1.2、在腳本中調用過濾函數2.2、自定義過濾器三、指令(directive)3.1、支持AngularJS功能的指令3.1.1、應用與模塊(ng-app)3.1.2、控制器(ng-Controller)3.1.3、包含(ng-I... ...
  • prismjs 是一款輕量、可擴展的代碼語法高亮庫,使用現代化的 Web 標準構建,使用 Prismjs 可以快速為網站添加代碼高亮功能,支持超過113中編程語言,還支持多種插件,是簡潔、高效的代碼高亮解決方案。科技愛好者博客就是使用了Prism.js 實現漂亮的代碼語法高亮功能,本文教你如何在wo ...
  • 之前js取form表單的值都是一個一個的取,數量一多之後容易出錯而且煩透了。感謝那些願意分享的人。 頁面定義form,並給form指定id值,裡面的元素只要是需要鍵值對應的都賦予name屬性,並且name值等於後臺能識別的參數名。 ...
  • 實例 對齊彈性盒的 <div> 元素的各項: div { display: flex; flex-flow: row wrap; align-content:space-around; } 複製 效果預覽 瀏覽器支持 表格中的數字表示支持該屬性的第一個瀏覽器的版本號。 緊跟在 -webkit-, - ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...