Kendo UI for jQuery使用教程:自定義小部件(三)
Kendo UI目前最新提供Kendo UI for jQuery、Kendo UI for Angular、Kendo UI Support for React和Kendo UI Support for Vue四個(gè)控件。Kendo UI for jQuery是創(chuàng)建現(xiàn)代Web應(yīng)用程序的最完整UI庫。
Kendo UI通過繼承基本窗口小部件類為您提供創(chuàng)建自定義窗口小部件的選項(xiàng)。
使用MVVM
1. 為了使該小部件具有MVVM-aware,您需要定義一些事件。具體來說,公開dataBinding事件和dataBound事件。在使用小部件對(duì)DOM進(jìn)行更改之前,將要調(diào)用dataBinding事件。這使MVVM有機(jī)會(huì)遍歷將要突變的片段,并取消綁定當(dāng)前綁定的任何片段。 第二個(gè)事件是dataBound事件,它使MVVM返回片段,并重新綁定必要的事件, 這些事件通過小部件上的事件對(duì)象公開。這些事件是字符串,因此在開發(fā)Kendo UI窗口小部件時(shí),將它們定義為窗口小部件頂部的常量,作為Kendo UI使用模式的一部分。
通過將這些事件公開為MVVM可以監(jiān)聽的事件,您可以在小部件和MVVM核心引擎之間實(shí)現(xiàn)松散耦合。 這意味著,如果您不公開這些事件,則MVVM將不會(huì)知道窗口小部件的生命周期。 這是一個(gè)非常好的架構(gòu),這是一個(gè)非常好的架構(gòu),因?yàn)樗梢源_保您的小部件不會(huì)破壞其他不知道的MVVM綁定。
var DATABINDING = "dataBinding",DATABOUND = "dataBound",CHANGE = "change" var Repeater = kendo.ui.Widget.extend({ init: function(element, options) { ... }, options{ ... }, // The events are used by other widgets or developers - API for other purposes. // These events support MVVM bound items in the template for loose coupling with MVVM. events: [ // Call before mutating DOM. // MVVM will traverse DOM, unbind any bound elements or widgets. DATABINDING, // Call after mutating DOM. // Traverses DOM and binds ALL THE THINGS. DATABOUND ] });
2. MVVM希望您從窗口小部件中公開DOM片段,該片段代表每一行或每個(gè)重復(fù)的數(shù)據(jù)元素。 您必須返回最外面的元素,MVVM才能使用。雖然有所不同,但這通常只是this.element.children。 由于呈現(xiàn)的每個(gè)模板項(xiàng)目都是一個(gè)DOM片段,并附加到綁定的元素上,因此您只需要這些。 通過使它在Items對(duì)象之外可用,將其公開用于MVVM。
var DATABINDING = "dataBinding",DATABOUND = "dataBound",CHANGE = "change" var Repeater = kendo.ui.Widget.extend({ init: function(element, options) { ... }, options{ ... }, // The events are used by other widgets or developers - API for other purposes. // These events support MVVM bound items in the template. for loose coupling with MVVM. events: [ // Call before mutating DOM. // MVVM will traverse DOM, unbind any bound elements or widgets. DATABINDING, // Call after mutating DOM. // Traverses DOM and binds ALL THE THINGS. DATABOUND ], // MVVM expects an array of DOM elements that represent each item of the datasource. // Has to be the children of the outermost element. items: function() { return this.element.children(); } });
3. 由于可以使用MVVM更改數(shù)據(jù)源,因此需要實(shí)現(xiàn)setDataSource函數(shù)。 當(dāng)在ViewModel中設(shè)置數(shù)據(jù)源時(shí),MVVM會(huì)調(diào)用此方法。 將內(nèi)部DataSource引用設(shè)置為與MVVM傳遞的引用相等,然后使用已定義的dataSource()函數(shù)重新構(gòu)建DataSource。
// For supporting changing the datasource over MVVM. setDataSource: function(dataSource) { // Set the internal datasource equal to the one passed in by MVVM. this.options.dataSource = dataSource; // Rebuild the datasource if necessary or just reassign. this._dataSource(); }
4. 您需要對(duì)分配或構(gòu)建數(shù)據(jù)源的方法進(jìn)行一些小的調(diào)整,在init中調(diào)用的_dataSource方法可完成3件事:
- 分配數(shù)據(jù)源,或從數(shù)組或配置對(duì)象建立。
- 從DataSource讀?。ㄈ绻麊⒂昧薬utoBind且尚未從DataSource讀?。?。
- 將數(shù)據(jù)源上的change事件綁定到您手動(dòng)處理的內(nèi)部刷新方法。
由于您可能已經(jīng)在數(shù)據(jù)源上綁定了一次更改事件,因此請(qǐng)確保在必要時(shí)取消綁定。如果不這樣做,則小部件將保留所有綁定的列表,并多次執(zhí)行刷新功能。 同樣,MVVM將監(jiān)聽尚未定義的內(nèi)部_refreshHandler函數(shù),您需要將內(nèi)部_refreshHandler指向公開的刷新方法。不過,請(qǐng)首先檢查綁定到DataSource上的change事件的公共刷新和內(nèi)部_refreshHandler之間是否存在現(xiàn)有連接,如果存在,則僅刪除對(duì)更改事件的綁定。 如果內(nèi)部_refreshHandler與公共刷新功能之間沒有連接,則需要?jiǎng)?chuàng)建它。這是通過$ .proxy jQuery方法完成的,該方法使用正確的上下文(即小部件本身)調(diào)用公共刷新。 最后,重新綁定到DataSource的change事件。
如果您以前沒有使用過代理jQuery函數(shù),則以下內(nèi)容可能會(huì)造成混淆,在調(diào)用_refreshHandler時(shí),它應(yīng)該執(zhí)行公共刷新小部件函數(shù),并且在該刷新函數(shù)內(nèi)部,這將是一個(gè)指向窗口小部件本身,而不是窗口之類的其他東西。 由于JavaScript中關(guān)鍵字的值始終在變化,因此這是確保刷新函數(shù)執(zhí)行時(shí)范圍正確的一種好方法。
_dataSource: function() { var that = this; // If the DataSource is defined and the _refreshHandler is wired up, unbind because // you need to rebuild the DataSource. if ( that.dataSource && that._refreshHandler ) { that.dataSource.unbind(CHANGE, that._refreshHandler); } else { that._refreshHandler = $.proxy(that.refresh, that); } // Returns the datasource OR creates one if using array or configuration object. that.dataSource = kendo.data.DataSource.create(that.options.dataSource); // Bind to the change event to refresh the widget. that.dataSource.bind( CHANGE, that._refreshHandler ); if (that.options.autoBind) { that.dataSource.fetch(); } }
5. 在公共刷新中觸發(fā)dataBinding和dataBound事件。 請(qǐng)注意,dataBinding發(fā)生在更改DOM之前,而dataBound發(fā)生在此之后。
refresh: function() {var that = this,view = that.dataSource.view(),html = kendo.render(that.template, view); // Trigger the dataBinding event. that.trigger(DATABINDING); // Mutate the DOM (AKA build the widget UI). that.element.html(html); // Trigger the dataBound event. that.trigger(DATABOUND); }
現(xiàn)在,您的窗口小部件中已完全啟用了MVVM。 定義小部件,如下面的示例所示。
<div data-role="repeater" data-bind="source: dataSource"></div> <script> var viewModel = kendo.observable({ dataSource: new kendo.data.DataSource({ transport: { read: "Customers/Orders", dataType: "json" } }) }); kendo.bind(document.body.children, viewModel); </script>
注意,小部件現(xiàn)在通過數(shù)據(jù)綁定綁定到ViewModel內(nèi)部的dataSource變量。 這意味著,如果我們?cè)跀?shù)據(jù)源中添加客戶端項(xiàng),則您的窗口小部件將立即反映更改,而無需重新渲染任何內(nèi)容。
在下面的完整示例中,請(qǐng)注意將項(xiàng)目添加到數(shù)據(jù)源時(shí),它會(huì)立即反映在Repeater小部件中。
```dojo<label for="newItem">Enter A New Item</label><input id="newItem" data-bind="value: newItem" class="k-input" /><button class="k-button" data-bind="click: add">Add Item</button> <div data-role="repeater" data-bind="source: items" data-template="template"></div> <script type="text/x-kendo-template" id="template"> <div style="color: salmon; margin-right: 10px'"><h1>#= data #</h1></div> </script> <script> var viewModel = kendo.observable({ items: ["item1", "item2", "item3"], newItem: null, add: function(e) { if (this.get("newItem")) { this.get("items").push(this.get("newItem")); } } }); kendo.bind(document.body, viewModel); </script> ```
使用價(jià)值有限的小部件
為了使小部件支持值綁定,您需要:
- 向窗口小部件添加一個(gè)value方法,該方法設(shè)置當(dāng)前窗口小部件的值,如果未傳遞任何參數(shù),則返回當(dāng)前值。
- 更改窗口小部件值時(shí)觸發(fā)窗口小部件更改事件。
以下示例演示如何創(chuàng)建一個(gè)簡單的輸入小部件,以選擇焦點(diǎn)值。
1. 創(chuàng)建窗口小部件并實(shí)現(xiàn)所需的功能。
(function ($) {var kendo = window.kendo; var SelectedTextBox = kendo.ui.Widget.extend({ init: function (element, options) { kendo.ui.Widget.fn.init.call(this, element, options); this.element.on("focus", this._focus); }, options: { name: "SelectedTextBox" }, _focus: function () { this.select(); }, destroy: function () { this.element.off("focus", this._focus); } }); kendo.ui.plugin(SelectedTextBox); })(jQuery);
2. 添加一個(gè)value方法。
var SelectedTextBox = kendo.ui.Widget.extend({ ... value: function (value) { if (value !== undefined) { this.element.val(value); } else { return this.element.val(); } } });
3. 觸發(fā)change事件。
var SelectedTextBox = kendo.ui.Widget.extend({init: function (element, options) {...this._changeHandler = $.proxy(this._change, this);this.element.on("change", this._changeHandler);}, ... _change: function () { this.trigger("change"); }, destroy: function () { this.element.off("change", this._changeHandler); this.element.off("focus", this._focus); } });
以下示例結(jié)合代碼片段并展示完整的代碼。
<script>(function ($) {var kendo = window.kendo; var SelectedTextBox = kendo.ui.Widget.extend({ init: function (element, options) { kendo.ui.Widget.fn.init.call(this, element, options); this._changeHandler = $.proxy(this._change, this); this.element.on("change", this._changeHandler); this.element.on("focus", this._focus); }, options: { name: "SelectedTextBox" }, _change: function () { this._value = this.element.val(); this.trigger("change"); }, _focus: function () { this.select(); }, value: function (value) { if (value !== undefined) { this.element.val(value); } else { return this.element.val(); } }, destroy: function () { this.element.off("change", this._changeHandler); this.element.off("focus", this._focus); } }); kendo.ui.plugin(SelectedTextBox); })(jQuery); </script> <input type="text" data-role="selectedtextbox" data-bind="value:foo" /> <script> var viewModel = kendo.observable({ foo: "bar" }); kendo.bind(document.body, viewModel); </script>
Kendo UI R3 2019全新發(fā)布,最新動(dòng)態(tài)請(qǐng)持續(xù)關(guān)注Telerik中文網(wǎng)!
掃描關(guān)注慧聚IT微信公眾號(hào),及時(shí)獲取最新動(dòng)態(tài)及最新資訊