這里是古老mvvm框架knockoutjs的學(xué)習(xí)總結(jié),邊入門邊填坑(2)
在上一篇總結(jié)中,描述了一個CRUD簡單例子霎奢,實現(xiàn)當(dāng)前頁面內(nèi)的所有操作均為異步刷新益愈,有很好的用戶體驗梢灭。同時開發(fā)人員編程也有固定的模式,弱化了jquery的直接DOM操作(僅用于ajax請求提交)蒸其,強(qiáng)化了ko的數(shù)據(jù)操作(所有數(shù)據(jù)操作敏释,事件操作)。如果有合適的異步請求插件摸袁,jquery也是可以放棄的钥顽。事實上單頁angular和vue框架已經(jīng)看不到j(luò)query了。
以下是代碼中的一些細(xì)節(jié)分析:
1.click事件
//當(dāng)前使用的click事件寫法
data-bind="click:function(){return $root.editUser(vo)},clickBubble:false"
//可以優(yōu)化為
data-bind="click:$root.editUser,clickBubble:false"
click事件的優(yōu)化寫法
點擊事件的模式化寫法(循環(huán)內(nèi))
1.<span class="attent" data-bind="click:$root.followOne,clickBubble:false">+ 關(guān)注</span>
2.<span class="attent" data-bind="click:$root.followOne2.bind($data,'里','中'),clickBubble:false">+ 關(guān)注2</span>
viewModel.followOne = function(item,event){//1.獲取本行靠汁,event
console.log(ko.toJS(item)) //vo
console.log(event.shiftKey) //event
}
viewModel.followOne2 = function(d1,d2,item,event){//2.獲取本行蜂大,event闽铐,以及d1,d2
console.log(d1)// 里
console.log(d2)// 中
console.log(ko.toJS(item)) //vo
console.log(event.shiftKey) //event
}
點擊事件的模式化寫法(循環(huán)外)
3.<a href="#" data-bind="click:$root.testClick1,clickBubble:false">測試點1</a>
4.<a href="#" data-bind="click:$root.testClick2.bind($data,'里','中'),clickBubble:false">測試點2</a>
viewModel.testClick1 = function(dto,event){//3.獲取dto,event
console.log(dto.limit()) //dto
console.log(event.shiftKey) //event
}
viewModel.testClick2 = function(d1,d2,dto,event){//4.獲取dto,event,以及d1,d2
console.log(d1) //里
console.log(d2) //中
console.log(dto.limit()) //dto
console.log(event.shiftKey) //event
}
2.回車觸發(fā)事件
用戶新增了記錄1,在輸入框填寫數(shù)據(jù)后奶浦,可以直接回車兄墅,觸發(fā)新增用戶。
//頁面上給input綁定了ko的事件監(jiān)聽
//keypress:$root.searchKeyboardCmd采用了事件的模式化寫法(循環(huán)內(nèi))
data-bind="value:vo.username,valueUpdate:'keyup',event:{keypress:$root.searchKeyboardCmd}"
//回車觸發(fā)確認(rèn)新增用戶
viewModel.searchKeyboardCmd = function (data, event) {
if(event.keyCode == 13){
viewModel.saveOneItem(data)
return false;
}
return true;
}
3.mapping的使用
新增userItem到ko的resultList列表中澳叉,此時userItem的ID是空的瓷患。提交新增請求辣苏,成功后绳军,需要用后臺返回的json對象obj.data賦值給ko的vo
//使用mapping把后臺的json數(shù)據(jù)賦值給ko對象
ko.mapping.fromJS(obj.data,{},vo);
使用mapping需要了解js對象彰导,json對象和ko對象的區(qū)別,它們之間是可以互相轉(zhuǎn)換的
json : 來自后臺瓶殃,通常由后臺服務(wù)返回JSON對象充包,包含列表,單個對象等 {status : 0 , message:'各種提示',data:{實際數(shù)據(jù)包}} (json對象)
js:從json獲得實際數(shù)據(jù)包 xx.data (js對象)
ko: 把js對象用ko.mapping.fromJS轉(zhuǎn)化成vo (ko對象)
json ----> js -----> ko -------> js ----> json
ko.utils.parseJson ko.mapping.fromJS(xxDTO,{} viewModel) ko.mapping.toJS/ko.toJS JSON.stringify
JSON.parse
4.valueHasMutated
往列表中插入新KO對象碌燕,會觸發(fā)列表上其他對象的KO事件误证,如果一次加多個,有時會觸發(fā)多次修壕,為了避免這個問題愈捅,加入了valueHasMutated方法,讓所有新對象全部加入后慈鸠,才執(zhí)行一次觸發(fā)事件蓝谨。
其他的ko用法還有自定義綁定ko.bindingHandlers,全選/反選青团,列表渲染后自定義觸發(fā)等譬巫。
5.my97DatePicker在ko中正確的顯示時間
//頁面使用新的日期綁定
data-bind="my97DatePicker:criteriaVO.headTime,sdf:'yyyy-MM-dd'"
//自定義 my97DatePicker
ko.bindingHandlers.my97DatePicker = {
init: function (element, valueAccessor,allBindings) {
var sdf = allBindings.get('sdf') || 'yyyy-MM-dd HH:mm:ss';
$(element).click(function() {
WdatePicker({dateFmt: sdf,onpicking:function(dp){
var nt = dp.cal.getNewDateStr()
valueAccessor()(nt)
},
oncleared:function(dp){
var nt = dp.cal.getNewDateStr()
valueAccessor()('')
}
})
});
},
update: function (element, valueAccessor) {
var v = valueAccessor()();
$(element).val(valueAccessor()());
if(v != null && v != ''){
}
}
};
6 全選/反選
以前寫checkbox的全選,反選督笆,用jquery很繁瑣芦昔,因為是直接操作DOM視圖。ko的思想則不同娃肿,開發(fā)者只操作ko數(shù)據(jù)咕缎,具體視圖交給ko自行渲染
//頁面-全選
data-bind="checked:selectAll"
//頁面-每一行
<input type="checkbox" data-bind="checked:fvo.fileCheck" >
//JS
viewModel.selectAll = ko.computed({
//全選hkj
read : function() {
var item = ko.utils.arrayFirst(viewModel.yunFileVOs(), function(item) {
return !item.fileCheck();
});
return item == null;
},
write : function(value) {
ko.utils.arrayForEach(viewModel.yunFileVOs(), function (item) {
item.fileCheck(value);
});
}
});
- pushAll
ko沒有類似pushAll的語法。料扰。凭豪。所以要批量提交,需要自實現(xiàn)晒杈。
//頁面
viewModel.teacherRecommends.pushAll(valuesToPush)
//自實現(xiàn)pushAll嫂伞,接收J(rèn)S數(shù)組為參數(shù)
ko.observableArray.fn.pushAll = function(valuesToPush) {
for(var i = 0 ; i < valuesToPush.length ; i++ ){
var tempV = valuesToPush[i]
console.log(">>>PUSH ALL :"+tempV.teacherId+"-"+tempV.realName)
console.log(tempV.teacherId != '')
if(tempV.teacherId != ''){
this.push(ko.mapping.fromJS(tempV))
}
}
this.valueHasMutated();//再次使用了valueHasMutated
return this;
};
KO的坑還是有的,但都有適配的方法來解決,而且都很容易做到√現(xiàn)在我主要把KO當(dāng)一個簡單的mvvm庫來使用撰豺,這是它的天然優(yōu)勢,值得好好學(xué)習(xí)拼余。再深入學(xué)習(xí)的話郑趁,就是組件了。如果做單頁項目姿搜,建議轉(zhuǎn)VUE學(xué)習(xí)
KO+路由也是可以做的,看這里
durandal框架(內(nèi)置路由捆憎,搭配ko,requirejs)
http://durandaljs.com/get-started.html