本文属spanzhang原创,其blog地址为:http://blog.csdn.net/spanzhang。引用或转贴请注明出处,谢谢!! 在开发B/S应用时,经常需要以列表的形式显示数据,但HTML的TABLE却显得很不够用。这里给出的是我自己的Listview模拟控件,它主要有如下几个特点: 1、Header和Columns都可以灵活配置; 2、Columns可以拖动; 3、支持单选和多选模式; 4、支持鼠标双击(引发事件)。
效果图如下:

HTC组件源代码如下(htc_listView.htc): <!--
作者:张友邦 时间:2004-12-01 描述:表格控件
-->
<!-- 接口定义 --> <public:component> <public:property name="description" value="Span ListView Behavior" /> <public:property name="version" value="1.0.0.0" /> <public:attach event="oncontentready" onevent="init()" /> <public:attach event="onselectstart" onevent="cancelSelect()" /> <public:attach event="onresize" onevent="resize()" /> <public:attach event="onmousemove" onevent="mouseMove()" /> <public:attach event="onmouseup" onevent="mouseUp()" />
<public:property name="headImage" value="/spanClient/htc_listView.htc.res/headerBg.gif" /> <public:property name="splitterImage" value="/spanClient/htc_listView.htc.res/headerSplit.gif" /> <public:property name="defStyle1" value="background-color: #DADFF1" /> <public:property name="defStyle2" value="background-color: #B9C1DD" /> <public:property name="defStyle11" value="background-color: #000000; color: #FFFFFF" /> <public:property name="defStyle22" value="background-color: #000064; color: #FFFFFF" /> <public:property name="singleSelect" value="true" /> <public:property name="freezeCols" value="false" />
<public:property name="header" /> <public:property name="columns" /> <public:property name="dataTable" /> <public:property name="rows" /> <public:property name="selectedRows" />
<public:method name="addColumn" /> <public:method name="addRow" /> <public:method name="delRow" /> <public:method name="selectRow" /> <public:method name="clearSelect" />
<public:event name="onSelChange" id="selChange" /> <public:event name="onWantEdit" id="wantEdit" /> <public:event name="onHeadClick" id="headClick" /> </public:component>
<!-- 组件实现 --> <script language="javascript"> var headerWidth = 0; //表头宽度 var bodySpan = null; //体对象 var downType = -1; //鼠标点下去的类型,点在不同地方会有不同的类型 var objSizeItem = null; //拖动线
//列对象 function column(colHeader, splitter, style1, style2, style11, style22) { this.colHeader = colHeader; this.splitter = splitter;
this.style1 = style1; //第一种未选中样式 if (this.style1 == null) this.style1 = defStyle1; this.style2 = style2; //第二种未选中样式 if (this.style2 == null) this.style2 = defStyle2; this.style11 = style11; //第一种选中状态样式 if (this.style11 == null) this.style11 = defStyle11; this.style22 = style22; //第一种选中状态样式 if (this.style22 == null) this.style22 = defStyle22; }
//内部函数,事件oncontentready,初始化 function init() { var rs = element.children[0].recordset;
//基本属性 columns = new Array(); selectedRows = new Array(); element.style.overflow = "hidden";
//构造表头 header = document.createElement("SPAN"); with (header.style) { width = "2048"; height = 20; backgroundImage = "url(" + headImage + ")"; cursor = "default"; } element.insertAdjacentElement("beforeEnd", header); //构造BODY bodySpan = document.createElement("SPAN"); with (bodySpan.style) { overflow = "auto"; cursor = "default"; } bodySpan.attachEvent("onscroll", bodyScroll); element.insertAdjacentElement("beforeEnd", bodySpan); dataTable = document.createElement("TABLE"); with (dataTable) { cellSpacing = 0; cellPadding = 0; width = 1; borderColor = "#305D03"; } bodySpan.insertAdjacentElement("beforeEnd", dataTable); rows = dataTable.rows;
//拖动线 if (freezeCols == 'false') { objSizeItem = window.document.createElement("DIV") ; with (objSizeItem.style) { backgroundColor = "black" ; cursor = "col-resize"; position = "absolute" ; border = "none";//"solid 0px" ; width = "1px" ; zIndex = 3000 ; visibility = "hidden" ; } window.document.body.insertAdjacentElement("beforeEnd", objSizeItem); }
//插入所有的列 var style1, style2, style11, style22; for (var i = 0; rs != null && !rs.EOF; ++i) { try {style1 = new String(rs('style1'));} catch(e) {style1 = defStyle1;} if (style1 == 'null') style1 = defStyle1; try {style2 = new String(rs('style2'));} catch(e) {style2 = defStyle2;} if (style2 == 'null') style2 = defStyle2; try {style11 = new String(rs('style11'));} catch(e) {style11 = defStyle11;} if (style11 == 'null') style11 = defStyle11; try {style22 = new String(rs('style22'));} catch(e) {style22 = defStyle22;} if (style22 == 'null') style22 = defStyle22;
addColumn(rs('width'), rs('text'), style1, style2, style11, style22);
rs.moveNext(); } //调整布局 resize(); }
//方法,创建列 function addColumn(colWidth, colContent, style1, style2, style11, style22) { var colIndex = columns.length; columns[colIndex] = new column ( document.createElement("SPAN"), document.createElement("SPAN"), style1, style2, style11, style22 ); //列标题栏 columns[colIndex].colHeader.innerHTML = colContent; with (columns[colIndex].colHeader.style) { width = colWidth; height = 20; textAlign = "center"; backgroundImage = "url(" + headImage + ")"; overflow = 'hidden'; headerWidth += parseInt(colWidth) + 4; } columns[colIndex].colHeader.onclick = new Function("var eventObject = createEventObject();eventObject.colIndex = " + colIndex + ";headClick.fire(eventObject);"); header.insertAdjacentElement("beforeEnd", columns[colIndex].colHeader);
//分隔条 with (columns[colIndex].splitter) { position = "absolute" ; if (freezeCols == 'false') onmousedown = new Function("splitterDown(" + colIndex + ")"); } with (columns[colIndex].splitter.style) { left = headerWidth - 4; width = 4; height = 20; if (freezeCols == 'false') cursor = "col-resize"; backgroundImage = "url(" + splitterImage + ")"; } header.insertAdjacentElement("beforeEnd", columns[colIndex].splitter);
//调整dataTable的宽度 dataTable.width = headerWidth - 2; }
//内部函数,事件onresize function resize() { with (bodySpan.style) { width = parseInt(element.clientWidth); height = parseInt(element.clientHeight) - 20; } }
//内部函数,体滚动事件onscroll function bodyScroll() { header.style.marginLeft = (-window.event.srcElement.scrollLeft) ; }
//取消选择 function cancelSelect() { with (window.event) { cancelBubble = true ; returnValue = false ; } return false ; }
var downSpliterIndex = -1; var eventX1; var eventX2;
//内部函数,分隔条点下 function splitterDown(index) { with (window.event) { eventX1 = parseInt(clientX); cancelBubble = true; returnValue = false; } element.setCapture();
downSpliterIndex = index; downType = 1; with (objSizeItem.style) { top = element.offsetTop; height = element.offsetHeight; posLeft = window.event.clientX - 3; visibility = "visible"; } }
//内部函数,事件onmousemove function mouseMove() { switch (true) { case downType == 1: objSizeItem.style.posLeft = window.event.clientX - 2; break;
default: break; } }
//内部函数,事件onmouseup function mouseUp() { if (downType == -1) return; with (window.event) { eventX2 = parseInt(clientX); cancelBubble = true; returnValue = false; }
switch (true) { case downType == 1: var dx = eventX2 - eventX1; var colWidth = parseInt(columns[downSpliterIndex].colHeader.style.width); if (colWidth + dx < 1) dx = 1-colWidth; colWidth += dx; columns[downSpliterIndex].colHeader.style.width = colWidth; dataTable.width = parseInt(dataTable.width) + dx;
for (var i = 0; i < rows.length; ++i) { //setRowCss(rows[i]); for (var j = 0; j < columns.length; ++j) { if (j == 0) rows[i].children[j].style.width = parseInt(columns[j].colHeader.style.width) + 2; else rows[i].children[j].style.width = parseInt(columns[j].colHeader.style.width) + 4; } }
setColWidth();
header.style.marginLeft = (-bodySpan.scrollLeft); break;
default: break; } element.releaseCapture(); objSizeItem.style.visibility = "hidden"; downType = -1; }
//行的事件:click function clickRow(rowIndex) { if (!window.event.ctrlKey || singleSelect == 'true') { for (var i = 0; i < selectedRows.length; ++i) { if (selectedRows[i].rowIndex >= 0) selectRow(selectedRows[i].rowIndex, false); } selectedRows.length = 0; }
if (rowIndex >= 0) selectRow(rowIndex, !rows[rowIndex].selected); }
//内部函数,设置一行选种样式 function setRowCss(row, selected) { if (selected == null) selected = row.selected; if (selected == null) selected = false;
if (!selected) { if (row.rowIndex % 2 == 0) { for (var i = 0; i < row.children.length; ++i) row.children[i].style.cssText = columns[i].style1; } else { for (var i = 0; i < row.children.length; ++i) row.children[i].style.cssText = columns[i].style2; } } else { if (row.rowIndex % 2 == 0) { for (var i = 0; i < row.children.length; ++i) row.children[i].style.cssText = columns[i].style11; } else { for (var i = 0; i < row.children.length; ++i) row.children[i].style.cssText = columns[i].style22; } }
for (var i = 0; i < row.children.length; ++i) { if (i == 0) row.children[i].style.width = parseInt(columns[i].colHeader.style.width) + 2; else row.children[i].style.width = parseInt(columns[i].colHeader.style.width) + 4; }
row.selected = selected }
//方法实现,设置某一行的选种状态 function selectRow(rowIndex, selected) { var row = rows[rowIndex]; if (row == null) return row;
if (selected) { setRowCss(row, true);
if (selectedRows.length > 0 && selectedRows[selectedRows.length - 1].rowIndex == rowIndex); else { selectedRows[selectedRows.length] = row; selChange.fire(); } } else { setRowCss(row, false); } return row; }
//方法实现 function clearSelect() { clickRow(-1); }
//内部函数 function setColWidth() { if (rows.length <= 0) return; var tableWidth = 0; for (var i = 0; i < columns.length; ++i) { if (i == 0) columns[i].colHeader.style.width = rows[0].children[i].clientWidth - 2; else columns[i].colHeader.style.width = rows[0].children[i].clientWidth - 4;
tableWidth += parseInt(columns[i].colHeader.style.width) + 4; } dataTable.width = tableWidth - 2; }
//方法实现 function addRow(rowData) { var row = dataTable.insertRow(); row.onmousedown = new Function("clickRow(" + row.rowIndex + ")"); row.ondblclick = new Function("var eventObject = createEventObject();eventObject.rowIndex = " + row.rowIndex + ";wantEdit.fire(eventObject);");
for (var i = 0; i < rowData.length; ++i) { var td = row.insertCell(); td.innerHTML = rowData[i]; } setRowCss(row, false);
//setColWidth(); return row; }
Array.prototype.remove = function(dx) { if(isNaN(dx)||dx>this.length){return false;} this.splice(dx, 1); }
//方法实现 function delRow(rowIndex) { dataTable.deleteRow(rowIndex); //重新格式化 for (var i = 0; i < rows.length; ++i) { rows[i].onmousedown = new Function("clickRow(" + i + ")"); rows[i].ondblclick = new Function("wantEdit.fire(" + i + ")"); setRowCss(rows[i], false); } //如果删除了已经选中的 var k = -1; for (var i = 0; i < selectedRows.length; ++i) { if (selectedRows[i].rowIndex == -1) k = i; else setRowCss(selectedRows[i], true); } if (k >= 0) selectedRows.remove(k); } </script>
测试文件(test_htc_listView.aspx)如下: <%@ Page language="c#" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" > <HTML> <HEAD> <title>test_htc_listView</title> <meta name="GENERATOR" Content="Microsoft Visual Studio .NET 7.1"> <meta name="CODE_LANGUAGE" Content="C#"> <meta name="vs_defaultClientScript" content="JavaScript"> <meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5"> <script> function init() { lv1.addColumn ( 200, "Added", "color:green;BORDER-BOTTOM: green 1px dashed;BACKGROUND-COLOR: #EED881", "color:green;BORDER-BOTTOM: green 1px dashed;BACKGROUND-COLOR: #EFE6C1", "color:white;BORDER-BOTTOM: green 1px dashed;BACKGROUND-COLOR: black", "color:white;BORDER-BOTTOM: green 1px dashed;BACKGROUND-COLOR: black" ); } function addData() { var data = new Array(); data[1] = "kasdkf<br>kaskd"; data[2] = "Liuk<br>as"; data[3] = "com<br>asss"; data[4] = "FF"; data[5] = "gaGG";
for (var i = 0; i < 5; ++i) { data[0] = 'A ' + i + ''; lv1.addRow(data); }
data[1] = "HH"; data[2] = "FF"; data[3] = '<span style="overflow:hidden">KKKKKSSSS呵呵</span>'; data[4] = "rr"; data[5] = "kk"; for (var i = 0; i < 5; ++i) { data[0] = '<span style="width:100%;height:100%;text-align:center">G ' + i + '</span>'; var row = lv1.addRow(data); } lv1.clearSelect(); lv1.selectRow(0, true); }
function delCur() { var oldSel = lv1.selectedRows[0].rowIndex; while (lv1.selectedRows.length > 0) lv1.delRow(lv1.selectedRows[0].rowIndex); lv1.selectRow(oldSel, true); } function wantEdit() { alert(event.rowIndex + "行想被编辑!"); }
function headClick() { alert("用户点击了第“" + event.colIndex + "”列,你可以排序,也可以什么都不干!"); } </script> </HEAD> <body MS_POSITIONING="GridLayout" bgcolor="menu" style="FONT-SIZE: 9pt; OVERFLOW: hidden" onload="init();"> <span id="lv1" style="BORDER-RIGHT: thin inset; BORDER-TOP: thin inset; LEFT: 0px; BEHAVIOR: url(/spanClient/htc_listView.htc); BORDER-LEFT: thin inset; WIDTH: 100%; BORDER-BOTTOM: thin inset; TOP: 0px; HEIGHT: 80%; BACKGROUND-COLOR: white" singleSelect='false' onwantedit="wantEdit()" onheadclick="headClick()" freezeCols='false'> <xml> <columns> <column width="50" text="col1" style1="background-color: #DADFF1;" style2="background-color: #B9C1DD;" style11="background-color: #DADFF1;" style22="background-color: #B9C1DD;" /> <column width="100" text="col2" style1="background-color: green;" style2="background-color: green;" /> <column width="100" text="col3" /> <column width="100" text="col4" /> <column width="100" text="col5" /> </columns> </xml> </span> <br> <br> <input type="button" value="增加" style="WIDTH:60px;HEIGHT:23px" onclick="addData();"> <input type="button" value="删除" style="WIDTH:60px;HEIGHT:23px" onclick="delCur();"> </body> </HTML> 另外,还有两张图片: headerBg.gif: 以及headerSplit.gif: 。 尽管这样反白,也不知道你能不能看清楚。 
|