avalon2的循環指令的用法徹底改變了。avalon最先期從knockout那樣抄來ms-each,ms-with,分別用於數組循環與對象循環。它們都是針對元素內容進行循環。後來又從angular那裏抄來了ms-repeat, 這是循環元素內部的。html
到avalon2,這三個指令合併成一個ms-for指令 ,用法與angular更類似,但沒有$index, $last, $first, $middle.數組
若是想獲得數組元素或對象的鍵值,在in關鍵字前指定一個新變量框架
<div ms-for="el in @arrayOrObject">{{el}}</div>
若是要指定數組索引值或對象的鍵名,那麼須要加一個小括號dom
<div ms-for="(index,el) in @arrayOrObject">{{el}}</div>
咱們能夠用limitBy, filterBy, orderBy, selectBy過濾器生成新的循環體性能
<div ms-for="(index,el) in @arrayOrObject | filterBy('name')">{{el}}</div>
若是用limitBy過濾器,那麼數組的長度或對象的大小會變小,那咱們如今就不
知道如今的長度,所以咱們須要另外一個變量引用新對象新數組優化
<div ms-for="(index,el) in @arrayOrObject as newArray| filterBy('name')">{{el}}::{{newArray.length}}</div>
若是想實現以前的$fist, $last效果,那就須要用到js指令ui
<div ms-for="(index,el) in @arrayOrObject as newArray| filterBy('name')"> <!--ms-js:var $first = $index === 0 --> <!--ms-js:var $last = $index === new Array -2 --> </div>
這是咱們第一次見到以註釋節點存在的指令了。實質上,ms-if的值爲false,建立的註釋節點也算是一種註釋指令。this
而avalon2是沒有像angular那樣的ng-repeat-start, ng-repeat-end這樣圈 定某個範圍的輔助指令。換言之,不能像ms-repeat那樣循環多個元素。spa
這時咱們須要瞭解一下其內部機制。這個以元素屬性存在的ms-for指令,會翻譯成以註釋節點存在的ms-for指令。翻譯
<div class='panel' ms-for="($index, el) in @array">{{el}}::{{$index}}</div>
等價於
<!--ms-for:($index,el) in @array--> <div class='panel'>{{el}}::{{$index}}</div> <!--ms-for-end:-->
這有點複雜,但能夠解決咱們循環多個元素的問題
<!--ms-for:($index,el) in @array--> <td>{{el.td1}}</td> <td>{{el.td2}}</td> <!--ms-for-end:-->
注意,avalon2的監控數組已經移除size()方法,因爲內部使用了虛擬DOM,你直接使用@array.length就能得知道當前長度了。
avalon2也沒有angular的track by機制,或像React那樣強制使用key.這種爲優化排序性能的方法,avalon內部幫你搞定,就不須要你多寫什麼了。
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <script src="./dist/avalon.js" ></script> <script> var vm = avalon.define({ $id: "test", array: ["aaa","bbb","ccc"] }) setTimeout(function(){ vm.array = ['ccc','dd1','dd2','dd3'] },3000) </script> </head> <body ms-controller="test"> <ul> <li ms-for="($index, el) in @array">{{el}} --- {{$index}}</li> </ul> </body> </html>
咱們再來看一下如何循環二維數組
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <script src="./dist/avalon.js" ></script> <script> var vm = avalon.define({ $id: "test", array: [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]] }) setTimeout(function(){ vm.array.set(0, [13,14,15,16]) },3000) </script> </head> <body ms-controller="test"> <table border="1"> <tr ms-for="($index, el) in @array"> <td ms-for="elem in el">{{elem}} 它位於第<b style="color:orchid">{{$index}}</b>行</td> </tr> </table> </body> </html>
圖上的這些註釋節點,你用過angular也會發現相似的東西,這是方便框架對這些元素進行排序增刪操做設計的。你們不要手動移除它們。
咱們再看一個經典的例子,如何經過操做數組爲列表添加或移除某一項!另,你們也能夠對照這裏看看avalon1是怎麼實現的,你就明白avalon2在這方面的巨大優點與便利。
<!DOCTYPE HTML> <html> <head> <title>ms-repeat</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <script src="./dist/avalon.js" ></script> <script> var definition = { $id: 'test', array: ['1', '2', '3', '4'], removeAt: function (e) { var elem = e.target if (isFinite(elem.value)) {//this爲input元素 var a = ~~elem.value this.array.removeAt(a) elem.value = '' } } } 'push,unshift,remove,ensure'.replace(avalon.rword, function (method) { definition[method] = function (e) { //avalon2中,全部經過ms-on-* 及其變體綁定的事件,其this都是指向vm, //而元素自己則經過e.targeta獲得 var elem = e.target if (elem.value) { this.array[method](elem.value) elem.value = '' } } }) 'pop,shift,sort,reverse'.replace(avalon.rword, function (method) { definition[method] = function (e) { this.array[method]() } }) avalon.define(definition) </script> </head> <body ms-controller="test"> <p>監控數組擁有如下方法,咱們能夠操做它們就能同步對應的區域</p> <blockquote> push, shift, unshift, pop, slice, splice, remove, removeAt, removeAll, clear, ensure, pushArray, sort, reverse, set </blockquote> <ul> <li ms-for="($index,el) in @array">數組的第{{$index+1}}個元素爲{{el}}</li> </ul> <p>對數組進行push操做,並回車<input ms-keypress="@push | enter"></p> <p>對數組進行unshift操做,並回車<input ms-keypress="@unshift | enter"></p> <p>對數組進行ensure操做,並回車<input ms-keypress="@ensure | enter"><br/> (只有數組不存在此元素才push進去)</p> <p>對數組進行remove操做,並回車<input ms-keypress="@remove | enter"></p> <p>對數組進行removeAt操做,並回車<input ms-keypress="@removeAt | enter"></p> <p><button type='button' ms-click="@sort">對數組進行sort操做</button></p> <p><button type='button' ms-click="@reverse">對數組進行reverse操做</button></p> <p><button type='button' ms-click="@shift">對數組進行shift操做</button></p> <p><button type='button' ms-click="@pop">對數組進行pop操做</button></p> <p>當前數組的長度爲<span style="color:red">{{@array.length}}</span>。</p> </body> </html>
最後咱們來一個表格的實用例子。以前avalon的大表格渲染時存在性能問題,如今大大獲得改進了。
<!DOCTYPE html> <html> <head> <title>TODO supply a title</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script src="./dist/avalon.js"></script> <script> var vm = avalon.define({ $id: 'for3', header: ['name','age','sex'], list: [] }) var sexMap = { true: "男", false: "女" } function genData(n){ var ret = [] for(var i =0 ; i< n; i++){ ret.push({ name: Math.random(), age: 3+ Math.ceil((Math.random() *30)), sex: sexMap[1-Math.random() > 0.5], desc: Math.random() }) } return ret } setInterval(function(){ var t1 = Date.now(); vm.list = genData(100) console.log('total ' + (Date.now() - t1) + ' ms'); }, 70); </script> </head> <body> <div ms-controller='for3' > <table border="1"> <tr><th ms-for='el in @header'>{{el}}</th></tr> <tr ms-for='tr in @list'> <td ms-for='td in tr | selectBy(["name","age","sex"])' ms-attr="{align:td === 'age' ?'left':'right'}">{{td}}</td> </tr> </table> </div> </body> </html>