以前都是默默地看園子里的文章,猥瑣的點贊,今天也分享一下自己用js實現的一個簡單mvvm框架。 最初只做了自動綁定事件,後面又參考學習了vue,knouckout以及argular實現方式,以及結合自己做WPF的一些經驗,增加了屬性綁定,今天又稍微整理了下,完善了部分功能,把代碼提交到了碼雲:htt ...
以前都是默默地看園子里的文章,猥瑣的點贊,今天也分享一下自己用js實現的一個簡單mvvm框架。
最初只做了自動綁定事件,後面又參考學習了vue,knouckout以及argular實現方式,以及結合自己做WPF的一些經驗,增加了屬性綁定,今天又稍微整理了下,完善了部分功能,把代碼提交到了碼雲:https://gitee.com/zlj_fy/Simple-MVVM
先簡單介紹下用法:
1 <form class="form-horizontal" role="form" data-context="TestController"> 2 <div class="form-group"> 3 <legend>Form title</legend> 4 </div> 5 <div class="form-group"> 6 <div class="col-sm-6 col-sm-offset-2"> 7 <input type="text" class="form-control" bind-val="age,format=format" style="margin:5px 0" /> 8 <input type="text" class="form-control" bind-val="desc" style="margin:5px 0" /> 9 <input type="range" min="10" max="300" bind-val="age" step="10" class="form-control" style="margin:5px 0" /> 10 <input type="button" class="btn btn-primary" value="更新" style="margin:5px 0" on-click="update" /> 11 </div> 12 </div> 13 </form> 14 15 <script> 16 var TestController = { 17 data: { 18 name: 'xiaoming', 19 age: 3, 20 desc: function() { 21 return this.name + ' likes looking little movie. he should take care of his body' 22 } 23 }, 24 format: function(val) { 25 return val + '歲' 26 }, 27 update: function() { 28 this.name = 'this is a test' 29 this.age = 18 30 } 31 } 32 $('body').controller() 33 </script>
首先定義一個控制器,可以是json對象,也可一是一個function,然後在頂層的元素定義data-context=“[控制器名稱]”就可以將該控制器綁定到該節點底下所有元素。如果元素後代存在嵌套Controller,則其所在的元素以下子元素作用域指向子控制器。
1.監控屬性以及複雜屬性
所有屬性必須定義在data節點下,如果裡面的屬性定義成function則認為是複雜屬性(例如desc),複雜屬性是只讀的,重新賦值的話會提示錯誤。
綁定到html元素上的格式:"{屬性名,fomat=[控制器方法]}",屬性名支持嵌套屬性,例如(a.b);屬性名不支持表達式,考慮了覺得不是很有必要,完全可以使用複雜屬性去代替,當前缺點是業務複雜的話可能造成大量複雜屬性;屬性名右邊是可選參數,目前只有format,也就是屬性顯示在html上的轉換方法。
2.指令
綁定指令語法是 bind-{指令}的形式,目前只實現了val,attr,text,html,template,其實可以看出,前面4個都只是簡單封裝了jqeury方法,template是用到了jquery-tmpl插件實現的,如果你需要更多的指令,你可以自己去擴展,只需要實現init初始載入方法(接收當前的observer參數),以及update方法(參數說明:對應的jquery元素,最新的值,當前控制器實例);如果是擴展已有的指令,預設會覆蓋原有的。如下:
1 $.controller.addDirective("val", {
2 init: function (observer) { 3 if (observer.$ele.is('input,select')) { 4 //監聽onchange事件 5 observer.$ele.on('input propertychange', function () { 6 var newVal = $(this).val() 7 observer.writeValue(newVal) 8 }) 9 } 10 }, 11 update: function ($ele, newVal, controller) { 12 $ele.val && $ele.val(newVal) 13 } 14 })
3.事件
綁定事件語法:on-{事件}=“{控制器方法},type=on/one”,控制器方法右邊是可選參數,目前只有綁定類型on/one,預設是on;控制器方法接收兩個參數,一個是可在對應事件的元素上設置初始參數,一個是event事件參數;
1 <button type="button" class="btn btn-primary" data-page="1" on-click="refesh">查詢</button>
4.方法
直接使用this.屬性名,就可以直接訪問對應data節點下的屬性。
5.鉤子
init以及created,init是在監聽所有屬性之後編譯dom之前,可以在這方法上初始化參數;created是編譯dom元素之後。
其中控制器預設實現了extend繼承方法,可以繼承另一個控制器,必須在init方法中使用。當前你也可以自己使用原型繼承的方式去實現。
1 init: function () { 2 this.extend(PageController) 3 }, 4 created: function () { 5 //TODO 6 },
6.擴展
相信大家在做項目的時候肯定都會有一套公用的組件,那麼可以像下麵那樣擴展,預設對應的組件掛載到所有的控制器示例下麵,就可以之間在對應的方法下直接調用了: this.http.post();
不過有一個建議,就是儘量統一將回調方法的作用域指向控制器,這樣開發不至於老是出現作用域的問題。
1 $.controller.extend({ 2 utils: utils, 3 notify: $.notify, 4 modal: $.modal, 5 http: $.http, 6 alert: $.alert 7 })
7.原理以及代碼分析(待續...)
整個js代碼量只有300多行,所以實現的比較簡單,有很多方面是沒有考慮到的,還有一些功能是想實現卻沒有去做的,
目前不支持數組變化檢測,以及局部更新相關dom。
哎,寫博客好費時間,先睡了。。。