序言:
前面我介紹了我做的.net版的AJax庫(.Net下的簡單AJax處理庫 ),現在要介紹的是一種開發模式:樣式綁定式驅動開發。
樣式驅動是我自己命名的,(我也不知道它叫什麼,嘿嘿)以便區別目前的請求驅動式開發(如struts、webwork等)和事件驅動式開發(如ASP.Net、JSF等)。
正文:
1 簡介
首先,讓我們來看看傳統的web開發流程:
·請求驅動: 最常見的一類WEB框架實現了以請求驅動的流程。一個HTTP請求近來,被一個通用的分發器Servlet
(Dispather Servlet)分析,再被分發到一個對應的應用處理器。處理器依次處理UI特有的控制邏輯,調用業務對象和處理會
話狀態,准備一個模型,再轉發到視圖。
·事件驅動: 事件驅動框架的設計目標是將桌面UI編程中著名的事件驅動模式搬到WEB環境中來。其特征是;對於如何將
表單提交到URL、如何將URL映射到控制器這些問題它們不關心;在事件驅動的框架中,表單組件和監聽器聯系在一起,監聽器
通過事件開調用。而且,這類框架通常不打算實現可插拔的試圖技術來呈現給特定的模型對象,而是把WEB頁看作一寫列界面組
件的組合物,每個組件可以保持自己的狀態,並且知道如何呈現自己,甚至可能使用不同界面皮膚。
從上面可以看到一個是傳統的MVC架構是開發,一個是以頁面為中心的快速應用開發(RAD)兩者各有各的好處。
樣式驅動式開發在請求驅動開發或事件驅動開發的基礎上進行簡單的封裝,在界面層融合了以上兩者概念優勢,它以最前台
的界面層為基礎,通過CSS樣式或HTC事件綁定界面元素來執行相應後台業務,從而達到執行相應請求,處理相應的事件的目的
。
樣式驅動的優勢在於只需把前台元素賦予特定的樣式,即可實現特殊的動能以及特定的業務處理,從而減少編碼量和編譯的
次數,具有“一次編寫,到處綁定”的特點。比傳統開發復用性更強。尤其是在AJax大行其道的今天,在請求驅動框架或事件
驅動現有框架的基礎上利用樣式綁定式開發基於AJAX的應用,你會發現你的AJax程序的開發效率會提高很多,尤其是當反復應
用同一(或相似)後台邏輯的情況會更明顯,同樣,樣式綁定式開發對於面向服務式開發也具有很大的優勢。
2 基於ASP.Net的樣式驅動開發
樣式驅動的操作不依賴與後台實現,ASP.Net的runat=server可以魔法搬地將前台元素轉化為後台的元素,不過這樣的轉化
依賴於特定的元素和後台,比如<input type=text runat=server> 這樣確實是將input元素擴展成後台可以使用的服務器元素
了,但是對於後台來講他要在頁面對應的裡進行特定的處理,而且input type=text只能是input type=text也不可能擴展自己
的功能。樣式驅動則可以把一切元素、控件或控件中的元素利用JS的強大功能在前台轉換為你想要的功能和效果,然後再送入
原請求或自定義請求,從而彌補ASP.Net的一些不足,“一次編寫,到處綁定”的特點也為我們省去了多個頁面類寫重復代碼的
諸多困擾。
也許你會說不是有用戶控件嗎,很抱歉,用戶控件跟前台嚴重耦合,你將它拿到一個項目中也許派不上一點用場。
那WEB控件庫呢?雖然能重用,跟用戶控件比不耦合了,但是局限性太強,復雜度高,我覺得叫一個普通程序員寫一個帶模
板項的DataGird能排序的,可以刪除、修改、上移下移]可以查看詳細信息的控件出來是一件很費事的事。
又有人說了,真笨,我直接拖一個DATAGRID然後再這個基礎上加按紐,模板列,排序,詳細連接好不好啊,還用特意做個
控件嗎?有很抱歉的告訴你,如果是1000個DATAGIRD,每一個都有這些功能的一種或幾種,那麼你後台夠寫的了,即使你抽象
出一層、封裝出一個專門的DataGirdBuilder類,也夠復雜的,各種重載方法,暈。
那麼使用樣式綁定式的開發就簡單了,給DataGird個排序的樣式(比如CSSClass=sort),後台幾句代碼,或者干脆不寫(
你的准備比較充足),就可以了,再加個列變為刪除按鈕(比如其中的一個列裡ItemStyle CSSClass="delbtn"),就可以了,
別的DataGrid不需要排序,那麼樣式去掉。而後頁面類裡干干靜靜。樣式綁定後變化的元素傳值到統一的業務對象進行處理,
一切都很規矩。
3 實現
利用我之前做過的AJax庫,再結合Javascript腳本構建一個這樣的庫不成問題。自然,跟做燒飯做菜一樣,這裡選料非常的
重要,這裡我要選用來自Dean Edwards和Tino Zijdel的事件操作腳本庫(common.JS)和Neil Cro~~~~y制作的樣式基本操作庫(
CSS.js)來做好我們這道美味,噢,當然,還有大名鼎鼎的prototype.JS庫.
好了,,前台的制作工序基本完成。
然後就是利用我前一陣子做的AJax庫了。
假設是刪除,QueryString: command=delrow&JS生成的參數……
則後台調用AJaxDelRow.cs
protected override void DoAJax()
...{
// 搜集參數
string parlist = request.Params["pars"];
string[] paritem = parlist.Split('|');
Hashtable hash = new Hashtable(paritem.Length);
for(int i=0;i<paritem.Length-1;i++)
...{
string[] paritempart = paritem[i].Split('^');
hash.Add(paritempart[0],paritempart[1]);
}
bool isDeled = false;
string table = request.Params["table"];
// 判斷來源
if(table!=null)
...{
if(table.Equals("dgBigclassmanage")) //DATAGRID的ID號
...{
// 調用對應業務外觀的DAO來刪除
// hash["0"]為datagrid的第0列,假設第0列傳過來是ID值
isDeled = (new BusinessFacade()).DeleteById(hash["0"].ToString());
}
if(isDeled)
...{
Output("true");
}
else
...{
Output("false");
}
}
AJaxDelRow制作流程請參考.Net下的簡單AJax處理庫
好了,完成刪除,,那麼所有對應這個業務的刪除都可以由命名為dgBigclassmanage的某一元素通過綁定delbtn樣式來執行刪
除(當然,這樣不科學,不過是DEMO嘛,如果是實際你可以在QueryString裡多傳一個參數,在到AJaxDelRow派發後再用進行二
次派發,然後以這個參數做標識就完美了)由於麻煩,,有興趣的自己做吧。。 呵呵。
這個樣式只依賴TABLE元素,所以DATAGRID、DATALIST、自己做的TABLE,自定義控件只要最後生成TABLE元素的控件都可以用。
主要提供一個思想,跟代碼制作的好壞無關。在.Net裡輕量地使用樣式綁定,在有AJax應用的開發中效果很棒。你也可以自己去實現一個更優秀的輕量框架了。
增刪改、上下移動記錄樣式綁定的JS:
/**//**
* Written by Wangzhongyuan
*
* 這是一個樣式驅動的功能按鈕控制腳本,樣式用法如下:
*
* 修改按鈕樣式: editgtn 應用樣式後即可把目標元素變為修改按鈕,目標行變為修改行並出現確定、取消按鈕。
* 刪除按鈕樣式: delbtn 應用樣式後即可把目標元素變為刪除按鈕,點擊刪除則目標刪除。
* 上移下移按鈕樣式: updownbtn 應用樣式後即可把目標元素變為上移、下移元素,目標行變為可上移和下移。
*
* 其他需要樣式正在制作中........
**/
var crudbtn = ...{
that: false,
isOdd: false,
lastAssignedId : 0,
addbtnid : 0,
newRows: -1,
init : function() ...{
// 首先, 查看浏覽器是否能執行此腳本(有些浏覽器不能用getElementsByTagName)
if (!document.getElementsByTagName) ...{
return;
}
this.that = this;
this.run();
},
/**//**
* 遍歷document中的所有table,如果有樣式crudtable,則應用此腳本
*
**/
run : function() ...{
var tables = document.getElementsByTagName("table");
for (var i=0; i < tables.length; i++) ...{
var thisTable = tables[i];
if (CSS.elementHasClass(thisTable, 'crudtable')) ...{
this.makecrudTable(thisTable);
}
}
},
/**//**
* 構建控制按鈕
**/
makecrudTable : function(table) ...{
// 首先, 檢測table是否有id,如果沒有則創建
if (!table.id) ...{
table.id = 'crudTable'+this.lastAssignedId++;
}
// 遍歷表格的數據行
var newRows = new Array();
// 遍歷表格所有數據行
for (var j = 0; j < table.tBodIEs[0].rows.length-1; j++) ...{
// 遍歷數據行所有列
for(var k = 0;k < table.tBodIEs[0].rows[j+1].cells.length;k++) ...{
// 判斷是否存在刪除樣式,如果存在則把該單元個轉化為刪除按鈕
if(CSS.elementHasClass(table.tBodIEs[0].rows[j+1].cells[k], 'delbtn')) ...{
table.tBodIEs[0].rows[j+1].cells[k].id = 'delbtn'+this.addbtnid ++;
var linkEl = createElement('a');
linkEl.href = '#';
linkEl.onclick = this.delRow;
linkEl.setAttribute('columnId', k);
var innerEls = table.tBodIEs[0].rows[j+1].cells[k].childNodes;
linkEl.innerText = "刪除";
table.tBodIEs[0].rows[j+1].cells[k].appendChild(linkEl);
}
// 判斷是否存在修改樣式,如果存在則把該單元個轉化為修改按鈕
if(CSS.elementHasClass(table.tBodIEs[0].rows[j+1].cells[k], 'editbtn')) ...{
table.tBodIEs[0].rows[j+1].cells[k].id = 'delbtn'+this.addbtnid ++;
var linkEl = createElement('a');
linkEl.href = '#';
linkEl.onclick = this.editRow;
linkEl.setAttribute('columnId', k);
var innerEls = table.tBodIEs[0].rows[j+1].cells[k].childNodes;
linkEl.innerText = "修改";
table.tBodIEs[0].rows[j+1].cells[k].appendChild(linkEl);
}
// 判斷是否存在上移、下移樣式,如果存在則把該單元個轉化為上移、下移按鈕
if(CSS.elementHasClass(table.tBodIEs[0].rows[j+1].cells[k], 'updownbtn')) ...{
table.tBodIEs[0].rows[j+1].cells[k].id = 'updownbtn'+this.addbtnid ++;
var linkEl = createElement('a');
linkEl.href = '#';
linkEl.onclick = this.upRow;
linkEl.setAttribute('columnId', k);
var innerEls = table.tBodIEs[0].rows[j+1].cells[k].childNodes;
linkEl.innerText = "上移";
table.tBodIEs[0].rows[j+1].cells[k].appendChild(linkEl);
var p = createElement('span');
p.innerHtml = " ";
table.tBodIEs[0].rows[j+1].cells[k].appendChild(p);
var linkEl2 = createElement('a');
linkEl2.href = '#';
linkEl2.onclick = this.downRow;
linkEl2.setAttribute('columnId', k);
var innerEls2 = table.tBodIEs[0].rows[j+1].cells[k].childNodes;
linkEl2.innerText = "下移";
table.tBodIEs[0].rows[j+1].cells[k].appendChild(linkEl2);
}
}
}
// 隔行換顏色,依賴odd樣式
this.isOdd = true;
var rows = table.tBodIEs[0].rows;
// We appendChild rows that already exist to the tbody, so it moves them rather than creating new ones
for (var i=0;i<rows.length-1;i++) ...{
this.DOStripe(rows[i+1]);
}
},
/**//**
* 隔行分色策略,依賴odd樣式
**/
DOStripe : function(rowItem) ...{
if (!this.isOdd) ...{
CSS.addClassToElement(rowItem, 'odd');
} else ...{
CSS.removeClassFromElement(rowItem, 'odd');
}
this.isOdd = !this.isOdd;
},
/**//**
* 刪除目標列
**/
delRow : function(e) ...{
var that = crudbtn.that;
var linkEl = getEventTarget(e);
var td = linkEl.parentNode;
var tr = td.parentNode;
var thead = tr.parentNode;
var table = thead.parentNode;
if (!table.tBodies || table.tBodIEs[0].rows.length <= 1) ...{
return false;
}
this.isOdd = true;
var rows = table.tBodIEs[0].rows;
// 實現AJax調用處理刪除
var pars = "pars=";
for(h=0;h<tr.cells.length;h++) ...{
if(!css.elementHasClass(tr.cells[h],'editbtn')&&!CSS.elementHasClass(tr.cells[h],'delbtn')
&&!CSS.elementHasClass(tr.cells[h],'updownbtn')) ...{
var colid = tr.cells[h].getAttribute('columnId');
if(tr.cells[h].firstChild.value!=null) ...{
pars += h +"^"+ tr.cells[h].firstChild.value +"|";
}
else ...{
pars += h +"^"+ tr.cells[h].innerText +"|";
}
}
}
pars += "&command=delrow&callback=afterUpdate&table="+table.id;
table.deleteRow(tr.rowIndex);
// 重新隔行換色
for (var i=1;i<rows.length;i++) ...{
if (!this.isOdd) ...{
CSS.addClassToElement(rows[i], 'odd');
} else ...{
CSS.removeClassFromElement(rows[i], 'odd');
}
this.isOdd = !this.isOdd;
}
new Ajax.Updater('result','Dispatcher.AJax?'+pars,...{evalScripts: true});
if(table.rows.length<=1) ...{
alert("該頁已無數據,系統將重載數據項");
window.location = "?";
}
},
/**//**
* 修改按鈕
**/
editRow : function(e) ...{
var that = crudbtn.that;
var linkEl = getEventTarget(e);
var td = linkEl.parentNode;
var tr = td.parentNode;
var thead = tr.parentNode;
var table = thead.parentNode;
var column = linkEl.getAttribute('columnId') || td.cellIndex;
var cellcount = tr.cells.length;
// 如果沒點擊修改
if(tr.getAttribute('editing')!=1) ...{
for(var o=0;o<cellcount;o++) ...{
// 如果該列含有修改樣式、刪除樣式或其他類似樣式,則忽略該列
if(!css.elementHasClass(tr.cells[o],'editbtn')&&!CSS.elementHasClass(tr.cells[o],'delbtn')
&&!css.elementHasClass(tr.cells[o],'updownbtn') &&!CSS.elementHasClass(tr.cells[o],'noedit')) ...{
var inputEl = createElement('input');
inputEl.type = "text";
// 文本框大小
// inputEl.size = tr.cells[o].innerText.length*2; inputEl.size = tr.cells[o].innerText.replace(/[^\x00-\xff]/gi,'xx').length;
tr.cells[o].setAttribute('columnId', o);
inputEl.setAttribute('oldValue', tr.cells[o].innerHtml);
var inputEls = tr.cells[o].innerText;
inputEl.value = inputEls;
tr.cells[o].firstChild.removeNode(true);
tr.cells[o].appendChild(inputEl);
tr.setAttribute('editing',1);
linkEl.setAttribute('oldValue',linkEl.innerText);
}
}
linkEl.innerText = "確定";
var p = createElement('span');
p.innerHtml = " ";
td.appendChild(p);
var linkEl2 = createElement('a');
linkEl2.href="#";
linkEl2.onclick = that.cancelRow;
linkEl2.innerText = "取消";
td.appendChild(linkEl2);
}
else
...{
// 如果已經點擊了確定
var pars = "pars=";
if(tr.getAttribute('editing')!=0) ...{
td.childNodes[0].removeNode(true);
td.childNodes[0].removeNode(true);
td.childNodes[0].removeNode(true);
var linkEl2 = createElement('a');
linkEl2.href="#";
linkEl2.onclick = that.editRow;
linkEl2.innerText = "修改";
td.appendChild(linkEl2);
for(h=0;h<tr.cells.length;h++) ...{
if(!css.elementHasClass(tr.cells[h],'editbtn')&&!CSS.elementHasClass(tr.cells[h],'delbtn')
&&!CSS.elementHasClass(tr.cells[h],'updownbtn')) ...{
var colid = tr.cells[h].getAttribute('columnId');
if(tr.cells[h].firstChild.value!=null)
pars += h +"^"+ tr.cells[h].firstChild.value +"|";
else
pars += h +"^"+ tr.cells[h].innerText +"|";
}
if(!css.elementHasClass(tr.cells[h],'editbtn')&&!CSS.elementHasClass(tr.cells[h],'delbtn')
&&!css.elementHasClass(tr.cells[h],'updownbtn') &&!CSS.elementHasClass(tr.cells[h],'noedit')) ...{
tr.cells[h].innerHtml = tr.cells[h].firstChild.value;
}
}
pars = pars.substr(0,pars.length-1);
tr.setAttribute('editing',0);
pars += "&command=editrow&callback=afterUpdate&table="+table.id;
new Ajax.Updater('result','Dispatcher.AJax?'+pars,...{evalScripts: true});
}
}
},
/**//**
* 取消修改
**/
cancelRow : function(e) ...{
var that = crudbtn.that;
var target = getEventTarget(e);
var td = target.parentNode;
var tr = td.parentNode;
var thead = tr.parentNode;
var table = thead.parentNode;
var column = target.getAttribute('columnId') || td.cellIndex;
for(var o=0;o<tr.cells.length-1;o++) ...{
// 如果該列含有修改樣式、刪除樣式或其他類似樣式,則忽略該列
if(!css.elementHasClass(tr.cells[o],'editbtn')&&!CSS.elementHasClass(tr.cells[o],'delbtn')
&&!css.elementHasClass(tr.cells[o],'updownbtn') &&!CSS.elementHasClass(tr.cells[o],'noedit')) ...{
tr.cells[o].innerHtml = tr.cells[o].firstChild.getAttribute('oldValue');
tr.setAttribute('editing',0);
target.innerText = target.getAttribute('oldValue');
}
}
var linkEl = createElement('a');
linkEl.href = '#';
linkEl.onclick = that.editRow;
td.firstChild.removeNode(true);
td.firstChild.removeNode(true);
td.firstChild.removeNode(true);
var innerEls = td.childNodes;
linkEl.innerText = "修改";
td.appendChild(linkEl);
td.setAttribute('columnId', column);
},
/**//**
* 上移按鈕
**/
upRow : function(e) ...{
var that = crudbtn.that;
var linkEl = getEventTarget(e);
var td = linkEl.parentNode;
var tr = td.parentNode;
var thead = tr.parentNode;
var table = thead.parentNode;
// var column = linkEl.getAttribute('columnId') || td.cellIndex;
var oTr = tr.innerHtml;
if(tr.rowIndex == 1) ...{
alert("已經是第一行了");
return false;
}
else ...{
table.moveRow(tr.rowIndex,tr.rowIndex-1);
this.isOdd = true;
var rows = table.tBodIEs[0].rows;
// 重新隔行換色
for (var i=1;i<rows.length;i++) ...{
if (!this.isOdd) ...{
CSS.addClassToElement(rows[i], 'odd');
} else ...{
CSS.removeClassFromElement(rows[i], 'odd');
}
this.isOdd = !this.isOdd;
}
}
// 實現AJax調用處理上移
var pars = "pars=";
for(h=0;h<tr.cells.length;h++) ...{
if(!css.elementHasClass(tr.cells[h],'editbtn')&&!CSS.elementHasClass(tr.cells[h],'delbtn')
&&!CSS.elementHasClass(tr.cells[h],'updownbtn')) ...{
var colid = tr.cells[h].getAttribute('columnId');
if(tr.cells[h].firstChild.value!=null) ...{
pars += h +"^"+ tr.cells[h].firstChild.value +"|";
}
else ...{
pars += h +"^"+ tr.cells[h].innerText +"|";
}
}
}
var pars2 = "&pars2=";
var uprow = table.rows[tr.rowIndex+1];
for(y=0;y<uprow.cells.length;y++) ...{
if(!css.elementHasClass(uprow.cells[y],'editbtn')&&!CSS.elementHasClass(uprow.cells[y],'delbtn')
&&!CSS.elementHasClass(uprow.cells[y],'updownbtn')) ...{
var colid = uprow.cells[y].getAttribute('columnId');
if(uprow.cells[y].firstChild.value!=null) ...{
pars2 += y +"^"+ uprow.cells[y].firstChild.value +"|";
}
else ...{
pars2 += y +"^"+ uprow.cells[y].innerText +"|";
}
}
}
pars3 = "&command=MoveUpDown&callback=afterUpdate&table="+table.id;
new Ajax.Updater('result','Dispatcher.AJax?'+pars+pars2+pars3,...{evalScripts: true});
},
/**//**
* 下移按鈕
**/
downRow : function(e) ...{
var that = crudbtn.that;
var linkEl = getEventTarget(e);
var td = linkEl.parentNode;
var tr = td.parentNode;
var thead = tr.parentNode;
var table = thead.parentNode;
var otr = tr;
if(tr.rowIndex == table.rows.length-1) ...{
alert("已經是最後一行了");
return false;
}
else ...{
table.moveRow(tr.rowIndex,tr.rowIndex+1);
this.isOdd = true;
var rows = table.tBodIEs[0].rows;
// 重新隔行換色
for (var i=1;i<rows.length;i++) ...{
if (!this.isOdd) ...{
CSS.addClassToElement(rows[i], 'odd');
} else ...{
CSS.removeClassFromElement(rows[i], 'odd');
}
this.isOdd = !this.isOdd;
}
}
// 實現AJax調用處理下移
// 下移則把pars和pars2的值反過來,後台不變
var pars = "pars2=";
for(h=0;h<tr.cells.length;h++) ...{
if(!css.elementHasClass(tr.cells[h],'editbtn')&&!CSS.elementHasClass(tr.cells[h],'delbtn')
&&!CSS.elementHasClass(tr.cells[h],'updownbtn')) ...{
var colid = tr.cells[h].getAttribute('columnId');
if(tr.cells[h].firstChild.value!=null) ...{
pars += h +"^"+ tr.cells[h].firstChild.value +"|";
}
else ...{
pars += h +"^"+ tr.cells[h].innerText +"|";
}
}
}
var pars2 = "&pars=";
var uprow = table.rows[tr.rowIndex-1];
for(y=0;y<uprow.cells.length;y++) ...{
if(!css.elementHasClass(uprow.cells[y],'editbtn')&&!CSS.elementHasClass(uprow.cells[y],'delbtn')
&&!CSS.elementHasClass(uprow.cells[y],'updownbtn')) ...{
var colid = uprow.cells[y].getAttribute('columnId');
if(uprow.cells[y].firstChild.value!=null) ...{
pars2 += y +"^"+ uprow.cells[y].firstChild.value +"|";
}
else ...{
pars2 += y +"^"+ uprow.cells[y].innerText +"|";
}
}
}
pars3 = "&command=MoveUpDown&callback=afterUpdate&table="+table.id;
new Ajax.Updater('result','Dispatcher.AJax?'+pars+pars2+pars3,...{evalScripts: true});
}
}
function crudbtnInit() ...{
crudbtn.init();
}
// 回調: 處理結束後的反映
afterUpdate = function(e) ...{
if(e == 'true') ...{
}
else if(e == 'false') ...{
alert("您的操作失敗了,請重新嘗試");
window.location.reload();
}
else if(e == 'repeated') ...{
alert("您寫入了重復的信息!請重新輸入");
window.location.reload();
}
}
addEvent(window, 'load', crudbtnInit);
後台處理同 AJaxDelRow.cs
排序樣式綁定JS:
/**//*
* Written by Wangzhongyuan
* 通過綁定sort樣式進行後台排序的代碼
*/
var sorting = ...{
that: false,
isOdd: false,
sortColumnIndex : -1,
lastAssignedId : 0,
newRows: -1,
lastSortedTable: -1,
/**//**
* 初始化排序器
**/
init : function() ...{
// 首先, 查看浏覽器是否能執行此腳本(有些浏覽器不能用getElementsByTagName)
if (!document.getElementsByTagName) ...{
return;
}
this.that = this;
this.run();
},
/**//**
* 在文檔中遍歷所有table,如果table擁有sort樣式,則啟動排序功能
**/
run : function() ...{
var tables = document.getElementsByTagName("table");
for (var i=0; i < tables.length; i++) ...{
var thisTable = tables[i];
if (CSS.elementHasClass(thisTable, 'sort')) ...{
this.makeSortable(thisTable);
}
}
},
/**//**
* 啟動給定表的排序功能
**/
makeSortable : function(table) ...{
// 首先,檢測該table是否有ID.如果沒有就分配一個給它
if (!table.id) ...{
table.id = 'sortableTable'+this.lastAssignedId++;
}
// 判斷有沒有數據
if(table.rows.length<2)
return ;
// 把表格的第一行視為表頭,然後下面要把它們變成可點擊
var row = table.tBodIEs[0].rows[0];
/**//* 結合後台的hack: 主要用於解析初始化時的排序方向.
* 由於考慮到適應自定義數據綁定模板,故越過表頭,使用第二行
*/
var row2 = table.tBodIEs[0].rows[1];
for (var i=0; i < row.cells.length; i++) ...{
// 建立一個鏈接,並使它擁有能控制排序的onClick事件
var linkEl = createElement('a');
linkEl.href = '#';
linkEl.onclick = this.headingClicked;
linkEl.setAttribute('columnId', i);
linkEl.title = '點擊排序';
// 獲取標題行的所有列,以便加入鏈接
var innerEls = row.cells[i].childNodes;
// 遍歷標題行的所有列並加入鏈接
for (var j = 0; j < innerEls.length; j++) ...{
// 如果標題列樣式為nosort則不排序
if(!CSS.elementHasClass(row.cells[i], 'nosort'))
linkEl.appendChild(innerEls[j]);
}
// 把新鏈接加到表格中
row.cells[i].appendChild(linkEl);
var spanEl = createElement('span');
CSS.addClassToElement(row.cells[i], 'tableSortArrow');
// 加兩個空格
// spanEl.appendChild(document.createTextNode(' '));
row.cells[i].appendChild(spanEl);
// 為每一列判斷從後台傳過來的排序方向樣式
if(CSS.elementHasClass(row2.cells[i], 'sortOrderASC')) ...{
spanEl.className = 'tableSortArrow';
spanEl.appendChild(document.createTextNode(' ↑'));
spanEl.setAttribute('sortOrder', 'ASC');
}
else if(CSS.elementHasClass(row2.cells[i], 'sortOrderDESC'))
...{
spanEl.className = 'tableSortArrow';
spanEl.appendChild(document.createTextNode(' ↓'));
spanEl.setAttribute('sortOrder', 'DESC');
}
}
// 初始化隔行換色標志
this.isOdd = false;
var rows = table.tBodIEs[0].rows;
// 啟動隔行換色
for (var i=0;i<rows.length;i++) ...{
this.DOStripe(rows[i]);
}
},
headingClicked: function(e) ...{
var that = sorting.that;
// 被點擊的目標鏈接
var linkEl = getEventTarget(e);
// 直接獲取td, tr, thead 和 table
var td = linkEl.parentNode;
var tr = td.parentNode;
var thead = tr.parentNode;
var table = thead.parentNode;
// 獲得目標鏈接的columnId屬性
var column = linkEl.getAttribute('columnId') || td.cellIndex;
// 找出當前列的排序方向
var arrows = CSS.getElementsByClass(td, 'tableSortArrow', 'span');
var previousSortOrder = '';
if (arrows.length > 0) ...{
previousSortOrder = arrows[0].getAttribute('sortOrder');
}
that.lastSortedTable = table.id;
// 將哪一列被排序回饋給用戶
// 首先把所有的排序方向復位
var arrows = CSS.getElementsByClass(tr, 'tableSortArrow', 'span');
for (var j = 0; j < arrows.length; j++) ...{
var arrowParent = arrows[j].parentNode;
arrowParent.removeChild(arrows[j]);
if (arrowParent != td) ...{
spanEl = createElement('span');
spanEl.className = 'tableSortArrow';
// 加入兩個空格
// spanEl.appendChild(document.createTextNode(' '));
arrowParent.appendChild(spanEl);
}
}
// 現在,回饋給用戶
var spanEl = createElement('span');
spanEl.className = 'tableSortArrow';
if (null == previousSortOrder || '' == previousSortOrder || 'DESC' == previousSortOrder) ...{
spanEl.appendChild(document.createTextNode(' ↑'));
td.setAttribute('sortOrder', 'ASC');
spanEl.setAttribute('sortOrder', 'ASC');
} else ...{
spanEl.appendChild(document.createTextNode(' ↓'));
td.setAttribute('sortOrder', 'DESC');
spanEl.setAttribute('sortOrder', 'DESC');
}
td.appendChild(spanEl);
// 以下為沒有doPostBack的版本,已經取消
/**//*
if(td.firstChild.getAttribute('columnId')!=null) {
window.location = "?sortdirect="+td.getAttribute('sortOrder')+"&colid="+td.firstChild.getAttribute('columnId');
}
else {
window.location = "?sortdirect="+td.getAttribute('sortOrder')+"&colid="+td.getAttribute('columnId');
}
*/
// 使用__doPostBack進入後台處理
__doPostBack('Pars',"sortdirect="+td.getAttribute('sortOrder')+"&colid="+td.firstChild.getAttribute('columnId'));
return false;
},
/**//**
* 隔行換色
**/
DOStripe : function(rowItem) ...{
if (!this.isOdd) ...{
CSS.addClassToElement(rowItem, 'odd');
} else ...{
CSS.removeClassFromElement(rowItem, 'odd');
}
this.isOdd = !this.isOdd;
}
}
function sortInit() ...{
sorting.init();
}
addEvent(window, 'load', sortInit)
後台:
public DataView SortBuilder(object dataobj,DataVIEw dv)
...{
string req = Request.Form["__EVENTARGUMENT"];
string p_sort = null;
string p_colid = null;
if(req!=null)
...{
string[] args = req.Split('&');
foreach (string arg in args)
...{
string[] hash = arg.Split('=');
if(hash[0].Equals("sortdirect"))
...{
p_sort = hash[1];
}
else if(hash[0].Equals("colid"))
...{
p_colid = hash[1];
}
}
if(p_sort!=null && p_colid!=null && !p_colid.Equals("null"))
...{
SortDirect = p_sort;
int iColid = Int32.Parse(p_colid);
if(dataobj is DataGrid)
...{
foreach (DataGridColumn dc in ((DataGrid)dataobj).Columns)
...{
if(((Style)(Style)dc.ItemStyle).CSSClass.IndexOf("sortOrder")!=-1)
...{
((Style)(Style)dc.ItemStyle).CSSClass = "";
}
}
((Style)(((DataGrid)dataobj).Columns[iColid].ItemStyle)).CSSClass += " sortOrder" + SortDirect;
DataGrid grid = (DataGrid)dataobj;
DataGridColumn dgc = grid.Columns[iColid];
BoundColumn bc = (BoundColumn)dgc;
string df = bc.DataFIEld;
dv.Sort = df + " " + SortDirect;
}
if(dataobj is DataList)
...{
DataList dl = (DataList)dataobj;
((Style)dl.ItemStyle).CSSClass += " sortOrder" + SortDirect;
dv.Sort = dl.DataKeyFIEld + " " + SortDirect;
}
// 自定義控件,,,可以自己實現一個
if(dataobj is table)
...{
table tbl = (table)dataobj;
tbl.DataSource = VIEwLogic.Data.DataSourceFactory.Create(dv.Table);
IList list = (tbl).ColumnList;
tbl.ColName = list[iColid].ToString();
tbl.SortDrIEct = SortDirect;
dv.Sort = list[iColid] + " " + SortDirect;
}
}
}
return dv;
}
樣式綁定的用法如下
例如,排序樣式綁定的用法:
前台: 引用JS,並綁定樣式 sort
後台:
DataSet ds = 獲取數據源ds
DataView dv = ds.Tables[0].DefaultVIEw;
dv= SortBuilder(控件,dv) ;
控件.DataSource = newdv;