KnockoutJs 進階學習

來源:互聯網
上載者:User

標籤:ko   knockoutjs   mvvm   

Q: KnockOut的雙向繫結是如何工作的呢?

A: 原理上還是挺簡單的:

  1. 聲明Observable的時候記住當前的值, var personName =     ko.observable("");
  2. 在HTML裡declarative     binding時,即data-binding="text: personName",會註冊一個subscriber 到personName
  3. 當personName的值發生變化時,會通知所有的subscriber,觸發對應的行為
  4. 重新記錄這個新的值,迴圈#c步驟。

順便提下,如果想讓personName改變後還是原值的時候也觸發subscriber,可以用extender

myViewModel.personName.extend({ notify: 'always' });

 

Q: 為什麼ViewModel的官方規範裡面需要var self= this;

A: 防止在事件觸發的時候ViewModel的this和事件自己的this混淆

 

Q: 區別: subscribe vs computed vs extend

如果需要處理由值變化而引發另一個操作的情境,可以有幾種方式:

  1. Subscribe在單值變化的時候使用;
  2. Computed在多個值變化的時候使用;
  3. Extend則一般定義了通用方法,可以讓多個observable公用同一個extend方法,類似於C#裡面的filter.

具體用法如下:

  1. Subscribe, 該方法有3個參數:
       
    1. callback是由值變化後觸發的callback函數 
    2. Target:可選項,callback的this值 
    3. event可以定義callback 函數觸發的事件,比如: beforeChange,預設是用change
myViewModel.personName.subscribe(function(newValue) {    alert("Theperson's new name is " + newValue);});

 

PS: KO的官方文檔裡解釋是,KO在HTML裡的聲明綁定(Decliaritivebinding),就是使用subscribe的機制來實現的。

 

既然可以顯示聲明subscribe,也就可以把它dispose掉

var subscription =myViewModel.personName.subscribe(function(newValue) { /* do stuff */ });// ...then later...subscription.dispose(); // I no longer want notifications
  1. Computed:

如果在computed裡面的KO對象的值有變更,都會觸發computed函數執行:

function AppViewModel() {    this.firstName = ko.observable('Bob');    this.lastName = ko.observable('Smith');}function AppViewModel() {    // ... leave firstName and lastNameunchanged ...    this.fullName = ko.computed(function() {        return this.firstName() + " " +this.lastName();    }, this);}

這裡,傳遞this是 為了在computed裡讀取fistName和lastName.

 

如果要在改變fullName的時候反向改變firstName和LastName,可以定義裡面的write callback, 我使用過的一個情境是一個checkbox控制所有其他Itemcheckbox的 select和unselect.

function MyViewModel() {    this.firstName =ko.observable('Planet');    this.lastName = ko.observable('Earth');    this.fullName = ko.pureComputed({        read:function () {            return this.firstName() + " " +this.lastName();        },        write:function (value) {            var lastSpacePos = value.lastIndexOf(" ");            if (lastSpacePos > 0) { // Ignore values with no space character                this.firstName(value.substring(0,lastSpacePos)); // Update "firstName"                this.lastName(value.substring(lastSpacePos+ 1)); // Update "lastName"            }        },        owner: this    });}

 

  1. Extender:

Target參數傳遞被extend的對象,option傳遞外部的值

ko.extenders.logChange = function(target, option) {    target.subscribe(function(newValue) {  console.log(option+ ": " + newValue);    });   return target;};this.firstName =ko.observable("Bob").extend({logChange: "first name"});

 

區別:Computed VS Pure Computed

Pure Computed只有當有其他subscriber的時候才會有這個對象,所對應的DOM對象 不啟用的時候不存在,這樣可以防止記憶體泄露,在Component等情境下不用擔心dispose的問題。

如果computed裡面的對象不會有其他寫的操作,優先使用pure computed

 

"text" binding 注意事項:

Text binding非常常用,使用也非常簡單,但是要注意一些情境:

Today's message is: <span data-bind="text:myMessage"></span>   <script type="text/javascript">     var viewModel = {        myMessage:ko.observable() // Initially blank     };     viewModel.myMessage("Hello,world!"); // Text appears </script>
  1. 如果text是非number或string, 它的值會轉換成ToString()的形式顯示,比如顯示成Object
  2. text會過濾掉所有HTML元素防止Javascript注入,如果要保護HTML元素,使用HTML綁定

 

關於綁定上下文:

首先理解下上下文Context和上下文ViewModel的對象,以$parentContext和$parent為例:

    var initialData = [        {            firstName: "Danny",lastName: "LaRusso", id:"C6A2D391-6B68-42EA-9EE2-3E25756143C2", phones: [              { type: "Mobile",number: "(555) 121-2121", id:"C6A2D391-6B68-42EA-9EE2-3E25756143C1" },              { type: "Home", number:"(555) 123-4567", id:"C6A2D391-6B68-42EA-9EE2-3E25756143C5" }]        },        {            firstName: "Sensei",lastName: "Miyagi", id:"C6A2D391-6B68-42EA-9EE2-3E2575614334", phones: [              { type: "Mobile",number: "(555) 444-2222", id:"C6A2D391-6B68-42EA-9EE2-3E25756143C20" },              { type: "Home", number:"(555) 999-1212", id:"C6A2D391-6B67-42EA-9EE2-3E25756143C2" }]        }    ];


 

假設當前的上下文是在Phones, 如果要訪問父級的firstName, lastName對象,可以用$parentContext先擷取父級的上下文,然後再取出對象
<spandata-bind="text: $parentContext.contact.firstName"></span>

也可以用$parent取得父級內容相關的object: {  firstName:"Danny", lastName: "LaRusso", id:"C6A2D391-6B68-42EA-9EE2-3E25756143C2"},

 然後直接取得firstName的值 <span data-bind="text:$parent.firstName"></span>

 

KO定義很一些上下文綁定對象,可以方便的找到當前和不同層別的上下文。

  1. $parent,  $parents and $root

$parent可以找到上級的對象, $parents[0], $parents[1].$parents[$parents.length -1]則一級一級往上找。

<h1 data-bind="text:name"></h1><div data-bind="with:manager">    <!-- Now we're inside a nested binding context -->   <span data-bind="text:name"></span> is the    manager of <span data-bind="text: $parent.name"></span></div>

如果當前的上下文是root, $parent和$parents都會是undefined, $parents[$parents.length-1]也相當於$root.

  1.  $data, 儲存當前內容相關的ViewModel對象,同樣, 在root上下文,$data相當於$root
<table>    <thead>        <tr><th>Firstname</th><th>Last name</th></tr>    </thead>    <tbody data-bind="foreach:people">        <tr>            <td data-bind="text: $data.firstName"></td>            <td data-bind="text: lastName"></td>        </tr>    </tbody></table><script type="text/javascript">    ko.applyBindings({        people: [            { firstName: 'Bert', lastName: 'Bertington' },            { firstName: 'Charles', lastName: 'Charlesforth' },            { firstName: 'Denise', lastName: 'Dentiste' }      ]    });</script>

 

  1. $context and $parentContext

$context是當前的上下文,$parentContext對應的是父級的上下文

 

  1. $element

當前綁定的DOM對象

<div id="item1"data-bind="text:$element.id"></div>

 

  1. Foreach會改變當前的上下文,和 with 綁定可以主動的改變當前的上下文
<h1 data-bind="text: city"> </h1> <p data-bind="with: coords">     Latitude: <span data-bind="text:latitude"> </span>,    Longitude: <spandata-bind="text: longitude"> </span></p>   <script type="text/javascript">     ko.applyBindings({         city:"London",         coords: {             latitude: 51.5001524,             longitude:-0.1262362         }     }); </script>


 

非常好用的資料轉化observable外掛程式:Ko.mapping

這是一個外掛程式,能複雜物件的資料和子層資料轉化成Observable, 沒有在KO內建的js裡,需要額外下載,用法:

self.changeRequest = ko.mapping.fromJS(data); //data裡面的所有資料都會變成observable

 

如果要更新整個對象,通過直接的賦值self.changeRequest沒有作用,可以通過以下方法:

 ko.mapping.fromJS(result,instance.changeRequestViewModel.changeRequest);

 

區別 If binding vs visible binding vs with

 if 綁定會根據條件判斷是否產生對應的DOM對象,而Visiable只是通過css顯示和隱藏DOM對象,兩者的使用情境還是有所差別的。比如,根據使用者當前的許可權判斷時候可以顯示某個操作時,最好還是使用if,可以防止別人通過修改HTML 屬性看到這個DOM對象。

with除了改變內容相關的層級,還有另一個特性,當內部的元素不存在時,不會出現找不到元素的綁定錯誤。

 

Click 綁定注意事項

Click 事件會預設傳遞當前上下的 ViewModel值和觸發的事件對象給函數, 如果要改變函數,可以有兩個辦法:

<button data-bind="click: function(data, event) {myFunction('param1', 'param2', data, event) }">    Click me </button> <button data-bind="click: myFunction.bind($data,'param1', 'param2')">    Click me </button>

 一般情況下,聲明了click綁定之後,就不會觸發其他的點擊事件了,比如a標籤的href,如果還想繼續觸發,在click的函數裡返回true

 

Form相關的綁定注意事項:

  1. Checkbox 和radio 按鈕請使用checked 綁定(不用value), 只需聲明個數組 this.checkedList=     ko.observableArray(); 然後在HTML綁定時指定value和checked就能實現多選,不需要很複雜的代碼:     databind="value: Id, checked: checkedList", checkedList取到的就是選中的Id列表。
  2. Input標籤需要使用textInput 綁定而不是value綁定, 區別在於,textInput在值改變的時候就能觸發, value要等到keydown才行。

參考:http://knockoutjs.com/documentation/introduction.html

 

KnockoutJs 進階學習

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.