- KnockoutJS 教程
- KnockoutJS - 首頁
- KnockoutJS - 概述
- KnockoutJS - 環境設定
- KnockoutJS - 應用
- KnockoutJS - MVVM 框架
- KnockoutJS - 可觀察物件
- 計算可觀察物件
- KnockoutJS - 宣告式繫結
- KnockoutJS - 依賴項跟蹤
- KnockoutJS - 模板
- KnockoutJS - 元件
- KnockoutJS 資源
- KnockoutJS 快速指南
- KnockoutJS - 資源
- KnockoutJS - 討論
KnockoutJS 快速指南
KnockoutJS - 概述
KnockoutJS 本質上是一個用 JavaScript 編寫的庫,基於 MVVM 模式,幫助開發人員構建豐富且響應迅速的網站。該模型將應用程式的模型(儲存的資料)、檢視(UI)和檢視模型(模型的 JavaScript 表示)分開。
KnockoutJS 由微軟員工 Steve Sanderson 於 2010 年 7 月 5 日開發並作為開源專案維護。KO 是 KnockoutJS 的縮寫。KO 支援所有主流瀏覽器 - IE 6+、Firefox 3.5+、Chrome、Opera、Safari(桌面/移動)。
KnockoutJS 的特性
以下是 KnockoutJS 一些最突出的特性的列表:
宣告式繫結 - 透過使用非常簡單的語法,HTML DOM 元素透過 data-bind 屬性連線到模型。使用此功能可以輕鬆實現響應能力。
自動 UI 重新整理 - 對模型資料進行的任何更改都會自動反映在 UI 中,反之亦然。無需編寫額外的程式碼。
依賴項跟蹤 - KO 屬性與 KO 庫函式/元件之間的關係是透明的。自動跟蹤 KO 屬性中的資料更改並更新相應的受影響區域。
模板 - 模板是一種簡單方便的方式來構建複雜的 UI 結構 - 可以根據檢視模型資料重複或巢狀塊。
可擴充套件 - 非常容易擴充套件自定義行為。
為什麼要使用 KnockoutJS?
KnockoutJS 庫提供了一種簡單且乾淨的方式來處理複雜的資料驅動介面。可以為 Javascript 物件建立自我更新的 UI。
它是一個純 JavaScript 庫,可以與任何 Web 框架一起使用。它不是 JQuery 的替代品,但可以作為補充提供智慧功能。
KnockoutJS 庫檔案非常小巧輕便。
KnockoutJS 獨立於任何其他框架。它與其他客戶端或伺服器端技術相容。
最重要的是 KnockoutJS 是開源的,因此可以免費使用。
KnockoutJS 文件齊全。官方網站提供了完整的文件,包括 API 文件、即時示例和互動教程。
KnockoutJS - 環境設定
使用 KnockoutJS 非常簡單。只需在 HTML 頁面中使用 <script> 標籤引用 JavaScript 檔案即可。
可以透過以下方式訪問 Knockout.js:
您可以從其官方網站下載 Knockout.js 的生產版本
將顯示如下面的影像所示的頁面。單擊下載連結,您將獲得最新的 knockout.js 檔案。
現在,請參考以下程式碼中顯示的檔案。
<script type = 'text/javascript' src = 'knockout-3.3.0.js'></script>
更新 src 屬性以匹配下載的檔案所在的路徑。
您可以從 CDN 引用 KnockoutJS 庫:
您可以在程式碼中從Microsoft Ajax CDN引用 KnockoutJS 庫,如下所示:
<script src = "https://ajax.aspnetcdn.com/ajax/knockout/knockout-3.1.0.js" type = "text/javascript"></script>
或者,您可以從CDNJS引用 KnockoutJS 庫的壓縮版本,如下所示:
<script src = "https://cdnjs.cloudflare.com/ajax/libs/knockout/3.3.0/knockout-min.js" type = "text/javascript"></script>
注意 - 在本教程的所有章節中,我們都引用了 KnockoutJS 庫的 CDN 版本。
示例
KnockoutJS 基於模型-檢視-檢視模型 (MVVM) 模式。我們將在KnockoutJS - MVVM 框架章節中深入研究此模式。首先,讓我們來看一個 KnockoutJS 的簡單示例。
<!DOCTYPE html>
<head>
<title>KnockoutJS Simple Example</title>
<script src = "https://ajax.aspnetcdn.com/ajax/knockout/knockout-3.1.0.js"
type = "text/javascript"></script>
</head>
<body>
<!-- This is called "view" of HTML markup that defines the appearance of UI -->
<p>First String: <input data-bind = "value: firstString" /></p>
<p>Second String: <input data-bind = "value: secondString" /></p>
<p>First String: <strong data-bind = "text: firstString">Hi</strong></p>
<p>Second String: <strong data-bind = "text: secondString">There</strong></p>
<p>Derived String: <strong data-bind = "text: thirdString"></strong></p>
<script>
<!-- This is called "viewmodel". This javascript section defines the data and
behavior of UI -->
function AppViewModel() {
this.firstString = ko.observable("Enter First String");
this.secondString = ko.observable("Enter Second String");
this.thirdString = ko.computed(function() {
return this.firstString() + " " + this.secondString();
}, this);
}
// Activates knockout.js
ko.applyBindings(new AppViewModel());
</script>
</body>
</html>
以下行引用了 KnockoutJS 庫。
<script src = "https://ajax.aspnetcdn.com/ajax/knockout/knockout-3.1.0.js" type = "text/javascript"> </script>
此行引用了 KnockoutJS 庫。
我們有兩個輸入框:第一個字串和第二個字串。這兩個變數在 ViewModel 中分別初始化為值“輸入第一個字串”和“輸入第二個字串”。
<p>First String: < input data-bind = "value: firstString" /> </p>
這就是我們如何使用主體部分中的'data-bind'屬性將 ViewModel 中的值繫結到 HTML 元素。
這裡,'firstString' 指的是 ViewModel 變數。
this.firstString = ko.observable("Enter First String");
ko.observable是一個概念,它密切關注值的變化,以便它可以更新底層的 ViewModel 資料。
為了更好地理解這一點,讓我們將第一個輸入框更新為“Hello”,將第二個輸入框更新為“TutorialsPoint”。您將看到這些值會同時更新。我們將在KnockoutJS - 可觀察物件章節中更多地學習這個概念。
this.thirdString = ko.computed(function() {
return this.firstString() + " " + this.secondString();
}, this);
接下來,我們在檢視模型中有一個計算函式。此函式根據前面提到的兩個字串推匯出第三個字串。因此,對這些字串進行的任何更新都會自動反映在此派生字串中。無需編寫額外的程式碼來實現此目的。這只是一個簡單的例子。我們將在KnockoutJS - 計算可觀察物件章節中學習這個概念。
輸出
將以上程式碼儲存為my_first_knockoutjs_program.html。在瀏覽器中開啟此檔案,您將看到如下所示的輸出。
將字串修改為“Hello”和“TutorialsPoint”,輸出將更改如下。
KnockoutJS - 應用
KnockoutJS 廣泛用於單頁面應用程式 - 一個建立的網站,能夠透過單個頁面載入動態檢索所有必要資料,從而減少伺服器往返次數。
KnockoutJS 是一個客戶端框架。這是一個 JavaScript 庫,它使將 HTML 繫結到域資料變得非常容易。它實現了稱為模型-檢視-檢視模型 (MVVM) 的模式。可觀察物件是 KnockoutJS 的神奇成分。由於可觀察屬性,所有資料都保持同步。
架構
檢視
檢視只不過是使用 HTML 元素和 CSS 樣式建立的使用者介面。
您可以使用 KnockoutJS 將 HTML DOM 元素繫結到資料模型。它使用'data-bind'概念在檢視和檢視模型之間提供雙向資料繫結,這意味著在 UI 中進行的任何更新都反映在資料模型中,並且在資料模型中進行的任何更改都反映在 UI 中。可以使用 knockoutJS 建立自更新的 UI。
檢視模型
檢視模型是一個 JavaScript 物件,其中包含表示資料所需的屬性和函式。檢視和檢視模型透過 HTML 中使用的宣告式 data-bind 概念連線在一起。這使得在不更改檢視模型的情況下輕鬆更改 HTML 變得容易。KnockoutJS 透過使用可觀察物件來處理它們之間的自動資料重新整理。
資料同步是透過首先使用 data-bind 將 DOM 元素繫結到資料模型,然後透過使用可觀察物件重新整理這兩個元件來實現的。由於這種資料同步,依賴項跟蹤是自動完成的。無需編寫額外的程式碼即可實現它。KnockoutJS 允許在顯示和底層資料之間建立直接連線。
您可以建立自己的繫結,稱為自定義繫結,用於應用程式特定的行為。透過這種方式,Knockout 可以直接控制如何將資料轉換為 HTML。
模型
模型是伺服器上的域資料,並在從檢視模型傳送/接收請求時進行操作。
資料可以儲存在資料庫、cookie 或其他形式的持久儲存中。KnockoutJS 不關心它是如何儲存的。程式設計師負責在儲存的資料和 KnockoutJS 之間進行通訊。
大多數情況下,資料透過 Ajax 呼叫儲存和載入。
KnockoutJS - MVVM 框架
模型-檢視-檢視模型 (MVVM)是一種用於開發軟體應用程式的體系結構設計模式。MVVM 由微軟架構師 John Gossman 於 2005 年開發。此模式源自模型-檢視-控制器 (MVC) 模式。MVVM 的優點是它將應用程式層的圖形使用者介面與業務邏輯分離。MVVM 負責以非常容易表示和管理的方式處理來自底層模型的資料。MVVM 中的檢視模型表示檢視狀態和操作的抽象版本。
檢視類不知道模型和檢視模型類是否存在,同樣,模型和檢視模型也不知道檢視是否存在。模型也不知道檢視模型和檢視是否存在。
架構
檢視
檢視是使用標記語言建立的圖形使用者介面,用於表示資料。檢視透過 data-bind 概念繫結到檢視模型的屬性,這間接連線到模型資料。對於在檢視模型中進行的任何更改,無需更改檢視。由於繫結,對檢視模型中資料所做的更改會自動傳播到檢視中。
模型
模型是域資料或業務物件,它儲存即時資料。模型不包含行為。行為主要在業務邏輯中實現。
檢視模型
檢視模型是中心位置,模型的資料和檢視的顯示邏輯捆綁在一起。檢視模型儲存資料的動態狀態。在檢視和檢視模型之間存在一個隱式繫結器來相互通訊。此繫結包括宣告式資料和命令繫結。透過此繫結實現檢視和檢視模型的同步。在檢視中進行的任何更改都會反映在檢視模型中,類似地,檢視模型中的任何更改都會自動反映在檢視中。這種雙向繫結機制的存在是此 MVVM 模式的關鍵方面。
KnockoutJS - 可觀察物件
KnockoutJS 建立在以下 3 個重要概念之上。
可觀察物件及其之間的依賴項跟蹤 - DOM 元素透過 'data-bind' 連線到檢視模型。它們透過可觀察物件交換資訊。這會自動處理依賴項跟蹤。
UI 和檢視模型之間的宣告式繫結 - DOM 元素透過 'data-bind' 概念連線到檢視模型。
建立可重用元件的模板 - 模板提供了一種強大的方法來建立複雜的 Web 應用程式。
我們將在本章中學習可觀察物件。
顧名思義,當您將檢視模型資料/屬性宣告為可觀察物件時,每次資料修改都會自動反映在使用該資料的所有位置。這也包括重新整理相關的依賴項。KO 會處理這些事情,無需編寫額外的程式碼即可實現此目的。
使用可觀察物件,使 UI 和檢視模型動態通訊變得非常容易。
語法
您只需要使用函式ko.observable()宣告檢視模型屬性即可使其成為可觀察物件。
this.property = ko.observable('value');
示例
讓我們來看下面的示例,它演示了可觀察物件的使用。
<!DOCTYPE html>
<head>
<title>KnockoutJS Observable Example</title>
<script src = "https://ajax.aspnetcdn.com/ajax/knockout/knockout-3.1.0.js"
type = "text/javascript"></script>
</head>
<body>
<!-- This is called "view" of HTML markup that defines the appearance of UI -->
<p>Enter your name: <input data-bind = "value: yourName" /></p>
<p>Hi <strong data-bind = "text: yourName"></strong> Good Morning!!!</p>
<script>
<!-- This is called "viewmodel". This javascript section defines the data and behavior of UI -->
function AppViewModel() {
this.yourName = ko.observable("");
}
// Activates knockout.js
ko.applyBindings(new AppViewModel());
</script>
</body>
</html>
以下行用於輸入框。可以看到,我們使用了 data-bind 屬性將 yourName 值繫結到 ViewModel。
<p>Enter your name: <input data-bind = "value: yourName" /> <p>
以下行僅列印 yourName 的值。請注意,這裡 data-bind 型別是文字,因為我們只是讀取值。
<p>Hi <strong data-bind = "text: yourName"></strong> Good Morning!!!</p>
在下面的程式碼行中,ko.observable 會持續關注 yourName 變數的任何資料修改。一旦發生修改,相關的地方也會更新為修改後的值。執行以下程式碼時,會彈出一個輸入框。當您更新該輸入框時,新值將反映或重新整理到任何使用該值的地方。
this.yourName = ko.observable("");
輸出
讓我們按照以下步驟來了解上面程式碼是如何工作的:
將上述程式碼儲存到名為first_observable_pgm.htm的檔案中。
在瀏覽器中開啟此 HTML 檔案。
輸入名稱為 Scott,並觀察名稱是否反映在輸出中。
資料修改可以來自 UI 或 ViewModel。無論資料從哪裡更改,UI 和 ViewModel 都會保持彼此同步。這使得它成為一個雙向繫結機制。在上面的例子中,當您在輸入框中更改您的姓名時,ViewModel 會獲得一個新值。當您從 ViewModel 內部更改 yourName 屬性時,UI 會收到一個新值。
讀取和寫入可觀察物件
下表列出了可在可觀察物件上執行的讀寫操作。
| 序號 | 讀寫操作及語法 |
|---|---|
| 1 | 讀取 要讀取值,只需像這樣呼叫可觀察屬性,無需引數:AppViewModel.yourName(); |
| 2 | 寫入 要在可觀察屬性中寫入/更新值,只需像這樣在引數中傳遞所需的值:AppViewModel.yourName('Bob'); |
| 3 | 批次寫入 可以使用鏈式語法在同一行更新多個 ViewModel 屬性,例如:AppViewModel.yourName('Bob').yourAge(45); |
可觀察陣列
可觀察物件的宣告負責單個物件的修改。ObservableArray 用於處理物件的集合。當您處理包含多種型別的值且基於使用者操作頻繁更改其狀態的複雜應用程式時,這是一個非常有用的功能。
語法
this.arrayName = ko.observableArray(); // It's an empty array
可觀察陣列只跟蹤其中新增或刪除了哪些物件。如果單個物件的屬性被修改,它不會發出通知。
首次初始化
您可以初始化陣列,並同時將其宣告為可觀察物件,方法是將初始值傳遞給建構函式,如下所示。
this.arrayName = ko.observableArray(['scott','jack']);
從可觀察陣列讀取
您可以按如下方式訪問可觀察陣列元素。
alert('The second element is ' + arrayName()[1]);
可觀察陣列函式
KnockoutJS 有自己的一套可觀察陣列函式。它們很方便,因為:
這些函式在所有瀏覽器上都能正常工作。
這些函式將自動處理依賴項跟蹤。
語法易於使用。例如,要將元素插入陣列,您只需使用 arrayName.push('value') 而不是 arrayName().push('value')。
以下是各種可觀察陣列方法的列表。
| 序號 | 方法及描述 |
|---|---|
| 1 | push('value')
在陣列末尾插入一個新項。 |
| 2 | pop()
刪除陣列中的最後一項並返回它。 |
| 3 | unshift('value')
在陣列開頭插入一個新值。 |
| 4 | shift()
刪除陣列中的第一項並返回它。 |
| 5 | reverse()
反轉陣列的順序。 |
| 6 | sort()
按升序對陣列項進行排序。 |
| 7 | splice(start-index,end-index)
接受 2 個引數 - start-index 和 end-index - 從 start 到 end index 刪除項,並將它們作為陣列返回。 |
| 8 | indexOf('value')
此函式返回提供的引數第一次出現的索引。 |
| 9 | slice(start-index,end-index)
此方法切出一部分陣列。返回從 start-index 到 end-index 的項。 |
| 10 | removeAll()
刪除所有項並將其作為陣列返回。 |
| 11 | remove('value')
刪除與引數匹配的項並作為陣列返回。 |
| 12 | remove(function(item) { condition })
刪除滿足條件的項並將其作為陣列返回。 |
| 13 | remove([set of values])
刪除與給定值集匹配的項。 |
| 14 | destroyAll() 將陣列中所有項的 _destroy 屬性標記為 true。 |
| 15 | destroy('value') 搜尋與引數相等的項,並將其標記為一個特殊屬性 _destroy,值為 true。 |
| 16 | destroy(function(item) { condition}) 查詢所有滿足條件的項,並將它們標記為 _destroy 屬性,值為 true。 |
| 17 | destroy([set of values]) 查詢與給定值集匹配的項,將其標記為 _destroy 屬性,值為 true。 |
注意 - 可觀察陣列中的 Destroy 和 DestroyAll 函式主要供“Ruby on Rails”開發人員使用。
當您使用 destroy 方法時,相應的項不會立即從陣列中真正刪除,而是透過將其 _destroy 屬性標記為 true 來隱藏,以便 UI 無法讀取它們。標記為 _destroy 等於 true 的項將在以後處理 JSON 物件圖時刪除。
KnockoutJS - 計算可觀察物件
計算可觀察物件是一個函式,它依賴於一個或多個可觀察物件,並在其底層可觀察物件(依賴項)更改時自動更新。
計算可觀察物件可以進行鏈式呼叫。
語法
this.varName = ko.computed(function(){
...
... // function code
...
},this);
示例
讓我們看下面的例子,它演示了計算可觀察物件的使用。
<!DOCTYPE html>
<head >
<title>KnockoutJS Computed Observables</title>
<script src = "https://ajax.aspnetcdn.com/ajax/knockout/knockout-3.1.0.js"></script>
</head>
<body>
<p>Enter first number: <input data-bind = "value: a" /></p>
<p>Enter second number: <input data-bind = "value: b"/></p>
<p>Average := <span data-bind="text: totalAvg"></span></p>
<script>
function MyViewModel() {
this.a = ko.observable(10);
this.b = ko.observable(40);
this.totalAvg = ko.computed(function() {
if(typeof(this.a()) !== "number" || typeof(this.b()) !== "number") {
this.a(Number(this.a())); //convert string to Number
this.b(Number(this.b())); //convert string to Number
}
total = (this.a() + this.b())/2 ;
return total;
},this);
}
ko.applyBindings(new MyViewModel());
</script>
</body>
</html>
在下面的程式碼行中,前兩行用於接受輸入值。第三行列印這兩個數字的平均值。
<p>Enter first number: <input data-bind = "value: a" /></p> <p>Enter second number: <input data-bind = "value: b"/></p> <p>Average := <span data-bind = "text: totalAvg"></span></p>
在下面的程式碼行中,可觀察物件 a 和 b 的型別在 ViewModel 內部首次初始化時為數字。但是,在 KO 中,從 UI 接收的每個輸入預設情況下都採用字串格式。因此,需要將其轉換為數字,以便對它們執行算術運算。
this.totalAvg = ko.computed(function() {
if(typeof(this.a()) !== "number" || typeof(this.b()) !== "number") {
this.a(Number(this.a())); //convert string to Number
this.b(Number(this.b())); //convert string to Number
}
total = (this.a() + this.b())/2 ;
return total;
},this);
在下面的程式碼行中,計算出的平均值顯示在 UI 中。請注意,totalAvg 的 data-bind 型別只是文字。
<p>Average := <span data-bind = "text: totalAvg"></span></p>
輸出
讓我們按照以下步驟來了解上面程式碼是如何工作的:
將上述程式碼儲存到名為computed-observable.htm的檔案中。
在瀏覽器中開啟此 HTML 檔案。
在文字框中輸入任意 2 個數字,並觀察平均值是否已計算。
管理“this”
請注意,在上面的示例中,第二個引數作為this提供給 Computed 函式。如果不提供this,則無法引用可觀察物件a()和b()。
為了克服這個問題,使用了self變數,它持有this的引用。這樣做,就不需要在整個程式碼中跟蹤this。而是可以使用self。
以下 ViewModel 程式碼是使用 self 重寫的上述示例。
function MyViewModel(){
self = this;
self.a = ko.observable(10);
self.b = ko.observable(40);
this.totalAvg = ko.computed(function() {
if(typeof(self.a()) !== "number" || typeof(self.b()) !== "number") {
self.a(Number(self.a())); //convert string to Number
self.b(Number(self.b())); //convert string to Number
}
total = (self.a() + self.b())/2 ;
return total;
});
}
純計算可觀察物件
如果可觀察物件只是計算並返回值,而不是直接修改其他物件或狀態,則應將其宣告為Pure計算可觀察物件。純計算可觀察物件有助於 Knockout 高效地管理重新評估和記憶體使用。
顯式通知訂閱者
當計算可觀察物件返回基本資料型別值(字串、布林值、空值和數字)時,只有在實際值發生變化時才會通知其訂閱者。這意味著,如果可觀察物件接收到的值與之前的值相同,則不會通知其訂閱者。
您可以使用notify語法使計算可觀察物件始終顯式通知觀察者,即使新值與舊值相同,如下所示。
myViewModel.property = ko.pureComputed(function() {
return ...; // code logic goes here
}).extend({ notify: 'always' });
限制更改通知
過多的昂貴更新會導致效能問題。您可以使用rateLimit屬性限制從可觀察物件接收到的通知數量,如下所示。
// make sure there are updates no more than once per 100-millisecond period
myViewModel.property.extend({ rateLimit: 100 });
確定屬性是否為計算可觀察物件
在某些情況下,可能需要確定屬性是否為計算可觀察物件。可以使用以下函式來識別可觀察物件的型別。
| 序號 | 函式 |
|---|---|
| 1 | ko.isComputed 如果屬性是計算可觀察物件,則返回true。 |
| 2 | ko.isObservable 如果屬性是可觀察物件、可觀察陣列或計算可觀察物件,則返回true。 |
| 3 | ko.isWritableObservable 如果屬性是可觀察物件、可觀察陣列或可寫計算可觀察物件,則返回true。(這也稱為 ko.isWriteableObservable) |
可寫計算可觀察物件
計算可觀察物件是從一個或多個其他可觀察物件派生的,因此它是隻讀的。但是,可以使計算可觀察物件可寫。為此,您需要提供一個在寫入值時起作用的回撥函式。
這些可寫計算可觀察物件的工作方式與普通可觀察物件相同。此外,它們需要構建自定義邏輯來干預讀寫操作。
可以使用鏈式語法將值分配給多個可觀察物件或計算可觀察物件屬性,如下所示。
myViewModel.fullName('Tom Smith').age(45)
示例
以下示例演示了可寫計算可觀察物件的使用。
<!DOCTYPE html>
<head >
<title>KnockoutJS Writable Computed Observable</title>
<script src = "https://ajax.aspnetcdn.com/ajax/knockout/knockout-3.3.0.js"></script>
</head>
<body>
<p>Enter your birth Date: <input type = "date" data-bind = "value: rawDate" ></p>
<p><span data-bind = "text: yourAge"></span></p>
<script>
function MyViewModel() {
this.yourAge = ko.observable();
today = new Date();
rawDate = ko.observable();
this.rawDate = ko.pureComputed ({
read: function() {
return this.yourAge;
},
write: function(value) {
var b = Date.parse(value); // convert birth date into milliseconds
var t = Date.parse(today); // convert todays date into milliseconds
diff = t - b; // take difference
var y = Math.floor(diff/31449600000); // difference is converted
// into years. 31449600000
//milliseconds form a year.
var m = Math.floor((diff % 31449600000)/604800000/4.3); // calculating
// months.
// 604800000
// milliseconds
// form a week.
this.yourAge("You are " + y + " year(s) " + m +" months old.");
},
owner: this
});
}
ko.applyBindings(new MyViewModel());
</script>
</body>
</html>
在上面的程式碼中,rawDate是從 UI 接收的純計算屬性。yourAge可觀察物件是從rawDate派生的。
JavaScript 中的日期以毫秒為單位進行操作。因此,兩個日期(今天日期和出生日期)都轉換為毫秒,然後將它們之間的差值轉換回年和月。
輸出
讓我們按照以下步驟來了解上面程式碼是如何工作的:
將上述程式碼儲存到名為writable_computed_observable.htm的檔案中。
在瀏覽器中開啟此 HTML 檔案。
輸入任何出生日期,並觀察年齡是否已計算。
KnockoutJS - 宣告式繫結
KnockoutJS 中的宣告性繫結提供了一種將資料連線到 UI 的強大方法。
瞭解繫結和可觀察物件之間的關係非常重要。從技術上講,這兩者是不同的。您可以使用普通 JavaScript 物件作為 ViewModel,KnockoutJS 可以正確處理 View 的繫結。
如果沒有可觀察物件,則 UI 中的屬性將僅在第一次處理。在這種情況下,它無法根據底層資料更新自動更新。要實現此目的,繫結必須引用可觀察屬性。
繫結語法
繫結由 2 個專案組成,即繫結名稱和值。以下是一個簡單的示例:
Today is : <span data-bind = "text: whatDay"></span>
這裡,text 是繫結名稱,whatDay 是繫結值。您可以用逗號分隔多個繫結,如下面的語法所示。
Your name: <input data-bind = "value: yourName, valueUpdate: 'afterkeydown'" />
這裡,值在每次按鍵後更新。
繫結值
繫結值可以是單個值、字面量、變數或JavaScript表示式。如果繫結引用了一些無效的表示式或引用,則 KO 將產生錯誤並停止處理繫結。
以下是幾個繫結示例。
<!-- simple text binding --> <p>Enter employee name: <input -bind = 'value: empName' /></p> <!-- click binding, call a specific function --> <button data-bind="click: sortEmpArray">Sort Array</button> <!-- options binding --> <select multiple = "true" size = "8" data-bind = "options: empArray , selectedOptions: chosenItem"> </select>
請注意以下幾點:
空格沒有任何區別。
從 KO 3.0 開始,您可以跳過繫結值,這將為繫結提供一個未定義的值。
繫結上下文
當前繫結中使用的資料可以透過一個物件來引用。此物件稱為繫結上下文。
上下文層次結構由 KnockoutJS 自動建立和管理。下表列出了 KO 提供的不同型別的繫結上下文。
| 序號 | 繫結上下文型別及說明 |
|---|---|
| 1 | $root 這始終指的是頂級 ViewModel。這使得可以訪問用於操作 ViewModel 的頂級方法。這通常是傳遞給 ko.applyBindings 的物件。 |
| 2 | $data 此屬性非常類似於 Javascript 物件中的this關鍵字。繫結上下文中的 $data 屬性指的是當前上下文的 ViewModel 物件。 |
| 3 | $index 此屬性包含 foreach 迴圈內陣列中當前專案的索引。隨著底層 Observable 陣列的更新,$index 的值將自動更改。顯然,此上下文僅適用於foreach繫結。 |
| 4 | $parent 此屬性指的是父 ViewModel 物件。當您想從巢狀迴圈內部訪問外部 ViewModel 屬性時,這很有用。 |
| 5 | $parentContext 在父級繫結的上下文物件稱為$parentContext。這與$parent不同。$parent 指的是資料。而$parentContext指的是繫結上下文。例如,您可能需要從內部上下文中訪問外部 foreach 專案的索引。 |
| 6 | $rawdata 此上下文在當前情況下儲存原始 ViewModel 值。這類似於 $data,但區別在於,如果 ViewModel 包裹在 Observable 中,則 $data 僅解包。ViewModel 和 $rawdata 成為實際的 Observable 資料。 |
| 7 | $component 當您在特定元件內部時,此上下文用於引用該元件的 ViewModel。例如,您可能希望從 ViewModel 訪問某些屬性,而不是元件模板部分中的當前資料。 |
| 8 | $componentTemplateNodes 當您在特定元件模板內時,這表示傳遞給該特定元件的 DOM 節點陣列。 |
以下術語也可用於繫結,但實際上並非繫結上下文。
$context - 這不過是現有的繫結上下文物件。
$element - 此物件指的是當前繫結中 DOM 中的一個元素。
處理文字和外觀
以下是 KO 提供的用於處理文字和視覺外觀的繫結型別列表。
| 序號 | 繫結型別及用法 |
|---|---|
| 1 | visible: <繫結條件>
根據某些條件顯示或隱藏 HTML DOM 元素。 |
| 2 | text: <繫結值>
設定 HTML DOM 元素的內容。 |
| 3 | html: <繫結值>
設定 DOM 元素的 HTML 標記內容。 |
| 4 | css: <繫結物件>
將 CSS 類應用於元素。 |
| 5 | style: <繫結物件>
定義元素的內聯樣式屬性。 |
| 6 | attr: <繫結物件>
動態地向元素新增屬性。 |
處理控制流繫結
以下是 KO 提供的控制流繫結型別列表。
| 序號 | 繫結型別及用法 |
|---|---|
| 1 | foreach: <繫結陣列>
在此繫結中,每個陣列項都在 HTML 標記中迴圈引用。 |
| 2 | if: <繫結條件>
如果條件為真,則處理給定的 HTML 標記。否則,它將從 DOM 中刪除。 |
| 3 | ifnot: <繫結條件>
If 的否定。如果條件為真,則處理給定的 HTML 標記。否則,它將從 DOM 中刪除。 |
| 4 | with: <繫結物件>
此繫結用於在指定物件的上下文中繫結物件的子元素。 |
| 5 | component: <元件名稱> 或 component: <元件物件>
此繫結用於將元件插入 DOM 元素並可選地傳遞引數。 |
處理表單欄位繫結
以下是 KO 提供的表單欄位繫結型別列表。
| 序號 | 繫結型別及用法 |
|---|---|
| 1 | click: <繫結函式>
此繫結用於根據點選事件呼叫與 DOM 元素關聯的 JavaScript 函式。 |
| 2 | event: <DOM 事件: 處理程式函式>
此繫結用於偵聽指定的 DOM 事件,並根據它們呼叫關聯的處理程式函式。 |
| 3 | submit: <繫結函式>
此繫結用於在關聯的 DOM 元素提交時呼叫 JavaScript 函式。 |
| 4 | enable: <繫結值>
此繫結用於根據指定條件啟用某些 DOM 元素。 |
| 5 | disable: <繫結值>
當引數計算結果為真時,此繫結停用關聯的 DOM 元素。 |
| 6 | value: <繫結值>
此繫結用於將相應的 DOM 元素的值連結到 ViewModel 屬性。 |
| 7 | textInput: <繫結值>
此繫結用於在文字框或文字區域與 ViewModel 屬性之間建立雙向繫結。 |
| 8 | hasFocus: <繫結值>
此繫結用於透過 ViewModel 屬性手動設定 HTML DOM 元素的焦點。 |
| 9 | checked: <繫結值>
此繫結用於在可選中表單元素與 ViewModel 屬性之間建立連結。 |
| 10 | options: <繫結陣列>
此繫結用於定義 select 元素的選項。 |
| 11 | selectedOptions: <繫結陣列>
此繫結用於處理當前在多列表選擇表單控制元件中選定的元素。 |
| 12 | uniqueName: <繫結值>
此繫結用於為 DOM 元素生成唯一的名稱。 |
KnockoutJS - 依賴項跟蹤
KnockoutJs 在值更新時自動跟蹤依賴項。它有一個名為依賴項跟蹤器 (ko.dependencyDetection) 的單個物件,充當兩個參與方之間訂閱依賴項的中間體。
以下是依賴項跟蹤的演算法。
步驟 1 - 每當您宣告一個計算型可觀察物件時,KO 會立即呼叫其評估器函式以獲取其初始值。
步驟 2 - 為評估器讀取的任何可觀察物件設定訂閱。在應用程式中,不再使用的舊訂閱將被處置。
步驟 3 - KO 最終通知更新的計算型可觀察物件。
示例
<!DOCTYPE html>
<html>
<head>
<title>KnockoutJS How Dependency Tracking Works</title>
<!-- CDN's-->
<script src = "https://ajax.aspnetcdn.com/ajax/knockout/knockout-3.1.0.js"
type = "text/javascript"></script>
</head>
<body>
<div>
<form data-bind = "submit: addFruits">
<b>Add Fruits:</b>
<input data-bind = 'value: fruitToAdd, valueUpdate: "afterkeydown"'/>
<button type = "submit" data-bind = "enable: fruitToAdd().length > 0">Add</button>
<p><b>Your fruits list:</b></p>
<select multiple = "multiple" width = "50" data-bind = "options: fruits"> </select>
</form>
</div>
<script>
var Addfruit = function(fruits) {
this.fruits = ko.observableArray(fruits);
this.fruitToAdd = ko.observable("");
this.addFruits = function() {
if (this.fruitToAdd() != "") {
this.fruits.push(this.fruitToAdd()); // Adds a fruit
this.fruitToAdd(""); // Clears the text box
}
}.bind(this); // "this" is the view model
};
ko.applyBindings(new Addfruit(["Apple", "Orange", "Banana"]));
</script>
</body>
</html>
輸出
讓我們按照以下步驟來了解上面程式碼是如何工作的:
將以上程式碼儲存到dependency_tracking.htm檔案中。
在瀏覽器中開啟此 HTML 檔案。
輸入任何水果名稱,然後單擊“新增”按鈕。
使用 Peek 控制依賴項
可以透過使用peek函式訪問計算型可觀察物件,而無需建立依賴項。它透過更新計算屬性來控制可觀察物件。
示例
<!DOCTYPE html>
<html>
<head>
<title>KnockoutJs Controlling Dependencies Using Peek</title>
<!-- CDN's-->
<script src = "https://ajax.aspnetcdn.com/ajax/knockout/knockout-3.1.0.js"
type = "text/javascript"></script>
</head>
<body>
<div class = "logblock">
<h3>Computed Log</h3>
<pre class = "log" data-bind = "html: computedLog"></pre>
</div>
<script>
function AppData() {
this.firstName = ko.observable('John');
this.lastName = ko.observable('Burns');
this.computedLog = ko.observable('Log: ');
this.fullName = ko.computed(function () {
var value = this.firstName() + " " + this.lastName();
this.computedLog(this.computedLog.peek() + value + '; <br/>');
return value;
}, this);
this.step = ko.observable(0);
this.next = function () {
this.step(this.step() === 2 ? 0 : this.step()+1);
};
};
ko.applyBindings(new AppData());
</script>
</body>
</html>
輸出
讓我們按照以下步驟來了解上面程式碼是如何工作的:
將以上程式碼儲存到dependency_tracking_peek.htm檔案中。
在瀏覽器中開啟此 HTML 檔案。
觀察結果
忽略計算依賴項中的依賴項
ko.ignoreDependencies函式有助於忽略您不想在計算依賴項中跟蹤的那些依賴項。以下是其語法。
ko.ignoreDependencies( callback, callbackTarget, callbackArgs );
為什麼迴圈依賴項沒有意義
如果 KO 正在評估一個計算型可觀察物件,則它不會重新啟動對依賴計算型可觀察物件的評估。因此,在您的依賴項鍊中包含迴圈沒有意義。
KnockoutJS - 模板
模板是一組可以重複使用的 DOM 元素。由於其最小化 DOM 元素重複的屬性,模板化使得構建複雜的應用程式變得容易。
有兩種建立模板的方法。
原生模板化 - 此方法支援控制流繫結,例如 foreach、with 和 if。這些繫結捕獲元素中存在的 HTML 標記並將其用作隨機專案的模板。此模板化不需要任何外部庫。
基於字串的模板化 - KO 連線到第三方引擎以將 ViewModel 值傳遞到其中,並將生成的標記注入到文件中。例如,JQuery.tmpl 和 Underscore Engine。
語法
template: <parameter-value> <script type = "text/html" id = "template-name"> ... ... // DOM elemets to be processed ... </script>
請注意,在指令碼塊中將type提供為text/html,以通知 KO 它不是可執行塊,而只是一個需要呈現的模板塊。
引數
以下屬性的組合可以作為引數值傳送到模板。
name - 這表示模板的名稱。
nodes - 這表示要用作模板的 DOM 節點陣列。如果傳遞了 name 引數,則忽略此引數。
data - 這不過是透過模板顯示的資料。
if - 如果給定條件的結果為真或真值,則將提供模板。
foreach - 以 foreach 格式提供模板。
as - 這只是為了在 foreach 元素中建立別名。
afterAdd、afterRender、beforeRemove - 這些都表示可呼叫的函式,根據執行的操作執行。
觀察結果
呈現命名模板
當與控制流繫結一起使用時,模板由 DOM 內部的 HTML 標記隱式定義。但是,如果您願意,可以將模板分解到一個單獨的元素中,然後按名稱引用它們。
示例
<!DOCTYPE html>
<head>
<title>KnockoutJS Templating - Named Template</title>
<script src = "https://ajax.aspnetcdn.com/ajax/knockout/knockout-3.3.0.js"
type = "text/javascript"></script>
</head>
<body>
<h2>Friends List</h2>
Here are the Friends from your contact page:
<div data-bind = "template: { name: 'friend-template', data: friend1 }"></div>
<div data-bind = "template: { name: 'friend-template', data: friend2 }"></div>
<script type = "text/html" id = "friend-template">
<h3 data-bind = "text: name"></h3>
<p>Contact Number: <span data-bind = "text: contactNumber"></span></p>
<p>Email-id: <span data-bind = "text: email"></span></p>
</script>
<script type = "text/javascript">
function MyViewModel() {
this.friend1 = {
name: 'Smith',
contactNumber: 4556750345,
email: 'smith123@gmail.com'
};
this.friend2 = {
name: 'Jack',
contactNumber: 6789358001,
email: 'jack123@yahoo.com'
};
}
var vm = new MyViewModel();
ko.applyBindings(vm);
</script>
</body>
</html>
輸出
讓我們按照以下步驟來了解上面程式碼是如何工作的:
將以上程式碼儲存到template-named.htm檔案中。
在瀏覽器中開啟此 HTML 檔案。
這裡,friend-template 使用了 2 次。
在模板中使用“foreach”
以下是使用foreach引數以及模板名稱的示例。
示例
<!DOCTYPE html>
<head>
<title>KnockoutJS Templating - foreach used with Template</title>
<script src = "https://ajax.aspnetcdn.com/ajax/knockout/knockout-3.3.0.js"
type = "text/javascript"></script>
</head>
<body>
<h2>Friends List</h2>
Here are the Friends from your contact page:
<div data-bind = "template: { name: 'friend-template', foreach: friends }"></div>
<script type = "text/html" id = "friend-template">
<h3 data-bind = "text: name"></h3>
<p>Contact Number: <span data-bind = "text: contactNumber"></span></p>
<p>Email-id: <span data-bind = "text: email"></span></p>
</script>
<script type = "text/javascript">
function MyViewModel() {
this.friends = [
{ name: 'Smith', contactNumber: 4556750345, email: 'smith123@gmail.com' },
{ name: 'Jack', contactNumber: 6789358001, email: 'jack123@yahoo.com' },
{ name: 'Lisa', contactNumber: 4567893131, email: 'lisa343@yahoo.com' }
]
}
var vm = new MyViewModel();
ko.applyBindings(vm);
</script>
</body>
</html>
輸出
讓我們按照以下步驟來了解上面程式碼是如何工作的:
將以上程式碼儲存到template-foreach.htm檔案中。
在瀏覽器中開啟此 HTML 檔案。
這裡,foreach 控制元件用於模板繫結。
為 foreach 專案建立使用 as 關鍵字的別名
以下是為 foreach 專案建立別名的方法 -
<div data-bind = "template: {
name: 'friend-template',
foreach: friends,
as: 'frnz'
}"></div>
透過建立別名,可以輕鬆地從 foreach 迴圈內部引用父物件。當代碼複雜並在多個級別巢狀時,此功能很有用。
示例
<!DOCTYPE html>
<head>
<title>KnockoutJS Templating - using alias in Template</title>
<script src = "https://ajax.aspnetcdn.com/ajax/knockout/knockout-3.3.0.js"
type = "text/javascript"></script>
</head>
<body>
<h2>Friends List</h2>
Here are the Friends from your contact page:
<ul data-bind = "template: {
name: 'friend-template',
foreach: friends,
as: 'frnz'
}"></ul>
<script type = "text/html" id = "friend-template">
<li>
<h3 data-bind = "text: name"></h3>
<span>Contact Numbers</span>
<ul data-bind = "template: {
name : 'contacts-template',
foreach:contactNumber,
as: 'cont'
} "></ul>
<p>Email-id: <span data-bind = "text: email"></span></p>
</li>
</script>
<script type = "text/html" id = "contacts-template">
<li>
<p><span data-bind = "text: cont"></span></p>
</li>
</script>
<script type = "text/javascript">
function MyViewModel() {
this.friends = ko.observableArray ( [
{
name: 'Smith',
contactNumber: [ 4556750345, 4356787934 ],
email: 'smith123@gmail.com'
},
{
name: 'Jack',
contactNumber: [ 6789358001, 3456895445 ],
email: 'jack123@yahoo.com'
},
{
name: 'Lisa',
contactNumber: [ 4567893131, 9876456783, 1349873445 ],
email: 'lisa343@yahoo.com'
}
]);
}
var vm = new MyViewModel();
ko.applyBindings(vm);
</script>
</body>
</html>
輸出
讓我們按照以下步驟來了解上面程式碼是如何工作的:
將以上程式碼儲存到template-as-alias.htm檔案中。
在瀏覽器中開啟此 HTML 檔案。
別名用於代替陣列的全名。
使用 afterAdd、beforeRemove 和 afterRender
在某些情況下,需要在模板建立的 DOM 元素上執行額外的自定義邏輯。在這種情況下,可以使用以下回調。假設您正在使用 foreach 元素,則 -
afterAdd - 在向 foreach 中提到的陣列中新增新專案時呼叫此函式。
beforeRemove - 在從 foreach 中提到的陣列中刪除專案之前呼叫此函式。
afterRender - 這裡提到的函式在每次渲染 foreach 並向陣列新增新條目時呼叫。
示例
<!DOCTYPE html>
<head>
<title>KnockoutJS Templating - Use of afterRender Template</title>
<script src = "https://ajax.aspnetcdn.com/ajax/knockout/knockout-3.3.0.js"
type = "text/javascript"></script>
<script src = "https://code.jquery.com/jquery-2.1.3.min.js"
type = "text/javascript"></script>
</head>
<body>
<h2>Friends List</h2>
Here are the Friends from your contact page:
<div data-bind = "template: {
name: 'friend-template',
foreach: friends ,
afterRender: afterProcess
}"></div>
<script type = "text/html" id = "friend-template">
<h3 data-bind = "text: name"></h3>
<p>Contact Number: <span data-bind = "text: contactNumber"></span></p>
<p>Email-id: <span data-bind = "text: email"></span></p>
<button data-bind = "click: $root.removeContact">remove </button>
</script>
<script type = "text/javascript">
function MyViewModel() {
self = this;
this.friends = ko.observableArray ([
{ name: 'Smith', contactNumber: 4556750345, email: 'smith123@gmail.com' },
{ name: 'Jack', contactNumber: 6789358001, email: 'jack123@yahoo.com' },
])
this.afterProcess = function(elements, data){
$(elements).css({color: 'magenta' });
}
self.removeContact = function() {
self.friends.remove(this);
}
}
var vm = new MyViewModel();
ko.applyBindings(vm);
</script>
</body>
</html>
輸出
讓我們按照以下步驟來了解上面程式碼是如何工作的:
將以上程式碼儲存到template-afterrender.htm檔案中。
在瀏覽器中開啟此 HTML 檔案。
這裡,afterProcess 函式在每次渲染 foreach 時執行。
動態選擇模板
如果有多個模板可用,則可以透過將名稱設為可觀察引數來動態選擇其中一個。因此,隨著 name 引數的變化,模板值將被重新評估,並且資料將被重新渲染。
示例
<!DOCTYPE html>
<head>
<title>KnockoutJS Templating - Dynamic Template</title>
<script src = "https://ajax.aspnetcdn.com/ajax/knockout/knockout-3.3.0.js"
type = "text/javascript"></script>
</head>
<body>
<h2>Friends List</h2>
Here are the Friends from your contact page:
<div data-bind = "template: {
name: whichTemplate,
foreach: friends
}"></div>
<script type = "text/html" id = "only-phon">
<h3 data-bind = "text: name"></h3>
<p>Contact Number: <span data-bind = "text: contactNumber"></span></p>
</script>
<script type = "text/html" id = "only-email">
<h3 data-bind = "text: name"></h3>
<p>Email-id: <span data-bind = "text: email"></span></p>
</script>
<script type = "text/javascript">
function MyViewModel() {
this.friends = ko.observableArray ([
{
name: 'Smith',
contactNumber: 4556750345,
email: 'smith123@gmail.com',
active: ko.observable(true)
},
{
name: 'Jack',
contactNumber: 6789358001,
email: 'jack123@yahoo.com',
active: ko.observable(false)
},
]);
this.whichTemplate = function(friends) {
return friends.active() ? "only-phon" : "only-email";
}
}
var vm = new MyViewModel();
ko.applyBindings(vm);
</script>
</body>
</html>
輸出
讓我們按照以下步驟來了解上面程式碼是如何工作的:
將以上程式碼儲存到template-dynamic.htm檔案中。
在瀏覽器中開啟此 HTML 檔案。
根據 active 標誌值確定要使用的模板。
使用外部基於字串的引擎
原生模板化與各種控制流元素完美配合,即使在巢狀程式碼塊中也是如此。KO 還提供了一種與外部模板庫(例如 Underscore 模板引擎或 JQuery.tmpl)整合的方法。
如官方網站所述,自 2011 年 12 月起,JQuery.tmpl 已不再處於積極開發狀態。因此,建議僅使用 KO 的原生模板化,而不是 JQuery.tmpl 或任何其他基於字串的模板引擎。
有關此內容的更多詳細資訊,請參閱官方網站。
KnockoutJS - 元件
元件是組織 UI 程式碼以構建大型應用程式並促進程式碼可重用性的絕佳方法。
它繼承或巢狀自其他元件。為了載入和配置,它定義了自己的約定或邏輯。
它被封裝以便在整個應用程式或專案中重複使用。表示應用程式的完整部分或小的控制元件/部件。可以根據需要載入或預載入。
元件註冊
元件可以使用ko.components.register() API 進行註冊。它有助於在 KO 中載入和表示元件。註冊需要元件名稱和配置。配置指定如何確定 viewModel 和模板。
語法
元件可以按如下方式註冊:
ko.components.register('component-name', {
viewModel: {...}, //function code
template: {....) //function code
});
component-name 可以是任何非空字串。
viewModel 是可選的,可以採用下一節列出的任何 viewModel 格式。
template 是必需的,可以採用下一節列出的任何模板格式。
宣告 ViewModel
下表列出了可用於註冊元件的 viewModel 格式。
| 序號 | viewModel 格式和描述 |
|---|---|
| 1 | 建構函式 為每個元件建立一個單獨的 viewModel 物件。該物件或函式用於繫結到元件檢視中。 function SomeComponentViewModel(params) {
this.someProperty = params.something;
}
ko.components.register('component name', {
viewModel: SomeComponentViewModel,
template: ...
});
|
| 2 | 共享物件例項 viewModel 物件例項是共享的。例項屬性被傳遞以直接使用該物件。 var sharedViewModelInstance = { ... };
ko.components.register('component name', {
viewModel: { instance: sharedViewModelInstance },
template: ...
});
|
| 3 | createViewModel 它呼叫一個充當工廠的函式,該函式可用作可以返回物件的檢視模型。 ko.components.register('component name', {
viewModel: {
createViewModel: function (params, componentInfo) {
... //function code
...
}
},
template: ....
});
|
| 4 | AMD 模組 這是一種用於定義模組的模組格式,其中模組和依賴項都非同步載入。 ko.components.register('component name', {
viewModel: { require: 'some/module/name' },
template: ...
});
define(['knockout'], function(ko) {
function MyViewModel() {
// ...
}
return MyViewModel;
});
|
宣告模板
下表列出了可用於註冊元件的模板格式。
| 序號 | 模板格式 |
|---|---|
| 1 | 元素 ID ko.components.register('component name', {
template: { element: 'component-template' },
viewModel: ...
});
|
| 2 | 元素例項 var elemInstance = document.getElementById('component-template');
ko.components.register('component name', {
template: { element: elemInstance },
viewModel: ...
});
|
| 3 | 標記字串 ko.components.register('component name', {
template: '<input data-bind = "value: yourName" />\
<button data-bind = "click: addEmp">Add Emp </button>',
viewModel: ...
});
|
| 4 | DOM 節點 var emp = [
document.getElementById('node 1'),
document.getElementById('node 2'),
];
ko.components.register('component name', {
template: emp,
viewModel: ...
});
|
| 5 | 文件片段 ko.components.register('component name', {
template: someDocumentFragmentInstance,
viewModel: ...
});
|
| 6 | AMD 模組 ko.components.register('component name', {
template: { require: 'some/template' },
viewModel: ...
});
|
作為單個 AMD 模組註冊的元件
AMD 模組可以自行註冊元件,而無需使用 viewModel/template 對。
ko.components.register('component name',{ require: 'some/module'});
元件繫結
元件繫結有兩種方式。
完整語法 - 它將引數和物件傳遞給元件。它可以使用以下屬性傳遞。
name - 新增元件名稱。
params - 它可以在元件上以物件的形式傳遞多個引數。
<div data-bind='component: {
name: "tutorials point",
params: { mode: "detailed-list", items: productsList }
}'>
</div>
簡寫語法 - 它將字串作為元件名稱傳遞,並且不包含引數。
<div data-bind = 'component: "component name"'></div>
僅模板元件 - 元件只能定義模板而無需指定 viewModel。
ko.components.register('component name', {
template:'<input data-bind = "value: someName" />,
});
在沒有容器元素的情況下使用元件 - 元件可以在不使用額外容器元素的情況下使用。這可以透過使用無容器流控制來完成,這類似於註釋標籤。
<!--ko.component: ""--> <!--/ko-->
自定義元素
自定義元素是渲染元件的一種方式。在這裡,您可以直接編寫自描述的標記元素名稱,而不是定義佔位符,元件透過它繫結。
<products-list params = "name: userName, type: userType"></products-list>
傳遞引數
params 屬性用於將引數傳遞給元件 viewModel。它類似於 data-bind 屬性。params 屬性的內容被解釋為 JavaScript 物件文字(就像 data-bind 屬性一樣),因此您可以傳遞任意型別的任意值。它可以透過以下方式傳遞引數:
父元件和子元件之間的通訊 - 元件本身不會被例項化,因此檢視模型屬性是從元件外部引用的,因此將被子元件檢視模型接收。例如,您可以在以下語法中看到ModelValue是父檢視模型,它被子檢視模型建構函式ModelProperty接收。
傳遞可觀察表示式 - params 引數中有三個值。
simpleExpression - 它是一個數值。它不涉及任何可觀察物件。
simpleObservable - 它是定義在父 viewModel 上的例項。父 viewModel 將自動獲取子 viewModel 對可觀察物件所做的更改。
observableExpression - 表示式在表示式本身被評估時讀取可觀察物件。當可觀察物件的值發生變化時,表示式的結果也會隨著時間的推移而變化。
我們可以按如下方式傳遞引數:
<some-component
params = 'simpleExpression: 1 + 1,
simpleObservable: myObservable,
observableExpression: myObservable() + 1'>
</some-component>
我們可以按如下方式在 viewModel 中傳遞引數:
<some-component
params = 'objectValue:{a: 3, b: 2},
dateValue: new date(),
stringValue: "Hi",
numericValue:123,
boolValue: true/false,
ModelProperty: ModelValue'>
</some-component>
將標記傳遞到元件中
接收到的標記用於建立元件,並被選為輸出的一部分。以下節點作為元件模板中的輸出的一部分傳遞。
template: { nodes: $componentTemplateNodes }
控制自定義元素標籤名稱
您在元件中使用ko.components.register註冊的名稱,相同的名稱對應於自定義元素標籤名稱。我們可以透過覆蓋它來控制使用getComponentNameForNode。
ko.components.getComponentNameForNode = function(node) {
...
... //function code
...
}
註冊自定義元素
如果使用預設元件載入器,則自定義元素可以立即使用,因此元件使用ko.components.register註冊。如果我們沒有使用ko.components.register並實現自定義元件載入器,則可以透過定義任何選擇的元素名稱來使用自定義元素。當您使用ko.components.register時,無需指定配置,因為自定義元件載入器不再使用它。
ko.components.register('custom-element', { ......... });
示例
<!DOCTYPE html>
<head>
<title>KnockoutJS Components</title>
<script src = "https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
</head>
<body>
<!--params attribute is used to pass the parameter to component viewModel.-->
<click params = "a: a, b: b"></click>
<!--template is used for a component by specifying its ID -->
<template id = "click-l">
<div data-bind = "text: a"></div>
<!--Use data-bind attribute to bind click:function() to ViewModel. -->
<button data-bind = "click:function(){callback(1)}">Increase</button>
<button data-bind = "click:function(){callback(-1)}">Decrease</button>
</template>
<script>
//Here components are registered
ko.components.register('click', {
viewModel: function(params) {
self = this;
this.a = params.a;
this.b = params.b;
this.callback = function(num) {
self.b(parseInt(num));
self.a( self.a() + parseInt(num) );
};
},
template: { element: 'click-l' }
});
//keeps an eye on variable for any modification in data
function viewModel() {
this.a = ko.observable(2);
this.b = ko.observable(0);
}
ko.applyBindings(new viewModel() );
</script>
</body>
</html>
輸出
讓我們按照以下步驟來了解上面程式碼是如何工作的:
將以上程式碼儲存到component_register.htm檔案中。
在瀏覽器中開啟此 HTML 檔案。
元件載入器
元件載入器用於為給定的元件名稱非同步傳遞模板/viewModel 對。
預設元件載入器
預設元件載入器取決於顯式註冊的配置。每個元件在使用之前都已註冊。
ko.components.defaultLoader
元件載入器實用函式
預設元件載入器可以使用以下函式進行讀寫。
| 序號 | 實用函式和描述 |
|---|---|
| 1 | ko.components.register(name, configuration) 註冊元件。 |
| 2 | ko.components.isRegistered(name) 如果特定元件名稱已註冊,則返回 true,否則返回 false。 |
| 3 | ko.components.unregister(name) 從登錄檔中刪除元件名稱。 |
| 4 | ko.components.get(name, callback) 此函式依次轉到每個已註冊的載入器,以查詢誰已傳遞元件名稱的 viewModel/template 定義作為第一個。然後它透過呼叫callback返回 viewModel/template 宣告。如果已註冊的載入器找不到有關元件的任何資訊,則它將呼叫callback(null)。 |
| 5 | ko.components.clearCachedDefinition(name) 當我們想要清除給定元件快取條目時,可以呼叫此函式。如果下次需要該元件,載入器將再次被諮詢。 |
實現自定義元件載入器
自定義元件載入器可以透過以下方式實現:
getConfig(name, callback) - 根據名稱,我們可以以程式設計方式傳遞配置。我們可以呼叫 callback(componentConfig) 來傳遞配置,其中物件 componentConfig 可以由 loadComponent 或任何其他載入器使用。
loadComponent(name, componentConfig, callback) - 此函式根據配置方式解析 config 的 viewModel 和模板部分。我們可以呼叫 callback(result) 來傳遞 viewModel/template 對,其中物件 result 由以下屬性定義。
template - 必需。返回 DOM 節點陣列。
createViewModel(params, componentInfo) - 可選。根據 viewModel 屬性的配置方式返回 viewModel 物件。
loadTemplate(name, templateConfig, callback) - 使用自定義邏輯在模板中傳遞 DOM 節點。物件 templateConfig 是物件 componentConfig 中模板的一個屬性。callback(domNodeArray) 被呼叫以傳遞 DOM 節點陣列。
loadViewModel(name, templateConfig, callback) - 使用自定義邏輯在 viewModel 配置中傳遞 viewModel 工廠。