本文属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:。尽管这样反白,也不知道你能不能看清楚。