1. 程式人生 > >(更新)knockout.js學習——1.7例子——繫結的詳細語法

(更新)knockout.js學習——1.7例子——繫結的詳細語法

建立自定義模板


1、註冊繫結
新增子屬性到ko.bindingHandlers.yourBindingName ={};註冊繫結。


init和update可以只定義其中一個。


(1)初始化:init


  // 建立初始化狀態,事件處理等等




(2)更新:update


    // 無論何時相關聯的observable改變value時候
   // 基於應用values的DOM元素


(3)在DOM元素上使用: <div data-bind="yourBindingName: 


someValue"></div>




2、詳細解釋
   
   ko.bindingHandlers.yourBindingName ={
   init:function


(element,valueAccessor,allBindingsAccessor,viewModel){},
   update:function


(element,valueAccessor,allBindingsAccessor,viewModel)
   }


   引數:
   element——使用這個繫結的DOM元素。
            
   valueAccessor——Javascript函式。通過valueAccessor()可以得到應用到這個繫結的model上的當前屬性值。
   
另一種翻譯:得到是當前進入繫結的內容。是observable不是值。可以是表示式的值。


   allBindingsAccessor--Javascript函式。通過allBindingsAccessor()得到這個元素上所有model的屬性值。
另一種翻譯:得到其他繫結,並列入繫結屬性中。一般用來訪問其他繫結。這使您可以訪問所有的其他繫結在同一列資料繫結屬性。這通常是用於訪問其他與此結合相互作用的繫結。這些繫結可能不會有任何相關的程式碼,只是一種方法,通過附加選項的約束力,除非你選擇的多個屬性為您的主要結合傳遞一個物件。例如,optionsvalue,optionstext,和optionscaption是繫結,只能通過選項選項結合。


   viewModel--傳遞給ko.applyBindings使用的view model引數,如果是模板內部的話,這個引數就是傳遞給模板的資料。

另一種翻譯:通常以data代替避免混淆呼叫此引數資料。外模板繫結,這將提供對你的整體檢視模型。在一個模板,這將被繫結到模板資料。例如,使用的模板的結合foreach選項時,檢視模型引數會被設定為當前陣列成員通過模板傳送。大多數時候,valueaccessor會給你你想要的資料,而檢視模型引數是特別有用,如果你需要一個物件是你的目標的時候,你的call/apply功能。





 (1) init回撥:
  knockout在dom元素使用自定義繫結的時候會呼叫你的init函式。  init有兩個重要的用途:為dom元素設定初始值;註冊事件控制代碼,例如當用戶點選或者編輯DOM元素的時候,可以改變相關的observable值的狀態。ko會傳遞和update回撥函式一樣的引數。

你可以像讓slideVisible在頁面第一次顯示的時候設定該元素的狀態(但是不使用任何動畫效果),而只是讓動畫在以後改變的時候再執行。


你可以這樣來做:




ko.bindingHandlers.slideVisible = {
    init: function(element, valueAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor


());
        // Get the current value of the current property we're 


bound to
        $(element).toggle(value);
        // jQuery will hide/show the element depending on 


whether "value" or true or false
    },


    update: function(element, valueAccessor, 


allBindingsAccessor) {
        // Leave as before
    }
};
這就是說giftWrap的初始值宣告的是false(例如giftWrap: ko.observable(false)),然後讓初始值會讓關聯的DIV隱藏,之後使用者點選checkbox的時候會讓元素顯示出來。




(2)update回撥


    通過visible繫結來控制一個元素的可見性,但是想讓該元素在隱藏或者顯示的時候加入動畫效果。可以自定義自己的繫結來呼叫jquery的slideUp/slideDown函式。


ko.bindingHandlers.slideVisible = {
   update: function


(element,valueAccessor,allBindingsAccessor){
    // get the latest data that bound to
    var value = valueAccessor(), allBindings = 


allBindingsAccessor();
    // next,whether or not the supplied model property is 


observable,get its current value.
    var valueUnwrapped = ko.utils.unwrapObservable(value);
    // grab some more data from another bingding property
    var duration = allBindings.slideDuration || 500;
    // 500 is default duration unless otherwise specified
    // now manipulate the dom element
    if(valueUnwrapped == true) $(element).slideDown(duration);
    else $(element).slideUp(duration);
    }
  };




1、陣列繫結


this.items = ko.observableArray([
    { id: 1, name: "Apple Pie" },
    { id: 2, name: "Pumpkin Pie" },
    { id: 3, name: "Blueberry Torte" }
]);
this.items.push({ id: 4, "Strawberry Shortcake" });


重要是要注意,ObservableArrays跟蹤數組裡的item更改,而不是單獨的一個item的屬性。在上面的例子中,如果你的應用需要跟蹤item的name,那麼name屬性需要也加一個observable。


2、在IE6下,如果有空格要寫&nbsp;否則不呈現空格。




一、控制文字和展現
1、text繫結
2、visible繫結
3、html繫結
<div data-bind="html: details"></div>
 
<script type="text/javascript">
    var viewModel = {
        details: ko.observable() // Initially blank
    };
    viewModel.details("<em>For further details, view the 


report <a href='report.html'>here</a>.</em>"); // HTML content 


appears 
</script>


4、如果你提供的不是數字或者字串,你傳遞的是物件或陣列等,innerHTML/text bingding和yourParameter.toString()效果一樣。


5、css繫結
<div data-bind="css: { profitWarning: currentProfit() < 0 }">
   Profit Information
</div>
 
<script type="text/javascript">
    var viewModel = {
        currentProfit: ko.observable(150000) // Positive 


value, so initially we don't apply the "profitWarning" class
    };
    viewModel.currentProfit(-50); // Causes the 


"profitWarning" class to be applied
</script>


當currentProfit()<0時,css樣式名"profitWarning"就增加,否則移除這個css。


動態切換兩個css:
<div data-bind="css: profitStatus">
   Profit Information
</div>
 
<script type="text/javascript">
    var viewModel = {
        currentProfit: ko.observable(150000)
    };
 
    // Evalutes to a positive value, so initially we apply the 


"profitPositive" class
    viewModel.profitStatus = ko.computed(function() { // 


computed
        return this.currentProfit() < 0 ? "profitWarning" : 


"profitPositive";
    }, viewModel);
 
    // Causes the "profitPositive" class to be removed and 


"profitWarning" class to be added
    viewModel.currentProfit(-50);
</script>




可以同時使用多個css繫結:
<div data-bind="css: { profitWarning: currentProfit() < 0, majorHighlight: isSevere }">


當類標誌不合法時,如profitWarning,給其加上引號:'profitWarning'




6、style 繫結
<div data-bind="style: { color: currentProfit() < 0 ? 'red' : 


'black', fontWeight: isSevere() ? 'bold' : '' }">...</div>




7、attr繫結
<a data-bind="attr: { href: url, title: details }">
    Report
</a>
 
<script type="text/javascript">
    var viewModel = {
        url: ko.observable("year-end.html"),
        details: ko.observable("Report including final year-


end statistics")
    };
</script>


attr屬性名字不合法時,加上引號就可以。


二、控制流繫結
1、foreach繫結


   foreach繫結複製進入一個數組的標記部分,繫結每一個複製標記到相應的陣列條目。可以和其他控制流的if、with一起使用。


<h4>People</h4>
<ul data-bind="foreach: people">
    <li>
        Name at position <span data-bind="text: $index"> 


</span>:
        <span data-bind="text: name"> </span>
        <a href="#" data-bind="click: 


$parent.removePerson">Remove</a>
    </li>
</ul>
<button data-bind="click: addPerson">Add</button>
function AppViewModel() {
    var self = this;
 
    self.people = ko.observableArray([
        { name: 'Bert' },
        { name: 'Charles' },
        { name: 'Denise' }
    ]);
 
    self.addPerson = function() {
        self.people.push({ name: "New at " + new Date() });
    };
 
    self.removePerson = function() {
        self.people.remove(this);
    }
}
 
ko.applyBindings(new AppViewModel());






$index:序號
$parent:上一級元素


(1)$data


foreach塊可以在陣列項引用屬性,但是如果希望在陣列條目本身時引入屬性:
用$data代表每一項。
顯示每一項的具體內容:
<td data-bind="text: $data.firstName"></td>




(2)別名:as,加上引號,是給一個新名字為新的變數,不是改變值。
任何foreach迴圈內部,都會引用別名進入現在的陣列條目。這在祖先元素已經巢狀foreach塊,而且你需要在更高一層引用一個條目宣告時很有用。
<ul data-bind="foreach: { data: categories, as: 'category' }">
    <li>
        <ul data-bind="foreach: { data: items, as: 'item' }">
            <li>
                <span data-bind="text: category.name"></span>:
                <span data-bind="text: item"></span>
            </li>
        </ul>
    </li>
</ul>
 
<script>
    var viewModel = {
        categories: ko.observableArray([
            { name: 'Fruit', items: [ 'Apple', 'Orange', 


'Banana' ] },
            { name: 'Vegetables', items: [ 'Celery', 'Corn', 


'Spinach' ] }
        ])
    };
    ko.applyBindings(viewModel);
</script>


(3)只有部分元素迴圈遍歷,加上包裹元素在內部(如例子中的span標籤)。使用<!---->


<ul>
    <li class="header">Header item</li>
    <!-- ko foreach: myItems -->
        <li>Item <span data-bind="text: $data"></span></li>
    <!-- /ko -->
</ul>
 
<script type="text/javascript">
    ko.applyBindings({
        myItems: [ 'A', 'B', 'C' ]
    });
</script>




(4)想要顯示銷燬的條目,使用includeDestroyed
<div data-bind='foreach: { data: myArray, includeDestroyed: 


true }'>
    ...
</div>


(5)執行動畫效果
afterRender/afterAdd/beforeRemove/beforeMove/afterMove 
<ul data-bind="foreach: { data: myItems, afterAdd: 


yellowFadeIn }">
    <li data-bind="text: $data"></li>
</ul>
 
<button data-bind="click: addItem">Add</button>
 
<script type="text/javascript">
    ko.applyBindings({
        myItems: ko.observableArray([ 'A', 'B', 'C' ]),
        yellowFadeIn: function(element, index, data) {
            $(element).filter("li")
                      .animate({ backgroundColor: 'yellow' }, 


200)
                      .animate({ backgroundColor: 'white' }, 


800);
        },
        addItem: function() { this.myItems.push('New item'); }
    });
</script>


afterRender: 在foreach塊複製到文件中或foreach初始化,或新的條


目增加到陣列中,konckout將會提供如下引數到回撥函式中:
     插入到陣列中的dom元素
     對應被繫結的資料條目


afterAdd:當新條目增加到陣列中時激發。一般用來回調一個方法,比如$().fadeIn(),得到動畫過度當條目增加時。knockout會提供如下引數:
 被增加的dom節點,增加的陣列元素index,增加的陣列元素






beforeMove:當陣列條目在陣列中的位置發生改變,且在對應dom節點被移除前 被激發。它適用於所有序號改變的陣列元素,所以當你插入一個數組條目在陣列中,回撥函式會激發其他元素,知道他們的序號位置已經增加了1。可以使用beforeMove來儲存收影響元素的原始螢幕座標。這樣你可以使他們在afterMove回撥函式中動畫過度。
提供的回撥引數:
將要移動的dom節點,移動的陣列元素的序號,移動的陣列元素。


afterMove:當陣列中的陣列條目已經改變位置時,在foreach已經更新dom來匹配之後,被激發。
afterMove適用於所有序號被改變的陣列元素,回撥函式會激發其他元素,直到他們的序號位置都已經增加一。
konockout提供的回撥引數:
將要被移除的dom節點,移動的陣列元素的序號,移動的陣列元素。






2、if繫結


if和visible


if和visible差不多。不同在於,使用visible,包括標籤保持在dom中,經常使用data-bind屬性——visible繫結使用css來切換標籤的可見性。if只在表示式為真的情況下適用於增加或移除dom中繫結的後代元素包括的標籤。


例子:
<ul data-bind="foreach: planets">
    <li>
        Planet: <b data-bind="text: name"> </b>
        <div data-bind="if: capital">
            Capital: <b data-bind="text: capital.cityName"> 


</b>
        </div>
    </li>
</ul>
 
 
<script>
    ko.applyBindings({
        planets: [
            { name: 'Mercury', capital: null }, 
            { name: 'Earth', capital: { cityName: 'Barnsley' } 


}        
        ]
    });
</script>
在以上例子中,因為if,capital為null就不用繼續執行,發生錯誤:


計算後續capital.cityName不存在的屬性了。在javascript中,可以判斷if:capital判斷是否為空,但是不允許計算為空的值:


capital.cityName。


if後面的語句為true,顯示包含的標籤。
if後面的語句為false,包含的標籤將會從document中移走而不是適用於任何剛開始的繫結。


如果表示式提及到任何可觀測值,當它們改變時表示式會被重新計算。
相應的,帶有if標籤塊將會動態增加和移除當表示式結果發生改變時。
data-bind屬性將會被用於一個新的副本包含標籤。


當想要實現控制某一部分標籤顯示隱藏,
使用<!-- ko --><!-- /ko -->
<ul>
    <li>This item always appears</li>
    <!-- ko if: someExpressionGoesHere -->
        <li>I want to make this item present/absent 


dynamically</li>
    <!-- /ko -->
</ul>




3、ifnot繫結
和if一樣。完全可以用if代替。


4、with繫結
with繫結建立了一個新的上下文,所以後代元素被繫結一個詳細的物件上下文。
可以任意使用其他控制流繫結如if/foreach和巢狀with繫結。


以下是一個簡單的切換繫結上下文到子物件。
注意data-bind屬性,沒有必要加上latitude和longitude的字首


coords.。因為繫結上下文已經切換到coords了。
<h1 data-bind="text: city"> </h1>
<p data-bind="with: coords">
    Latitude: <span data-bind="text: latitude"> </span>,
    Longitude: <span data-bind="text: longitude"> </span>
</p>
 
<script type="text/javascript">
    ko.applyBindings({
        city: "London",
        coords: {
            latitude:  51.5001524,
            longitude: -0.1262362
        }
    });
</script>




複雜一點的with例子:
<form data-bind="submit: getTweets">
    Twitter account:
    <input data-bind="value: twitterName" />
    <button type="submit">Get tweets</button>
</form>
 
<div data-bind="with: resultData">
    <h3>Recent tweets fetched at <span data-bind="text: 


retrievalDate"> </span></h3>
    <ol data-bind="foreach: topTweets">
        <li data-bind="text: text"></li>
    </ol>
 
    <button data-bind="click: $parent.clearResults">Clear 


tweets</button>
</div>




function AppViewModel() {
    var self = this;
    self.twitterName = ko.observable('@example');
    self.resultData = ko.observable(); // No initial value
 
    self.getTweets = function() {
        var name = self.twitterName(),
            simulatedResults = [
                { text: name + ' What a nice day.' },
                { text: name + ' Building some cool apps.' },
                { text: name + ' Just saw a famous celebrity 


eating lard. Yum.' }
            ];
 
        self.resultData({ retrievalDate: new Date(), 


topTweets: simulatedResults });
    }
 
    self.clearResults = function() {
        self.resultData(undefined);
    }
}
 
ko.applyBindings(new AppViewModel());




with繫結動態增加移除後代元素依賴於聯絡的值是null/undefined或非空。
如果需要訪問父元素繫結的上下文中的data/functions,可以使用


$parent和root。




關於with的子屬性設定的兩種寫法:
1、寫在viewmodel物件中
var viewModel ={
  lcon: {
                lname: "lfwefw ",
                showCon: [
                 { name: "s", textInput: "second" },
                 { name: "t", textInput: "third" },
                 { name: "f", textInput: "first" }]
            }




}


2、用建立viewModel函式的寫法
function AppViewModel() {
    var self = this;
    self.resultData({ retrievalDate: new Date(), topTweets:    


 simulatedResults });
}




與其他沒有包括標籤一樣:
<ul>
    <li>Header element</li>
    <!-- ko with: outboundFlight -->
        ...
    <!-- /ko -->
    <!-- ko with: inboundFlight -->
        ...
    <!-- /ko -->
</ul>

例子:

<html>

<head>
    <title></title>


    <script type="text/javascript" src="js/jquery-1.8.2.min.js"></script>
    <script type="text/javascript" src="js/jquery.tmpl.js"></script>
    <script type="text/javascript" src="js/knockout-3.1.0.js"></script>
    <script type="text/javascript" src="js/knockout.simpleGrid.js"></script>
    <style type="text/css">
    </style>
</head>
<body>
    <form data-bind="submit: showDetail">
        <div>
            Your Account:<input type="text" data-bind="value: inputCon" />
            <button type="submit">提交資訊</button>
        </div>
    </form>
    <div data-bind="visible: hiddenDetail">
        <div data-bind="text: inputCon"></div>
        <div data-bind="with: lcon">
            <div data-bind="text: lname"></div>
            <div data-bind="foreach: showCon">
                hello:<span data-bind="text: name"></span>
                <span data-bind=" text: name"></span>
                <br />


            </div>
        </div>
        <button type="submit" data-bind="click: clearCon">隱藏</button>
    </div>


    <script type="text/javascript">
        var viewModel = {
            inputCon: ko.observable("@mail"),
            showDetail: ko.observable(true),
            hiddenDetail: ko.observable(false)
           ,


            lcon: {
                lname: "lfwefw ",
                showCon: [
                 { name: "s", textInput: "second" },
                 { name: "t", textInput: "third" },
                 { name: "f", textInput: "first" }]
            }
        };
        viewModel.showDetail = function () { viewModel.hiddenDetail(true); }
        viewModel.clearCon = function () { viewModel.hiddenDetail(false); }
        ko.applyBindings(viewModel);
    </script>

</body>

</html>