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