EasyStruct.js轻松创建可填入式html模板结构
友情提醒:由于舊版本的EasyStruct有一些bug,現在已經全部修復,而且增加了一份詳細的demo,如果想要使用的話可以直接下載demo去看了,下面這篇介紹可以跳過了。
友情鏈接:http://download.csdn.net/detail/sinolzeng/8578461
在前端開發的工作中,經常會碰到這樣的情況,加載頁面數據的時候,有一部分內容的結構是重復的,只是數據不一樣。比如說論壇、貼吧里面的各個樓層,還有一些類似工資報表、銷售報表的每一行,舉個例子:
function addTr(data1,data2,data3){
??? return '<tr style="text-align:center"><td style="height:40px;">'+data1+'<td><td style="height:40px;">'+data2+'<td><td style="height:40px;">'+data3+'<td></tr>';
}
類似這樣的結構體,在前端開發中很常見。我們通常會創建一個這樣的東西之后,放到一個for或者each類型的循環中用于加載數據。但是,這種結構的寫法看起來多少有些不便。而且要改動也不是很方便。所以,為了工作上的便捷,我開發了一個創建結構的純js插件。用戶可以輕松創建結構體了。該插件經過壓縮后只有4kb的大小,絕對不會占用你的網頁空間!而且不依賴于jquery或其他框架,可以獨立使用。
好了,下面說一下這款插件如何使用,非常簡單,舉個例子,只需要寫:
EasyStruct("#id").struct("table")(); 就可以在指定的id下方創建一個table了。我在EasyStruct中實現了一個簡單的選擇器,可以用#id選擇id,用.class獲取class的第一個,用tag獲取tag的第一個。由于不希望該選擇器太過復雜占用js插件空間,所以只實現了以上三個選擇,不過我相信已經完全夠用了。畢竟這個插件的作用僅僅是用來創建結構而已。
肯定會有人覺得,用EasyStruct這一串字符來寫非常麻煩,嗯,沒錯,我也覺得很麻煩,所以我寫了一句:var es = EasyStruct;
此時上面的那一句就等價于 es("#id").struct("table")();
如果用戶不喜歡es的名字呢,很簡單,只需要這樣: var 你設定的名字 = EasyStruct; 或者 var 你設定的名字 = es;??? 這樣就可以隨便你使用了。
細心的朋友可能會注意到,我剛剛寫的es("#id").struct("table")(); 后面還有一個(),嗯,沒錯,這個絕對不是我寫錯了或者寫多了,而是本來如此。為什么呢,因為前面的es("#id").struct("table")返回的是一個function,而不是直接執行。不采用直接執行是為了我們可以填入參數嘛。
下面再看第二個例子:
es("#id").struct("table|style[background-color]|")("red");
這一次,在“table”的字樣后面,多出了"|style[background-color]|"的字樣,而后面的花括號里填入了“red”,很簡單,就是我們在這個結構中定義了一個設置這個table的background-color的接口,而后面的“red”就是用戶自己填入的值,這樣,我們就可以將table的背景色定義為紅色。
當然,上面的寫法也可以寫成:
var table = es("#id").struct("table|style[background-color]|");
table("red");
這樣看起來是不是就清晰很多了呢?沒錯,EasyStruct的作用就是用來創建這樣的結構的,只要我們將結構賦值給一個變量,就可以在任何地方隨意地調用該結構了,放在for循環里面自然就不是什么問題了。當然了,很多時候,我們需要填入的可不止一個變量是不是?看下面:
var table = es("#id").struct("table|style[background-color color]|");
table("red","yellow");
很簡單,直接寫進去就可以了!這樣的話呢,我們就把字體顏色給設置成了黃色了!
var table = es("#id").struct("table|style[color background-color]|");
table("red","yellow");
當然,如果上面的background-color和color的位置倒換過來的話,就會變成紅色字體,黃色背景了。變量和出現的順序是一一對應的。如果你填入的變量過多,比如在后面多了一個“blue”,是沒有任何效果的。如果少了,比如說沒有“yellow”,就相當于沒有添加背景色而已,也不會出現什么bug的。我的設定是在兩個豎杠中間可以填入一定的值來表示需要傳入的參數內容。這些值需要用空格隔開。
可以傳入的值包括:“id”? “class”? “html”? “style”
“id”和“class”沒什么好說的,“html”就是文本內容,“style”就是平時整個style的內容。舉個例子:
var div = es("#id").struct("div|id class html style|");
div("aaa","bbb","哈哈","display:block;color:red;width:100px;height:50px");
等價于jquery的寫法:
function div(id,class,html,style){
??????? $("#id").append('<div id=“'+id+'” class="'+class+'" style="'+style+'">'+html+'</div>');
};
div("aaa","bbb","哈哈","display:block;color:red;width:100px;height:50px");
另外,如果有單個或多個的attr或者style的話,也可以以花括號的形式填充進去,舉個例子:
var div = es("#id").struct("div|style=[background-color color] attr[onclick onmouseover]|");
div("red","yellow","alert(1)","this.color=\'green\'");
相當于創建了一個這樣的東西:<div style="background-color:red; color:yellow" οnclick="alert(1)" οnmοuseοver="this.color=\'green\'"></div>
相信上面的例子已經說得很清楚了吧。接下來可能有人就會說,我需要填寫的內容并不是全部啊,有些東西是固定的,比如table的id,我就希望它是固定的,而不需要自己填進去。這個當然是可以的。舉例:
var table = es("#id").struct("table(#aaa .bbb $background-color:red;color:yellow; @οnclick=alert(1) @οnmοuseοver=alert(2))");
table();
此時相當于:<table id="aaa" class="bbb" style="background-color:red; color:yellow" οnclick="alert(1)" οnmοuseοver="alert(2)"></table>
語法方面很簡單,將需要直接填入而不是以參數形式賦值的內容放在一個小括號里面。如果是id的話,就寫#id,class就寫.class,style就直接在前面加一個$,attr就加一個@,中間加一個=符號,這樣就可以將這些內容直接寫進去了。小括號的內容和豎杠的內容是可以同時存在的,并且他們誰先睡后都可以,不影響執行。
比如: var div = es.struct("div($color:red;)|id class attr[onclick]|");
div("aaa","bbb","alert(1)");
相當于:<div style="color:red" id="aaa" class="bbb" οnclick="alert(1)"></div>
這樣一來,無論是寫成固定的,還是參數形式的,都沒有任何問題了,是不是挺方便的呢?
當然,解決了上面的問題之后,還是沒辦法做實際應用的,因為我們平時所寫的結構體不可能只有一個dom元素,舉個最最簡單的例子,我們用上面的方法創建了一個tr結構,然后放到一個for循環中執行了10次,這樣確實可以在一個table里面插入10個tr,但是這10個tr里面可是連一個td都沒有的。完全不能用呢。別急,現在我們就來解決這個問題:
對應EasyStruct來說,每一次創建結構可以傳入的參數是無限制個數的,而且后面的參數會變成前面參數的子參數,舉例:
es("#id").struct("div","span");
這樣的寫法相當于在指定的id下方創建了一個div,然后又在div下方創建了一個span。至于想對這個span和div進行各種屬性處理的,這里就不贅述了,和上面的寫法是一樣的。如果是用豎杠直接填入參數的話,那么執行的順序也是從左到右,如果div里面有豎杠,就先執行,再判斷span里面有沒有豎杠,再執行,以此類推。
但是這里就有一個問題了,比如說,我想在這個div下面放兩個span,如果我這樣寫呢:
es("#id").struct("div","span","span");
很明顯是錯的,這樣寫就相當于在這個div里面放span,在這個span里面又放了一個span,是層級關系,而不是同級關系。
于是我想了一個解決方法,可以改成這樣:
es("#id").struct("div",["span","span"]);
現在兩個span被放在同一個數組之中,而這個數組作為第二個參數,那么他們就會并列地成為上一個參數div的子參數了。
聽起來好像已經解決問題了,是吧?其實沒有的,因為就實際工作而言,我們需要的結構體有時候復雜得很,不可能像我舉的例子這么簡單。我舉的例子只是為了方便讀者理解而已。
那么我們再看看另一種情況,我先以html的形式寫出來:
<table>
? <tr>
? <td></td><td></td><td></td>
? </tr>
? <tr>
? <td></td><td></td><td></td>
? </tr>
</table>
es("#id").struct("table",["tr","tr"],?? ["td","td","td","td","td","td"]);
如果我們以上面的寫法來寫的話,出現的結構就是第一個tr下面有六個td,但是第二個tr下面什么都沒有!如果我們寫第四個參數的話,它是變成第一個tr下面的第一個td的子參數,那完全不是我們想要的結果……
于是肯定有人會說,那我們是不是可以把結構改成這樣:
es("#id").struct("table",[ "tr" , ["td","td","td"] , "tr", ["td","td","td"] ]);
理論上講,要通過函數來實現上面的嵌套式設計雖然有一定難度,但并不是什么問題。但是這樣的結構讀起來并不直觀,也不好理解。所以筆者最后放棄了這樣的設計模式,而是改成了下面的形式:
es("#id").struct("table",["tr","tr"],["(0)td","(0)td","(0)td","(1)td","(1)td","(1)td"]);
采用這樣的寫法看起來就變得很直觀了,前三個td的前面多了一個0,也就是指定它們會放在上一層的第一個對象的下方。(由于index通常都是以0代表第一個的,所以筆者在這里也遵循了數組的常用習慣),而后面的三個很明顯地就會被放在第二個tr的下方了。
這樣一來,寫起來雖然稍微長了一點,但卻可以很直觀地解決這個問題了!(在我設計過程中擬定的五六種布局模式中,這種是筆者認為最簡單最好理解的,所以筆者最終選用了這樣的布局方式,如果有更好的布局方式,歡迎留言指教,感激不盡!)
采用了這種模式之后,es.struct()里面的每一個參數就代表一個樹狀結構的層。第一個參數是第一層,第二個參數是第二層,第三個參數是第三層……以此類推,每一層里面如果有多個dom對象,就將該層變成一個數組,在沒有特別指定的情況下,每一個參數都會成為上一層的第一個dom對象的子對象。而經過特別指定之后,就會成為指定對象的子對象了。
舉個例子,我們上面的例子用了三層,假設現在我想在第一個tr下面的第一個td下面放一個div,想在第二個tr的第二個td下面放一個span,那么就這樣寫:
es("#id").struct("table",["tr","tr"],["(0)td","(0)td","(0)td","(1)td","(1)td","(1)td"],["(0)div","(4)span"]);
我們來看看第四層,里面的div前面的序列號是0,也就是它會被放在上一層的第一個里面,而上一層的第一個又會追朔到上上一層的第一個tr……(其實在寫的時候我們只需要用線性思維就可以了,并不需要一層層地往上考慮,這里只是為了寫得明白一些方便讀者理解而已。)再看看span,它的index是4,所以它會被放在上一層的第五個下面。而上一層的第五個td就是第二個tr對象的第二個子對象。這樣一來,我們就實現了這樣的結構:
<table>
??? <tr>
????????? <td>
??????????????? <div></div>
????????? </td>
?????? ?? <td>?????????
????????? </td>
????????? <td>?????????
????????? </td>
??? </tr>
??? <tr>?
????????? <td>
????????? </td>
?????? ?? <td>???
??????????????? <span></span>?????
????????? </td>
????????? <td>?????????
??? </tr>
</table>
現在,采用分層和決定順序的方式,無論多復雜的dom樹結構都可以排列出來了。采用EasyStruct也不會有任何問題了。現在,不管多復雜的結構我們都可以寫出來了。
至于有人說的["(0)td","(0)td","(0)td","(1)td","(1)td","(1)td"]這樣的寫法看起來很啰嗦,是不是可以簡化一下,筆者之前也有考慮過這個問題。雖然有一些可行的解決方法,但是簡化之后不便于代碼的閱讀。畢竟,我們的設計還需要考慮可讀性的問題。讀者也不希望你寫的代碼再過一兩個月連自己都看不懂吧?
如果真要解決的話,讀者自己寫一個for循環的方法來創建這個數組,配合著EasyStruct使用就行了。舉例:
function tr(){
??? var arr = [];
??? for(var i=0;i<3;i++){arr.push("(0)td")}
???? for(var j=0;j<3j++){arr.push("(1)td")}
??? return arr;
}
es("#id").struct( "table", ["tr","tr"], tr(), ["(0)div","(4)span"] );
=_=但是我怎么覺得這樣寫更不簡便。。。。。
哈哈,對于冗長的tr結構來說還是可能就有必要,一般不要這樣寫。
而且需要注意,我們創建的是結構啊!結構啊!不是要你一次性把全部內容創建出來。因為EasyStruct里用到了不少for循環和正則表達式,如果被讀者多次執行的話,效率是很低的,也沒有這個必要。通常我們只需要創建一到兩個結構,然后重復使用這一兩個結構就夠了。對于頁面中的靜態內容部分,雖然可以使用EasyStruct,但執行效率并不高,所以筆者是不推薦大家這樣寫的。
后記:開發這個插件還有一個原因,那就是筆者曾經在設想能不能用js完全代替html,讓看起來相當雜亂的html結構徹底滾蛋呢?實驗了一段時間之后,筆者發現其實是可以的,的確可以寫出完全沒有半點html的頁面。如果是一次設計,以后都不修改的話,那么這樣寫也倒是沒什么問題。但如果你需要經常修改你的頁面結構呢?純js的寫法創建的頁面肯定會讓你修改起來蛋碎一地……哈哈。
好了,這次的EasyStruct就講到這里。我覺得js的研究過程本身是最有意思,最有意義的。如果真的想學好前端開發的話,就不要浸泡在jquery的溫柔鄉里享受,有些問題,比如瀏覽器之間的兼容性問題,還是要自己思考思考的,有條件的話也要自己把jquery給實現一遍。筆者最近差不多搞定屬于自己的jquery了,我取名Joy.js。過幾天我會把整個設計過程寫出來放到博客上和大家一起分享。
?代碼地址:http://download.csdn.net/detail/sinolzeng/8465619
總結
以上是生活随笔為你收集整理的EasyStruct.js轻松创建可填入式html模板结构的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: js insertBefore inse
- 下一篇: JS事件:target与currentT