模拟Windows Listview的HTC组件

类别:网站制作 点击:0 评论:0 推荐:

本文属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();">
  &nbsp;&nbsp;&nbsp;&nbsp; <input type="button" value="删除" style="WIDTH:60px;HEIGHT:23px" onclick="delCur();">
 </body>
</HTML>
另外,还有两张图片:                      
 headerBg.gif:以及headerSplit.gif:。   
尽管这样反白,也不知道你能不能看清楚。      

本文地址:http://com.8s8s.com/it/it30814.htm