knockoutjs-邊入門邊填坑(1)

這里是古老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à)是:


image.png

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全部操作


image.png

圖中 記錄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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末拐格,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子刑赶,更是在濱河造成了極大的恐慌捏浊,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,718評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件撞叨,死亡現(xiàn)場離奇詭異金踪,居然都是意外死亡浊洞,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門胡岔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來法希,“玉大人,你說我怎么就攤上這事靶瘸√模” “怎么了?”我有些...
    開封第一講書人閱讀 158,207評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵奕锌,是天一觀的道長。 經(jīng)常有香客問我村生,道長惊暴,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,755評(píng)論 1 284
  • 正文 為了忘掉前任趁桃,我火速辦了婚禮辽话,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘卫病。我一直安慰自己油啤,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評(píng)論 6 386
  • 文/花漫 我一把揭開白布蟀苛。 她就那樣靜靜地躺著益咬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪帜平。 梳的紋絲不亂的頭發(fā)上幽告,一...
    開封第一講書人閱讀 50,050評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音裆甩,去河邊找鬼冗锁。 笑死,一個(gè)胖子當(dāng)著我的面吹牛嗤栓,可吹牛的內(nèi)容都是我干的冻河。 我是一名探鬼主播,決...
    沈念sama閱讀 39,136評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼茉帅,長吁一口氣:“原來是場噩夢啊……” “哼叨叙!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起担敌,我...
    開封第一講書人閱讀 37,882評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤摔敛,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后全封,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體马昙,經(jīng)...
    沈念sama閱讀 44,330評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡桃犬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了行楞。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片攒暇。...
    茶點(diǎn)故事閱讀 38,789評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖子房,靈堂內(nèi)的尸體忽然破棺而出形用,到底是詐尸還是另有隱情,我是刑警寧澤证杭,帶...
    沈念sama閱讀 34,477評(píng)論 4 333
  • 正文 年R本政府宣布田度,位于F島的核電站,受9級(jí)特大地震影響解愤,放射性物質(zhì)發(fā)生泄漏镇饺。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評(píng)論 3 317
  • 文/蒙蒙 一送讲、第九天 我趴在偏房一處隱蔽的房頂上張望奸笤。 院中可真熱鬧,春花似錦哼鬓、人聲如沸监右。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽健盒。三九已至,卻和暖如春称簿,著一層夾襖步出監(jiān)牢的瞬間味榛,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評(píng)論 1 267
  • 我被黑心中介騙來泰國打工予跌, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留搏色,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,598評(píng)論 2 362
  • 正文 我出身青樓券册,卻偏偏與公主長得像频轿,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子烁焙,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容