這里是古老mvvm框架knockoutjs的學(xué)習(xí)總結(jié)生巡,邊入門邊填坑(1)
knockout(以下簡稱ko)是一個(gè)古老而有效的mvvm框架洽蛀,實(shí)現(xiàn)了model-view-viewModel模式下的雙向數(shù)據(jù)綁定摹迷。在如今angular和vue正火的年代,ko算得上是古董級(jí)了郊供。在vue中文官網(wǎng)能看到對(duì)ko的評(píng)價(jià)是:
ko的應(yīng)用場景
目前我使用ko + springmvc做后臺(tái)項(xiàng)目峡碉,視圖部分有jsp,freemarker等。項(xiàng)目用的是iframe驮审,當(dāng)然你也可以使用采用單頁框架鲫寄。為什么要使用ko做項(xiàng)目吉执,原因有2個(gè):1>支持低版本IE 2>引入MVVM框架來提升用戶和開發(fā)者編程體驗(yàn),做以前用jquery和jstl標(biāo)簽做不了的事情地来。
場景1 在一個(gè)頁面內(nèi)完成CRUD全部操作
圖中 記錄1是新增的記錄戳玫。記錄3是修改的記錄。
數(shù)據(jù)表格初始化:
var viewModel = ko.mapping.fromJS({})//定義一個(gè)空對(duì)象viewModel未斑,所有數(shù)據(jù)來自后臺(tái)
ko.mapping.fromJS(monitorDTO,viewModel);//使用mapping插件賦值咕宿,省去了自己手寫的巨大工作量
var $content = $('body');
ko.applyBindings(viewModel, $content[0]);//綁定viewModel數(shù)據(jù)到頁面DOM
數(shù)據(jù)表格新增:
//定義一個(gè)JS對(duì)象,用于新增
var userItem = {//新增用戶VO
id:"",//用戶ID
organizationId:"",//所屬機(jī)構(gòu)
username:"",//用戶名稱
password:"",//密碼
salt:"",//加密-鹽
roleIds:"",//擁有角色列表 1,2,
locked:"",//被鎖定true 未鎖定false
isdeleted:"",//被刪除1 未刪除0
nickname:"",//昵稱
isEditing:false,
passwordTwo:"",//再次輸入密碼
chosenRoleVOs:[],//擁有的角色
isChangePsd:false
}
//+新增按鈕 被點(diǎn)擊蜡秽,加入記錄1
viewModel.addUser = function(){
userItem.id = 0;
userItem.locked = false;
userItem.isdeleted = 0;
//列表頭部加入新增對(duì)象userItem府阀,也就是記錄1
viewModel.sysUserPage.resultList().unshift(ko.mapping.fromJS(userItem));
viewModel.sysUserPage.resultList.valueHasMutated();
//保存剛才新增的記錄1
viewModel.saveOneItem = function(vo){
var j = ko.mapping.toJSON(vo)
$.ajax({
url : bPath+'user/saveOneItem',
type : "POST",
dataType : "JSON",
contentType:"application/json",
data:j,
success : function(data) {
var obj = typeof data == "object" ? eval(data) : data
if(obj.status != 0){
tipError(obj.message)
return false;
}else{
//更新這條新增的記錄
ko.mapping.fromJS(obj.data,{},vo);
}
},
//取消新增記錄1
viewModel.removeOneItem = function(vo){
viewModel.sysUserPage.resultList.remove(vo)
}
數(shù)據(jù)表格修改:
//記錄3的修改被點(diǎn)擊,進(jìn)入修改狀態(tài)
viewModel.editUser = function(vo){
//先在mydata_id備份記錄3芽突,如果取消修改试浙,可以還原
$(document).data("mydata_"+vo.id(), ko.mapping.fromJS(ko.mapping.toJS(vo)));
//記錄3改為修改狀態(tài)
vo.isEditing(true)
//提交修改記錄3
viewModel.editUserInput = function(vo){
var j = ko.mapping.toJSON(vo)
$.ajax({
url : bPath+'user/editUserInput',
type : "POST",
dataType : "JSON",
contentType:"application/json",
data:j,
success : function(data) {
var obj = typeof data == "object" ? eval(data) : data
if(obj.status != 0){
tipError(obj.message)
return false;
}else{
//更新這條記錄3
ko.mapping.fromJS(obj.data,{},vo);
//退出編輯狀態(tài)
vo.isEditing(false)
tipOK("修改成功")
//修改被取消了,還原記錄3
viewModel.editUserCancel = function(vo){
var oldVO = $(document).data("mydata_"+vo.id());
ko.mapping.fromJS(ko.mapping.toJS(oldVO), {}, vo);
vo.isEditing(false)
}
//JS和頁面部分的分割線寞蚌,以下為頁面
//引入ko庫和mapping庫田巴,這里搭配使用
<script type="text/javascript" src="${bPath }static/js/knockout/knockout340.js"></script>
<script type="text/javascript" src="${bPath }static/js/knockout/knockout.mapping241.js"></script>
//圖中的表格在這里定義
<table class="am-table table-main" data-bind="template:{name:'template_userlist'}" style="border:0;"></table>
//對(duì)應(yīng)模板template_userlist
<script type="text/html" id="template_userlist">
<thead>
<tr class="am-primary">
<th class="table-id">#</th><th class="table-title">用戶名</th><th class="table-title">密碼</th><th class="table-title">昵稱</th><th class="table-title">擁有角色</th><th class="table-set">操作</th>
</tr>
</thead>
<tbody>
<!-- ko foreach:{data:sysUserPage.resultList,as:'vo'} -->
<!--瀏覽狀態(tài) -->
<!-- ko if:vo.isEditing() == false && vo.id() != 0-->
<tr>
<td><!-- ko text:$root.jisuanIndex($index()+1) --><!-- /ko --></td>
<td><!-- ko text:vo.username --><!-- /ko --></td>
<td class="">****** <a href="#" class=" am-icon-pencil-square-o admin-icon-yellow" data-bind="click:function(){return $root.changePsd(vo)},clickBubble:false">改密</a></td>
<td><!-- ko text:vo.nickname --><!-- /ko --> </td>
<td><!-- ko text:$root.convertRoleIdToName(vo) --><!-- /ko --></td>
<td>
<div class="am-btn-toolbar">
<div class="am-btn-group am-btn-group-xs">
<button class="am-btn am-btn-default am-btn-xs am-text-secondary" data-bind="click:function(){return $root.editUser(vo)},clickBubble:false"><span class="am-icon-pencil-square-o"></span> 修改</button>
<button class="am-btn am-btn-default am-btn-xs am-text-danger " data-bind="click:function(){return $root.deleteUser(vo)},clickBubble:false"><span class="am-icon-trash-o"></span> 刪除</button>
</div>
</div>
</td>
</tr>
<!-- /ko -->
<!--瀏覽狀態(tài) end-->
<!--編輯狀態(tài) -->
<!-- ko if:vo.isEditing() && vo.id() != 0-->
<tr>
<td><!-- ko text:$index()+1 --><!-- /ko --></td>
<td>
<div class="am-input-group am-input-group-sm">
<!-- ko text:vo.username --><!-- /ko -->
</div>
</td>
<td class="">
****** </td>
<td>
<div class="am-input-group am-input-group-sm">
<input type="text" class="am-form-field" style="max-width: 200px;" data-bind="value:vo.nickname,valueUpdate:'keyup',event:{keypress:$root.searchKeyboardCmdEdit}" placeholder="請(qǐng)輸入昵稱">
</div>
</td>
<td>
<select multiple data-bind="attr:{id:$root.setId4select(vo)},options:$root.roleVOs4MultiSelect,optionsText:'role',optionsValue:'id',selectedOptions: vo.chosenRoleVOs" >
</select>
</td>
<td>
<div class="am-btn-toolbar">
<div class="am-btn-group am-btn-group-xs">
<button class="am-btn am-btn-default am-btn-xs am-text-secondary" data-bind="click:function(){return $root.editUserInput(vo)},clickBubble:false"><span class="am-icon-pencil-square-o"></span> 提交修改</button>
<button class="am-btn am-btn-default am-btn-xs am-text-danger " data-bind="click:function(){return $root.editUserCancel(vo)},clickBubble:false"><span class="am-icon-trash-o"></span> 取消修改</button>
</div>
</div>
</td>
</tr>
<!-- /ko -->
<!--編輯狀態(tài) end-->
<!--新增狀態(tài) -->
<!-- ko if:vo.isEditing()==false && vo.id()== 0-->
<tr>
<td><!-- ko text:$index()+1 --><!-- /ko --></td>
<td>
<div class="am-input-group am-input-group-sm">
<input type="text" class="am-form-field" style="max-width: 200px;" data-bind="value:vo.username,valueUpdate:'keyup',event:{keypress:$root.searchKeyboardCmd}" placeholder="請(qǐng)輸入用戶名">
</div>
</td>
<td class="">
<div class="am-input-group am-input-group-sm">
<input type="password" class="am-form-field" style="max-width: 200px;" data-bind="value:vo.password,valueUpdate:'keyup',event:{keypress:$root.searchKeyboardCmd}" placeholder="請(qǐng)輸入密碼">
<input type="password" class="am-form-field" style="max-width: 200px;" data-bind="value:vo.passwordTwo,valueUpdate:'keyup',event:{keypress:$root.searchKeyboardCmd}" placeholder="請(qǐng)?jiān)俅屋斎朊艽a">
</div>
</td>
<td>
<div class="am-input-group am-input-group-sm">
<input type="text" class="am-form-field" style="max-width: 200px;" data-bind="value:vo.nickname,valueUpdate:'keyup',event:{keypress:$root.searchKeyboardCmd}" placeholder="請(qǐng)輸入昵稱">
</div>
</td>
<td>
<select multiple data-bind="attr:{id:'select_0'},options:$root.roleVOs4MultiSelect,optionsText:'role',optionsValue:'id',selectedOptions: vo.chosenRoleVOs" >
</select>
</td>
<td>
<div class="am-btn-toolbar">
<div class="am-btn-group am-btn-group-xs">
<button class="am-btn am-btn-default am-btn-xs am-text-secondary" data-bind="click:function(){return $root.saveOneItem(vo)},clickBubble:false"><span class="am-icon-pencil-square-o"></span> 確定</button>
<button class="am-btn am-btn-default am-btn-xs am-text-danger " data-bind="click:function(){return $root.removeOneItem(vo)},clickBubble:false"><span class="am-icon-trash-o"></span> 取消新增</button>
</div>
</div>
</td>
</tr>
<!-- /ko -->
<!--新增狀態(tài) end-->
<!-- /ko -->
</script>
以上就是一個(gè)基礎(chǔ)的CURD頁面,和單頁項(xiàng)目比睬澡,它就是一個(gè)組件固额。類似VUE中的component對(duì)應(yīng)的xx.vue頁面。了解了這個(gè)基礎(chǔ)頁面煞聪,再加上iframe斗躏,就能做一個(gè)偽單頁項(xiàng)目了。目前項(xiàng)目就是這么做的昔脯,因?yàn)橐С諭E7啄糙,又要有酷炫的效果。沒有ko幫忙的話云稚,應(yīng)該是很難實(shí)現(xiàn)的隧饼。另外mapping框架也是很有用的,示例中很多地方用來拷貝KO對(duì)象静陈,省去了很多手寫代碼的工作量燕雁,推薦使用。
有幾個(gè)常用的鏈接鲸拥,可以去看看
ko在github https://github.com/knockout/knockout
湯姆大叔的博客-ko指南 http://www.cnblogs.com/TomXu/archive/2011/11/21/2257154.html
mapping插件
http://knockoutjs.com/documentation/plugins-mapping.html