kendoUI的文档大多外国网站,访问速度很尴尬。这边梳理我开发过程中遇到的一些重要的问题。
数据源是常用的,用来生成数据的对象。
DataSource示例:
new kendo.data.DataSource({
transport: {
read: {
cache: false,//无缓存
url: "/user",//获取数据的URL
dataType: "json"
}
},
schema: {//字段摘要
model: {
id: "id",
fields: {
name: {type: "string"},
id: { type: "string"},
sex: {type: "string"},
loginId: {type: "string"},
idNumber: {type: "string"},
email: {type: "string"},
mobilePhone: {type: "string"},
orderNo: {type: "string"},
deptId: {type: "string"}
}
}
},
pageSize: 15,//分页参数,每页15条数据
sort:{field:"deptId",dir:"asc"}//排序参数,根据部门ID升序排序
});
要想使用kendo对象的属性或方法,必须将所需html元素绑定kendo对象。这里用kendoWindow举例,kendoTreeList等控件类似。
①方式一: 直接通过声明kendo对象。这种方式声明和逻辑都放在了js中。
HTML:
<div id="content">
<div id="editWindow">div>
div>
JS:
var editDiv=$("#editWindow").kendoWindow({
visible: false,
title:"新增"
}).data("kendoWindow");
使用方式:
//打开窗口
var editDiv = $("#editWindow").data("kendoWindow");
editDiv.title("编辑").open();
②方式二: 通过MVVM绑定。这种方式,声明基本都放在了html上了,js只做逻辑的处理。
HTML:
<div id="content">
<div id="editWindow"
data-bind="events:{open:windowOpen,close:onCancel},
visible:isWindowVisible,
confirm:onSave,
cancel:onCancel"
data-role="window"
data-title="新增"
data-width="700"
data-buttons="['cancel']">div>
div>
JS:
var viewModel = kendo.observable({
isWindowVisible: false,
windowOpen: function (e) {
e.sender.center();
}});
kendo.bind($("#content"),viewModel);
使用方式:
//打开窗口
viewModel.set("isWindowVisible",true);
可以看出MVVM模式和直接控件声明的方式还是有很大差别的,重点看,开发中制定的模式是那种。
TreeList一大的好处就是能够子父级展示数据,利用id和parentId字段,但是在实际开发中,我被id和parentId只能是number类型给弄的很尴尬。下面通过例子展示如何能够用string类型表示id和parentId,并根据父ID进行升序展示。
new kendo.data.TreeListDataSource({
transport: {
read: {
url: "/getData",
dataType: "json"
}
},
schema: {
model: {
id: "id",
parentId: "parentId",
fields: {
name: {field: "name", type: "string"},
id: {field: "id", type: "string"},
parentId: {field: "parentId", type: "string", "defaultValue": "0"}
}
}
},
sort:{field:"parentId",dir:"asc"}//根据父ID进行升序展示
});
//《"defaultValue": "0" 》需要加在parentId的属性中,具体原因尚不明确,只是放进去后
//得以解决问题,有知道的人希望能指教一番
//本人开发中model:{} 没加导致显示有问题,注意schema内要嵌套model
当使用kendo新建对象时(例如$("#treelist").kendoTreeList({…}), $("#window").kendoWindow({…}))时,之后再用observable进行bind,是无法绑定上的。类似这样:
html:
<div id="editWindow">
<input type="input" name="a" data-bind="value:a"/>
<input type="input" name="b" data-bind="value:b"/>
div>
js:
var editDiv=$("#editWindow").kendoWindow({
visible: false,
title:"新增"
}).data("kendoWindow");
var viewModel = kendo.observable({
windowBindData:{a:"a",b:"b"}
});
//此时是无法绑定上数据的
例如增加某一字段为增删改查四个checkbox:
<div id="fromDiv" style="height:400px"
data-role="ctreelist"
data-selectable="multiple"
data-row-checkbox="true"
data-columns="[{ expandable: true,'field': 'Name','title':'资源名称', attributes: { 'class': 'cell-left' }},
{ 'field': 'Code','title':'资源代码'},{ 'field': 'authority','title':'权限',template:$('#auth-template').html()}]"
data-bind="source:fromDataSource,events:{change:selectFromItem}"
data-connect-with="selected2">div>
<script id="auth-template" type="text/x-kendo-template">
<input type='checkbox' data-code="#:Code#" id='addCk_#:Code#' name='addCk_#:Code#'
data-bind="events:{change:ckChangeFrom}"/>新增
<input type='checkbox' data-code="#:Code#" id='delCk_#:Code#' name='delCk_#:Code#'
data-bind="events:{change:ckChangeFrom}"/>删除
<input type='checkbox' data-code="#:Code#" id='updateCk_#:Code#' name='updateCk_#:Code#'
data-bind="events:{change:ckChangeFrom}"/>更新
<input type='checkbox' data-code='#:Code#' id='queryCk_#:Code#' name='queryCk_#:Code#'
data-bind='events:{change:ckChangeFrom}'/>查询
script>
<script id="remove-template" type="text/x-kendo-template">
<input type='checkbox' data-id="#:addId#" data-type="add" id='addReCk_#:resourceCode#'
name='addReCk_#:code#' style='#if (add!=1){#display: none;#}#'
data-bind="events:{change:ckReChangeFrom}"/><span style='#if (add!=1){#display: none;#}#'>新增 </span>
<input type='checkbox' data-id="#:deleteId#" data-type="del" id='delReCk_#:resourceCode#'
name='delReCk_#:code#' style='#if (del!=1){#;display: none;#}#'
data-bind="events:{change:ckReChangeFrom}"/><span style='#if (del!=1){#;display: none;#}#'>删除 </span>
<input type='checkbox' data-id="#:updateId#" data-type="update" id='updateReCk_#:resourceCode#'
name='updateReCk_#:code#' style='#if (update!=1){#;display: none;#}#'
data-bind="events:{change:ckReChangeFrom}"/><span style='#if (update!=1){#;display: none;#}#'>更新 </span>
<input type='checkbox' data-id="#:queryId#" data-type='query' id='queryReCk_#:resourceCode#'
name='queryReCk_#:code#' style='#if (query!=1){#;display: none;#}#'
data-bind='events:{change:ckReChangeFrom}'/><span style='#if (query!=1){#;display: none;#}#'>查询 </span>
script>
//基本方法:
var validatable = $("#myform").kendoValidator().data("kendoValidator");
if (validatable.validate()) {
//表单验证通过
} else {
//表单验证未通过
}
表单验证规则与提示信息:
表单验证规则与提示信息有三种方式可以定义,下面我们就来看一下
/**************第一种:放在页面上(记得标明属性type="text")******************/
<input type="text" pattern="^[A-Za-z0-9\.\-_@]+$" validationMessage='最多30个字符(支持英文数字.-_@)'>
/*************第二种:通用模块中*****************/
kendo.ui.validator.rules.dataLength = function (input) {
if (input.is('[dataLength]')) {
return input.val().length <= input.attr('dataLength');
}
return true;
};
kendo.ui.validator.messages.dataLength = function(input){
var len = input.attr('dataLength');
return kendo.format("最大长度不能超过{0}", len);
};
//这种方式适合定义通用验证规则,比如上面的限制最大长度。
//我们将上面的规则和提示信息放在公共模块中,在需要做验证规则的元素加上属性即可,如下
<input type="text" datalength="30">
/***************第三种:放在验证函数中********************/
validate: {
rules: {
reg: function(input){
var regex = '^[A-Za-z0-9\.\-_@]{0,30}$';
if(input.is('[reg]')){
return !input.val() || regex.test(input.val());
}
return true;
}
},
messages: {
reg: '最多30个字符(支持英文数字.-_@)'
}
}
//这种方式适合提示信息由前端人员来定义,我们可以把提示信息放在一个全局对象中,方便维护。
//在定义表单验证时,只需要将规则对象传给函数即可,如下:
var validatable = $("#myform").kendoValidator(validate).data("kendoValidator");
if (validatable.validate()) {
}
//----------------------开发错误总结--------------------------
//我使用的是第一种校验方式,但是input框忘记添加type属性,于是无法触发校验,折磨了很久。
//!!需要有type,需要有name
①方法一(kendo template): 适合check项目数确定,不可变
<div id="toDiv" style="height:500px;overflow: auto;"
data-remove-save="removeSave"
data-role="ctreelist"
data-selectable="multiple"
data-row-checkbox="false"
data-columns="[{ expandable: true,'field': 'resourceName','title':'资源名称', attributes: { 'class': 'cell-left' }},{ 'field': 'resourceCode','title':'资源代码'},{ 'field': 'authority','title':'权限',template:$('#remove-template').html()}]"
data-bind="source:toDataSource,events:{change:selectToItem}">div>
<script id="remove-template" type="text/x-kendo-template">
<input type='checkbox' data-id="#:addId#" data-type="add" id='addReCk_#:resourceCode#' name='addReCk_#:code#' style='#if (add!=1){#display: none;#}#'
data-bind="events:{change:ckReChangeFrom}"/><span style='#if (add!=1){#display: none;#}#'>新增 </span>
script>
②方法二:(适合可变的check项目数,用循环展示,javascript前后加“//”是关键,没加这句xml解析出错,无法解析html)
<div id="toDiv" style="height:500px;overflow: auto;"
data-remove-save="removeSave"
data-role="ctreelist"
data-selectable="multiple"
data-row-checkbox="false"
data-columns="[{ expandable: true,'field': 'resourceName','title':'资源名称', attributes: { 'class': 'cell-left' }},{ 'field': 'resourceCode','title':'资源代码'},{ 'field': 'authority','title':'权限',template:showAuthorized}]"
data-bind="source:toDataSource,events:{change:selectToItem}">div>
<script type="text/javascript" th:inline="javascript">
/*
function showAuthorized(e){
debugger;
var htmlStr = "";
for(var i=0;i<e.operateObj.length;i++){
htmlStr += "";
htmlStr += e.operateObj[i].oprName+" ";
}
return htmlStr;
}
/*]]>*/
script>
<div id="organization" style="width:200px;"
data-role="dropdowntree"
data-value-field="id"
data-load-on-demand="true"
data-bind="source:organizationDataSource,
events:{change:onSelectOrg,dataBound:onDataBound},
value:organizationId,
text:organizationText">
div>
var viewModel = kendo.observable({
onDataBound:function (e) {
if(!this.firstLoad &&
viewModel.organizationDataSource._data.length==1){
this.firstLoad=true;
e.sender.expand(".k-item:first");
}
//默认选中第一项
viewModel.set("organizationId",e.sender.dataSource._data[0].id );
viewModel.onSelectOrg();
}
});
html:
<div id="sortWindow"
data-role="cwindow"
data-bind="events:{close:sortOnClose},confirm:onSaveSort"
data-buttons="['update','cancel']"
data-ok-string="保存"
data-title="排序"
data-height="300"
data-width="200"
style="display: none">
<ul id="sortableUl" class="k-listview-block">ul>
div>
<script id="nameTemplate" type="text/x-kendo-template">
<li class="sortable"><span class="k-in">#:name#</span></li>
script>
脚本(MVVM):
var sortTable = {
sortWindowId:"sortWindow",
sortUlId:"sortableUl",
nameId:"nameTemplate",
sortEvent: function (ListDataSource, viewModel, sortDataName) {
$("#"+sortTable.sortUlId).kendocListView({
template: kendo.template($("#"+sortTable.nameId).html())
});
$("#"+sortTable.sortUlId).data("kendocListView").setDataSource(ListDataSource);
$("#"+sortTable.sortUlId).kendoSortable({
filter: ">li",
cursor: "move",
placeholder: function (element) {
return element.clone().addClass("k-listview-placeholder").html("");
},
hint: function (element) {
return element.clone().addClass("k-listview-hint");
},
change: function (e) {
var dataSource = $("#"+sortTable.sortUlId).data("kendocListView").dataSource;
var oldIndex = e.oldIndex,
newIndex = e.newIndex,
dataItem = dataSource.getByUid(e.item.data("uid"));
dataSource.remove(dataItem);
dataSource.insert(newIndex, dataItem);
viewModel.set(sortDataName,[]);
for(var i=0;i<dataSource._data.length;i++){
var sortObj = {};
sortObj.id = dataSource._data[i].id;
sortObj.orderNo = i;
viewModel[sortDataName].push(sortObj);
}
}
});
$("#"+sortTable.sortWindowId).data("kendocWindow").open();
},
onSaveSort:function (saveUrl, sortData, listDataSource) {
var resultState = true;
if(sortData.length>0){
resultfulRequestor.postJson(saveUrl, sortData, false).done(function (result) {
listDataSource.read();
}).fail(function (err) {
console.error(err.message);
listDataSource.read();
resultState = false;
});
}
return resultState;
},
onCloseSort:function (viewModel, sortDataName) {
viewModel.set(sortDataName,[]);
}
}
日常开发总是会遇到树状结构的数据,例如机构,部门,人员。若要完整展示数据,数据量过于庞大,且递归查询严重影响效率,因此实时加载数据显得格外重要。
html: 将 data-load-on-demand 属性置为"true",实现实时渲染数据。
<tr>
<td class="leftTd">部门主管td>
<td class="rightTd dropDownTreeTd">
<div id="leaderId" style="width:200px"
data-role="dropdowntree"
data-text-field="text"
data-value-field="id"
data-load-on-demand="true"
data-parent-select="false"
data-bind="source:leaderTreeDataSource,
value:reqData.leaderUserId,
events:{dataBound:onLeaderDataBound}">div>
td>
tr>
js: 这里只展示数据源
leaderTreeDataSource:new kendo.data.HierarchicalDataSource({
transport: {
read: {
cache: false,
url: commonUrl.departmentBaseUrl + "/departmentLeaderOptions",
dataType: "json"
}
},
schema: {
model: {
id: "id",
hasChildren:"hasChildren"
}
}
})
后台数据源:
需要设置hasChildren属性,并且为true,否则识别为无子节点,无法出现加载箭头。
交互示意图:
每次点击红框中的箭头(打开选项),会自动添加该数据源的id作为入参:
http://localhost:8080/department/departmentLeaderOptions?id=11862201%3D_Department