在 JavaScript 和 CSS 中高亮 GridView 行






4.50/5 (4投票s)
使用 JavaScript 管理控件布局、格式和突出显示,无需进行 Postback,这样更加简洁。
引言
有很多关于如何在 GridView 或其他与表相关的 HTML 控件中突出显示(背景颜色)行的示例和文章。
这篇有什么不同?首先,我展示的示例和代码是纯 JavaScript(不是 jQuery,因为那是另一个层级的专业知识!),代码是动态的(无论控件 ID 是什么都可以使用),没有硬编码控件 ID,JavaScript 位于主文件中(意味着任何辅助 ASPX 页面都可以重用相同的 JS 代码而无需在单个页面中重复),最后,我利用 CSS(样式表)的力量来控制背景颜色,而不会丢失之前的背景效果(就像一个 CSS 层覆盖另一个 CSS)。
为了实现本文的成果,没有使用一行代码隐藏或 C#/VB 代码。此外,对于那些学习 JavaScript 和客户端功能强大之处的人来说,这是一个很好的起点。
背景
好几天我都在苦思冥想如何避免 PostBack(可怕的闪烁!)。一旦你触摸了任何东西,无论是复选框、文本框还是链接,屏幕都会**闪烁**,因为调用会通过服务器并返回。肯定有更好的办法!
是的,有。
这仅仅是 JavaScript 或客户端编程。你能在客户端实现的、无需 Postback 的功能越多越好。你可以减少数据“默认”的风险,即表单上的数据重置为第一次加载时的原始状态,并且可以减少在服务器上控制事件流的风险;因为所有事件都在客户端浏览器中“平坦”地运行。代码会立即直接在你的网站中运行。无需调试!
在我看来,至少学习一些 JavaScript 对于任何网页设计师来说都是必须的。
尽情享用!
使用代码
那么,我们开始吧。
当然,第一件事就是你常用的 GridView 控件。我不会详细介绍如何在设计时创建它或如何用数据加载它等等。我会让你来管理 <datasource> 或与 GridView 相关的任何其他属性。
简单来说,这里有一个简单的 GridView,以及一个**嵌套的 GridView** 控件,在本例中它与主 GridView 中提到的学生相关 - gvStudents。
<asp:GridView ID="gvStudents" runat="server" CssClass="gvCSS" DataSourceID="SqlDataSourceStudents" AutoGenerateColumns="False" Width="87%"
OnRowDataBound="gvStudents_RowDataBound" OnDataBound="gvStudents_DataBound">
<HeaderStyle BackColor="#5D7B9D" ForeColor="White" />
<Columns>
<asp:TemplateField>
<HeaderTemplate>
<asp:CheckBox id="CheckBoxAll" runat="server" onClick="gridViewCheckAll(this)" Text="Student" TextAlign="Left"/>
</HeaderTemplate>
<ItemTemplate>
<asp:CheckBox ID="CheckBoxAdd" runat="server" onClick="highlightRow(this)" Visible='<%# Eval("StudentMobilePhone").ToString().Length > 0 %>'/>
</ItemTemplate>
<HeaderStyle Wrap="False" Width="200px" HorizontalAlign="Center" />
<ItemStyle HorizontalAlign="Center" Width="200px" Wrap="False" />
</asp:TemplateField>
...
...
</Columns>
</asp:GridView>
这里需要注意的主要几点是
- 复选框的 onClick() 事件调用及其函数名称(嵌套 GridView 的将与此相同),
- 每个 GridView 的 CssClass 属性(这些不会相同!),
- 没有指定 AlternateRow 或 Row 格式,即使有,你也会在下面的 CSS 样式表引用中看到。HeaderStyle 仅用于标题行;并且,
- 为了进一步“用户友好”,我实现了一个动态的 Visible 属性,根据学生是否有手机号码来决定是否显示复选框。至于它是否是一个有效号码,这超出了本文的范围。
嵌套的 GridView 同样相似,并嵌入在一个 <TemplateField> 或列中。
<asp:TemplateField>
<HeaderTemplate>
<asp:CheckBox ID="cbNOKall" runat="server" Text="Next Of Kin" TextAlign="Left" onClick="gridViewCheckAll(this)"/>
</HeaderTemplate>
<ItemTemplate>
<asp:GridView ID="gvNOKs" runat="server" CssClass="gvCSSsub" AutoGenerateColumns="False" BorderStyle="None" GridLines="None" ShowHeader="false" ShowFooter="false" BackColor="transparent" >
<Columns>
<asp:TemplateField HeaderText="Given Name" >
<ItemTemplate>
<asp:Label ID="lblNOKGivenName" runat="server" Text='<%# Eval("NOKname") %>'></asp:Label>
</ItemTemplate>
<ControlStyle Width="150px" />
</asp:TemplateField>
<asp:TemplateField HeaderText="NoK Type" >
<ItemTemplate>
<asp:Label ID="lblNOKType" runat="server" Text='<%# Eval("NOKType") %>'></asp:Label>
</ItemTemplate>
<ControlStyle Width="100px" />
<ItemStyle HorizontalAlign="Center" />
</asp:TemplateField>
<asp:TemplateField HeaderText="Mobile" >
<ItemTemplate>
<asp:Label ID="lblNOKMobile" runat="server" Text='<%# Eval("NOKMobile") %>'></asp:Label>
</ItemTemplate>
<ControlStyle Width="100px" />
<ItemStyle HorizontalAlign="Center" />
</asp:TemplateField>
<asp:TemplateField>
<ItemTemplate>
<asp:CheckBox ID="cbNOKAdd" runat="server" onClick="highlightRow(this)" Visible='<%# Eval("NOKMobile").ToString().Length > 0 %>'/>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</ItemTemplate>
<HeaderStyle HorizontalAlign="Left" Wrap="False" />
<ItemStyle HorizontalAlign="Center" Wrap="False" />
</asp:TemplateField>
这里需要注意的主要几点是
- 复选框的 onClick() 事件调用及其函数名称与 gvStudents 相同。
- CssClass 属性名称不同;并且,
- 同样没有指定 AlternateRow 或 Row 格式。
嵌套 GridView 的 CssClass 名称不同,这样我们可以将其行突出显示为**绿色**,**而不是黄色**。同时请注意透明背景?这样,如果学生在 NOK GridView 后面被选中,你仍然可以看到一层薄薄的黄色背景。
好的。到目前为止,我们有一个简单的 Gridview,在 NOK(Next of Kin)列中有一个嵌套的 Gridview,它有自己的主行和基于行的复选框。
所以,正如你可能已经猜到的,我们正在尝试做的是向用户提供数据,让他们可以使用复选框选择,无论是单个行还是所有行(看看 HeaderTemplates)。
快点展示 JavaScript!
如前所述,本文的另一个方面是使 JavaScript 代码**模块化**或只保存在一个地方,以便其他 ASPx 页面可以使用它。奇怪的是,我没有看到很多 JS 程序员这样做,而是到处乱放重复的代码!?为什么?你们在学校没学过 3G 编程吗?;-)
所以,废话不多说,将以下代码放在主页(如果你需要知道主页是什么 - 点击 这里)的 <body> 和 <form> 标签内,或者放在 <ContentPlaceHolder> 标签内。不要放在 <head> 元素内,否则子程序将无法拾取!如果你没有主页,请将其放在你的 ASPx 页面内的 <div>、<form> 或 <ContentPlaceHolder> 标签内。
现在,在你查看脚本之前,请注意这里有很多内容实际上比技术上必需的要多。然而,我包含了一些**垫片**(shims)以允许 JavaScript 在所有浏览器中运行,包括 7 及以上版本的旧版 IE。只需按原样复制它们。我在这里不解释它们的工作原理,但你可以搜索 ECMA262-5 例如,找到官方规范。
与本文相关的实际 JS 代码在注释掉的“hash-line”下方。
<script type="text/javascript" >
// Add ECMA262-5 method binding if not supported natively
//
if (!('bind' in Function.prototype)) {
Function.prototype.bind= function(owner) {
var that= this;
if (arguments.length<=1) {
return function() {
return that.apply(owner, arguments);
};
} else {
var args= Array.prototype.slice.call(arguments, 1);
return function() {
return that.apply(owner, arguments.length===0? args : args.concat(Array.prototype.slice.call(arguments)));
};
}
};
}
// Add ECMA262-5 string trim if not supported natively
//
if (!('trim' in String.prototype)) {
String.prototype.trim= function() {
return this.replace(/^\s+/, '').replace(/\s+$/, '');
};
}
// Add ECMA262-5 Array methods if not supported natively
//
if (!('indexOf' in Array.prototype)) {
Array.prototype.indexOf= function(find, i /*opt*/) {
if (i===undefined) i= 0;
if (i<0) i+= this.length;
if (i<0) i= 0;
for (var n= this.length; i<n; i++)
if (i in this && this[i]===find)
return i;
return -1;
};
}
if (!('lastIndexOf' in Array.prototype)) {
Array.prototype.lastIndexOf= function(find, i /*opt*/) {
if (i===undefined) i= this.length-1;
if (i<0) i+= this.length;
if (i>this.length-1) i= this.length-1;
for (i++; i-->0;) /* i++ because from-argument is sadly inclusive */
if (i in this && this[i]===find)
return i;
return -1;
};
}
if (!('forEach' in Array.prototype)) {
Array.prototype.forEach= function(action, that /*opt*/) {
for (var i= 0, n= this.length; i<n; i++)
if (i in this)
action.call(that, this[i], i, this);
};
}
if (!('map' in Array.prototype)) {
Array.prototype.map= function(mapper, that /*opt*/) {
var other= new Array(this.length);
for (var i= 0, n= this.length; i<n; i++)
if (i in this)
other[i]= mapper.call(that, this[i], i, this);
return other;
};
}
if (!('filter' in Array.prototype)) {
Array.prototype.filter= function(filter, that /*opt*/) {
var other= [], v;
for (var i=0, n= this.length; i<n; i++)
if (i in this && filter.call(that, v= this[i], i, this))
other.push(v);
return other;
};
}
if (!('every' in Array.prototype)) {
Array.prototype.every= function(tester, that /*opt*/) {
for (var i= 0, n= this.length; i<n; i++)
if (i in this && !tester.call(that, this[i], i, this))
return false;
return true;
};
}
if (!('some' in Array.prototype)) {
Array.prototype.some= function(tester, that /*opt*/) {
for (var i= 0, n= this.length; i<n; i++)
if (i in this && tester.call(that, this[i], i, this))
return true;
return false;
};
}
function hasClass(ele,cls) {
return !!ele.className.match(new RegExp('(\\s|^)'+cls+'(\\s|$)'));
}
function addClass(ele,cls) {
if (!hasClass(ele,cls)) ele.className += " "+cls;
}
function removeClass(ele,cls) {
if (hasClass(ele,cls)) {
var reg = new RegExp('(\\s|^)'+cls+'(\\s|$)');
ele.className=ele.className.replace(reg,' ');
}
}
//################################################################################################################
function gridViewCheckAll(chk) {
var cell = chk.parentNode;
var row = cell.parentNode;
var tbody = row.parentNode;
var rows = tbody.children;
var index = [].indexOf.call(row.children, cell);
for (var i = 1; i < rows.length; i++) {
var checkBoxes = rows[i].children[index].querySelectorAll('input[type=checkbox]');
for (var j = 0; j < checkBoxes.length; j++) {
checkBoxes[j].checked = chk.checked;
highlightRow(checkBoxes[j]);
}
}
}
function highlightRow(chk) {
var row = chk.parentNode.parentNode; //go to the <td> of the checkbox and then again to the <tr> of the <td>, which is the row
if (chk.checked)
addClass(row, 'selected-row');
else
removeClass(row, 'selected-row');
}
</script>
最后一个要素是 CSS 样式表本身。
<style type="text/css">
.arial { font-family: Arial; font-size: small; }
.table { font-family: Arial; font-size: small; background-color: #eeeeee; margin-right: 10px; display: inline; vertical-align: top; }
.header { text-align: center; background-color: #5D7B9D; color: White; font-weight: bold; font-size: medium; }
table.gvCSS {
margin-top: 50px;
font: 12px Verdana;
}
table.gvCSS > tbody > tr {
background-color: white;
}
table.gvCSS > tbody > tr:nth-of-type(odd) {
background-color: #EEE;
}
table.gvCSS > tbody > tr:first-of-type {
background-color: #5D7B9D;
color: white;
}
table.gvCSS > tbody > tr.selected-row {
background-color: yellow;
}
table.gvCSSsub > tbody > tr.selected-row {
background-color: lightgreen;
}
table.gvCSS tr td {
padding: 4px 15px;
}
/* ******** */
#gvCSS > tbody > tr > td:nth-of-type(1) {
width: 100px;
}
#gvCSS > tbody > tr > td:nth-of-type(2) {
width: 70px;
}
#gvCSS table > tbody > tr > td:nth-of-type(1) {
width: 120px;
}
#gvCSS table > tbody > tr > td:nth-of-type(2) {
width: 100px;
}
#gvCSS table > tbody > tr > td:nth-of-type(3) {
width: 100px;
}
</style>
你会注意到 CSS 中有 **nth-of-type(odd)** 和 **nth-of-type** 对 <td> 标签的引用?
这就是设置 GridView 的 AlternateRow 背景颜色的方法!啊,我听见你说!
所以,上述 JavaScript 的优点是,一旦你选择了一行,该行就会突出显示为黄色(或嵌套 GridView 的行为绿色),如果你取消勾选复选框,原始的 AlternateRow 背景颜色就会恢复。干净利落。
关注点
总而言之,我们有一个“又一个如何突出显示表格行中某一行”的文章,但增加了一些“用户友好”的代码。大多数其他示例都在 JavaScript 代码中**硬编码**了 GridView 的 ID,我非常讨厌这一点,而且这通常是糟糕的编程实践。所有控件和 Web 标签的 ID 都可以收集并传递给一个函数,为什么不使用呢!?当然,我也可以将 JS 代码保存在一个 .js 文件中,并在每个 ASPx 页面上简单地引用它。是的,这是另一种方法,尤其是在你没有主页的情况下。
希望你觉得这很有用,特别是用于为旧版 IE 浏览器覆盖格式的 JS 脚本。
历史
2015 年 10 月:版本 1.0, 1.1(重新措辞和语法修正)