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