Knockoutjs官网翻译系列(一)
? ? ? ?最近馬上要開始一個新項目的研發(fā),作為第一次mvvm應(yīng)用的嘗試,我決定使用knockoutjs框架。作為學(xué)習(xí)的開始就從官網(wǎng)的Document翻譯開始吧,這樣會增加印象并加入自己的思考,說是翻譯也并不是純粹的翻譯,會加入自己對知識點的思考以及自己的嘗試,在系列最后也希望用一個應(yīng)用案例作為結(jié)尾。希望自己能堅持下來并有所收獲,理解不對的地方大家也指出來避免我”誤入歧途“。也并不會翻譯所有的內(nèi)容,我會根據(jù)自己的經(jīng)驗選擇最能反映它使用和精髓的部分。當(dāng)前版本為3.4
? ? ? 好了,閑言少敘,正篇開始。
===================================華麗的分割線============================================
? ? ? knocket主要圍繞由以下三個核心特征組成:
? ? ??
? ? ?MVVM and View Models
? ? ??Model-View-View Model (MVVM)?是一種創(chuàng)建用戶界面或用戶接口的設(shè)計模式。你可以通過將UI拆分成下面三個部分從而將復(fù)雜的UI簡潔化,清晰化:
- Model(數(shù)據(jù)模型): 應(yīng)用程序存儲數(shù)據(jù)。模型包括了你應(yīng)用程序域中與業(yè)務(wù)相關(guān)的數(shù)據(jù)以及這些數(shù)據(jù)對應(yīng)的操作(例如 一個銀行賬戶模型具有轉(zhuǎn)賬的功能)并且它跟UI是相互獨立 的。 當(dāng)時用KO的時候,通常這類模型是通過ajax從服務(wù)器端進(jìn)行獲取的。
- ViewModel(視圖模型): 服務(wù)于數(shù)據(jù)模型,為數(shù)據(jù)模型在UI上的展現(xiàn)及UI上的操作進(jìn)行包裝服務(wù)。 例如, 如果你要在UI上做一個列表展現(xiàn), 你的視圖模型將會是包含一個數(shù)據(jù)集合的對象, 并提供一些添加和刪除數(shù)據(jù)的相關(guān)方法。需要注意的是視圖模型并不是UI本身,它并不包括任何UI元素,比如按鈕啊,標(biāo)簽啊樣式之類。它也不是持久化的數(shù)據(jù)對象,它只是為數(shù)據(jù)模型臨時保存一些用戶正在處理的數(shù)據(jù)。當(dāng)我們在使用KO的時候,它無非就是一些純粹的javascript對象而已。
- A?view(視圖): 一個可視,可交互的真正的UI展現(xiàn),他展現(xiàn)著視圖模型的當(dāng)前狀態(tài)。它所展現(xiàn)的信息來自于視圖模型,并且向視圖模型發(fā)送命令執(zhí)行動作 (例如: 當(dāng)用戶點擊按鈕的時候,視圖向視圖模型發(fā)送命令,視圖模型進(jìn)行真正的操作),并且當(dāng)視圖模型屬性發(fā)生變化的時候,視圖會自動進(jìn)行展現(xiàn)的更新。當(dāng)時用KO的時候,你的視圖中的Html元素內(nèi)容可以通過聲明式綁定與視圖模型進(jìn)行連接從而決定UI如何展現(xiàn)。另外,你也可以通過使用模板的方式來使用視圖模型中的數(shù)據(jù)生成UI中的Html內(nèi)容。(模板后面會提到)
? ? ? 好了,讓我們來舉個很小的例子來看看上面說的視圖與視圖模型在KO中是如何協(xié)作的。創(chuàng)建一個視圖模型對象非常容易,隨意聲明一個javascript對象我們就可以將它作為視圖模型對象。例如:
//創(chuàng)建一個視圖模型對象var myViewModel = {personName: 'Bob',personAge: 123};
ko.applyBindings(myViewModel);//ko是knockoutjs中的全局對象,這句話的意思是將數(shù)據(jù)模型對象與UI中所有有data-bind的屬性進(jìn)行聲明綁定的元素進(jìn)行連接
然后我們就可以創(chuàng)建一個非常簡單的視圖來展現(xiàn)上面的視圖對象。還記得嗎?他們使用聲明式綁定來進(jìn)行連接。下面的視圖用來展現(xiàn)視圖模型對象中的personName數(shù)據(jù)。
The name is <span data-bind="text: personName"></span>?
好了現(xiàn)在如果運行頁面的話將會顯示如下運行結(jié)果:
通過上面的例子我們可以看到,在UI上賦值我們并沒有像jquery一樣通過js來控制,而是使用聲明綁定的方式在UI元素和js數(shù)據(jù)對象上建立聯(lián)系,自動展現(xiàn)。在上面的代碼標(biāo)簽中data-bind?并不是Html中的原生標(biāo)記,它在Html5中得到瀏覽器的支持,是KO框架用來進(jìn)行聲明式綁定的工具,所以在KO中進(jìn)行聲明式綁定,都通過data-bind屬性進(jìn)行。有了視圖模型,有了相應(yīng)視圖,最后要進(jìn)行兩者的連接了,所以下面這行代碼必不可少:
ko.applyBindings(myViewModel); //將myViewModel對象與UI中所有進(jìn)行了聲明式綁定的元素進(jìn)行連接,注意:是所有。完整測試代碼:
The name is <span data-bind="text: personName"></span> @section scripts {<script src="~/Scripts/knockout-3.4.0.js"></script><script type="text/javascript">$(function () {var myViewModel = {personName: 'Bob',personAge: 123};ko.applyBindings(myViewModel);});</script> }?
? ? ? 關(guān)于ko.appyBindings(myViewModel)中參數(shù)的作用說明一下:第一個參數(shù)說明在整個UI中你希望使用哪個視圖模型對象與視圖中的聲明綁定進(jìn)行連接。你也可以傳遞第二個參數(shù)來決定這個視圖模型與UI中的哪個特定的聲明式綁定(data-bind)進(jìn)行連接,而不是與所有的進(jìn)行連接。舉個例子,?ko.applyBindings(myViewModel, document.getElementById('someElementId'))。這就限制了這個視圖模型對象只能與ID為someElementId?的Html元素對象以及它的后代元素對象進(jìn)行連接,這樣的話當(dāng)你想要定義多個視圖模型對象并且與頁面中不同的元素進(jìn)行綁定的時候就會特別有用。到目前為止真的是相當(dāng)簡單吧。
? ? ?Observables
? ? ?好了,你已經(jīng)看到了如何創(chuàng)建一個基本的視圖模型以及如何通過綁定進(jìn)行它的屬性數(shù)據(jù)的展現(xiàn)。但是使用KO一個核心的好處是當(dāng)視圖模型內(nèi)容改變的時候它還會自動更新你的UI,反之亦然。這有時會大大簡化你的代碼(我們稍后展示這個效果)。那么KO如何知道你的視圖模型什么時候發(fā)生了改變進(jìn)而更新你的UI呢?答案是:你需要將你的數(shù)圖模型中的屬性聲明為observable類型對象。 observables類型對象非常特殊,當(dāng)視圖模型發(fā)生改變的時候,他們可以向訂閱者發(fā)出通知,并自動建立與訂閱者的關(guān)系,訂閱者也就是具有聲明式綁定的元素。舉個例子, 重寫一下上面的代碼如下:
? ??
$(function () {var myViewModel = {personName: ko.observable('Bob'),personAge: ko.observable(123)};ko.applyBindings(myViewModel);});? ? ?現(xiàn)在,你完全不需要視圖 data-bind?聲明部分保持不變. 與之前代碼不同的是,現(xiàn)在ko可以自動監(jiān)測變化了, 一旦視圖模型有數(shù)據(jù)發(fā)生變化,它就會自動更新視圖。
? ? ?Observables屬性的讀取與寫入
? ?? 要讀取observable的當(dāng)前值,只需要像調(diào)用方法一樣以無參數(shù)的方式調(diào)用它。以上面的代碼為例,?myViewModel.personName()?將會返回?'Bob',而myViewModel.personAge()?將返回123。
? ? ?要向observable屬性中寫入一個值的話也跟上面一樣進(jìn)行調(diào)用,只不過傳入一個你想要寫入的新值就可以了。舉個例子:調(diào)用myViewModel.personName('Mary')?將會為personName賦一個新的名字。另外KO還提供了一個非常方便的代碼鏈寫法。?像這樣:myViewModel.personName('Mary').personAge(50)?會修改personName為?'Mary'?,personAge修改為?50。
? ? ?observables的核心作用就是"觀察" ,也就是說, 被聲明為observable的屬性將來是會被雙向通知的,它通知其它UI元素它已經(jīng)被修改了,并且觀察相關(guān)UI元素內(nèi)容,并將變化值更新到ViewModel對象上。KO框架中的很多內(nèi)置綁定就是用來干這事兒的。所以,當(dāng)你在UI元素上(例如span標(biāo)簽)寫上data-bind="text: personName"的時候?text?綁定類型將把這個span元素進(jìn)行注冊并做好被通知的準(zhǔn)備只要視圖對象上的personName發(fā)生了該表,span就會被通知修改內(nèi)部的文本內(nèi)容(假設(shè)personName是一個observable值,另外除了text綁定還有許多其它類型綁定,我們后面提到)。
? ? ?當(dāng)你通過調(diào)用myViewModel.personName('Mary')來修改personName的值的時候, text綁定將會自動更新相關(guān)DOM元素的text內(nèi)容?。
? ?observables的顯示訂閱處理??
? ? 通常你無需干預(yù)訂閱的過程,所以初學(xué)者可以暫時跳過這一小節(jié)。
? ? 當(dāng)observable類型數(shù)據(jù)發(fā)生改變后如果你希望在這個過程中做一些處理,你可以調(diào)用observable屬性上的subscribe方法來將自己的處理代碼注冊進(jìn)來。舉個例子:
myViewModel.personName.subscribe(function(newValue) {alert("The person's new name is " + newValue); });? ? 上面這段代碼執(zhí)行后,如果修改了personName的值后,那么將會彈出一個警告框,并且通過newValue參數(shù)可以獲取當(dāng)前正在更新的值。這個過程叫訂閱注冊。
? ??subscribe方法接受三個傳入?yún)?shù):?callback?是一個function當(dāng)通知到來時會自動執(zhí)行,?target?(可選) 定義了在callback方法中?this代表了哪個對象(默認(rèn)的話this就是當(dāng)前視圖模型對象), event(可選; 默認(rèn)值是"change") 事件名稱,是指當(dāng)什么類型的事件發(fā)生的時候會有通知到來,默認(rèn)情況下就是當(dāng)值發(fā)生改變的時候。(其它類型我們后面談到)。
? ? ?當(dāng)然了,一旦你注冊了一個自己的訂閱,你也可以根據(jù)需要在未來的某個時候取消這個訂閱,你需要先定義一個變量來接收subscribe當(dāng)前的返回值,然后調(diào)用dispose方法。代碼如下
var subscription = myViewModel.personName.subscribe(function (newValue) { /* do stuff */ }); // ...then later... subscription.dispose();? ? ?如果你希望在observable類型值在發(fā)生改變,但被賦值之前做一些處理的話,你也可以在beforeChange?事件上注冊自己的處理,代碼如下:
myViewModel.personName.subscribe(function(oldValue) {alert("The person's previous name is " + oldValue); }, null, "beforeChange");? ? 注意: Knockout 是否觸發(fā)上面的訂閱還有一個默認(rèn)條件就是新的值必須與老的值不相同,如果賦值時是相同值的話那么將不會觸發(fā)這兩個訂閱。如果需要更改這種默認(rèn)動作可以使用訂閱器上的extend方法來修改。代碼如下:
myViewModel.personName.extend({ notify: 'always' });? ? 最后,如果你的observable屬性在更新時的動作比較耗時或者會更新的很頻繁,你可以通過限制通知的時間間隔,畢竟訂閱通知會有性能影響。做法如下:
myViewModel.personName.extend({ rateLimit: 50 });? ? 這樣的話就算是頻繁更新屬性值,每次通知的事件間隔也會控制在50毫秒。測試代碼如下:
<button type="button" id="btnStart">點擊測試</button> <span id="clickcontent"></span> @section scripts {<script src="~/Scripts/knockout-3.4.0.js"></script><script type="text/javascript">$(function () {var myViewModel = {//personName: ko.observable("ZhouBo") personName: ko.observable("ZhouBo")};myViewModel.personName.extend({ notify: 'always' });myViewModel.personName.extend({ rateLimit: 5000 });ko.applyBindings(myViewModel);var index = 0;$('#btnStart').click(function () {$('#clickcontent').text(++index);myViewModel.personName(++index);});});說明:如果我快速點擊按鈕 btnStart,則5秒鐘之后第一個span的內(nèi)容才會發(fā)生變化,也就是5廟后才發(fā)送了一次通知。
?
轉(zhuǎn)載于:https://www.cnblogs.com/MichaelBang/p/5589421.html
總結(jié)
以上是生活随笔為你收集整理的Knockoutjs官网翻译系列(一)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: RedHat Enterprise Li
- 下一篇: vs自带iis局域网调试