65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 DHTML 和 JavaScript 实现动态表格筛选/搜索

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.83/5 (39投票s)

2001年8月30日

CPOL

10分钟阅读

viewsIcon

320099

downloadIcon

4102

无需往返服务器,即可轻松为您的网页添加表格筛选/搜索功能。

最新版本是 v1.0e

背景

前段时间,我正在开发一个典型的 Web 应用程序,该应用程序允许用户浏览和管理存储在数据库中的客户数据等。通常的做法是在服务器端实现此类逻辑。但是,一个特定的要求是用户必须能够使用一个或多个搜索条件从表格中快速搜索和查找一个或多个记录。往返服务器被认为成本太高。因此需要一个客户端解决方案。

此解决方案结合使用了 JavaScript 和 DHTML。该脚本在创建时考虑了灵活性、可重用性和简单性。即,开发人员(指您)只需包含该脚本,设置一些参数,并在适当的事件处理程序中进行 JavaScript 调用。

特点

此脚本提供以下功能集

  • 搜索条件可以是文本框、单选或多选列表框
  • 允许组合搜索条件(作为 AND 操作)
  • 提供 4 种匹配策略
    1. substring1 - 子字符串搜索(从第一个字符开始)(默认)
      例如,man 将匹配“manhood”和“man is evil”,而不是“superman”和“he is a man”
    2. substring - 子字符串搜索(任意位置)
      例如,man 将匹配“manhood”、“superman”和“he is a man”
    3. full - 全字符串搜索
      例如,man 将匹配“man”,而不是“manhood”、“superman”、“man is evil”和“he is a man”
    4. item - 在逗号分隔的字符串中搜索单词/短语
      例如,man 将匹配“man,woman,child”,而不是“superman,superwoman,kid”和“boy,girl,dog”
  • 如果搜索字符串中的最后一个字符是空格,则执行全字符串匹配(在 substring1 模式下)。
  • 允许关闭/打开搜索。
  • *新功能* 允许根据表格中的复选框状态进行筛选。搜索条件可以表示为复选框或单选下拉列表。

用法

要使用此脚本,您首先需要将其包含在您的 HTML 中,如下所示

<SCRIPT LANGUAGE="JavaScript" SRC="tablefilter.js" TYPE='text/javascript'>
</SCRIPT>

建议将此代码包含在 HTML 的 head 部分。

设置表格

首先,使用属性 idname 为表格元素提供一个句柄。这是必需的,以便脚本可以使用此引用访问表格中的行。在单元格元素中,包含一个名为 TF_colKey 的自定义属性,并为其提供一个标签以标识列。请注意,此属性仅在将进行搜索的列中是必需的。确保特定列中的所有单元格都使用相同的标签。另请注意,标签名称“不区分大小写”。

HTML 中此示例的外观如下所示

<table id="dataTable">
  <tbody> 
    <tr> 
      <td TF_colKey="ckbox"><INPUT type="checkbox"></td> 
      <td TF_colKey="name">Joe</td>
      <td TF_colKey="group">Alpha</td>
      <td TF_colKey="salary">400</td>
      <td TF_colKey="zone">North,South</td>
      <td TF_colKey="status">Off-Site</td>
    </tr>
    <tr> 
      <td TF_colKey="name">Celest</td>
      <td TF_colKey="group">Beta</td>
      <td TF_colKey="salary">5000</td>
      <td TF_colKey="zone">North</td>
      <td TF_colKey="status">OK</td>
    </tr>
  </tbody>
</table>

现在,简单的部分已经完成!

设置搜索表单

搜索条件输入机制是使用 HTML form 实现的。为了标识搜索输入组,需要使用 idname 属性为 form 元素提供一个句柄。

<form name="filter" onsubmit="TF_filterTable(dataTable, filter);return false" 
         onreset="_TF_showAll(dataTable)">

覆盖 onsubmit 以调用主脚本函数 TF_filterTable(table, form),并传入 table form 元素的句柄。通过这样做,当用户按下Enter键时,搜索将被激活。由于此 form 实际上不会提交到服务器,因此附加一个 return false 以取消提交。

您可能还希望通过让 onreset 调用脚本函数 _TF_showAll(table) 并传入 table 元素的句柄,来允许用户轻松重置搜索表单并显示所有行。

使用文本输入框

使用以下代码实现文本输入搜索字段

<input type="text" TF_colKey="name" TF_searchType="full" 
          onkeyup="TF_filterTable(dataTable, filter)">

属性 TF_colKey 应反映此搜索参数适用的列的名称。因此,在上述情况下,文本框中的条目将与 TF_colKey 属性中包含值“name”的任何单元格匹配。同样,此属性仅对将在搜索过程中使用的输入字段是必需的。这对于构建复杂的查询输入(在后面的部分中解释)特别有用。

属性 TF_searchType 是可选的,它定义将执行的匹配类型。可用选项有 substring1 - 从第一个字符开始的子字符串搜索(默认),substring - 任意位置的子字符串搜索,full - 仅匹配完整字符串和 item - 匹配任何逗号分隔的单词/短语。在上面的示例中,我们使用 full 字符串搜索。

要让搜索在用户按下按键后立即激活,请覆盖 onkeyup 以调用主搜索函数 TF_filterTable(table, form),并传入 table form 元素的句柄。

使用选择列表输入框

使用以下代码实现选择列表输入搜索字段

<select TF_colKey="status" onChange="TF_filterTable(dataTable, filter)">
  <option TF_not_used value="">-</option>
  <option value="OK">OK</option>
  <option value="Off-Site">Off-Site</option>
  <option value="On Leave">On Leave</option>
</select>

同样,属性 TF_colKey 应反映此搜索参数适用的列的名称。因此,在上述情况下,列表框中的条目将与 TF_colKey 属性中包含值“status”的任何单元格匹配。

与所有其他搜索输入一样,可以在 select 元素中指定可选属性 TF_searchType 以定义替代匹配策略。

请注意,选项元素的 value 属性将用作搜索字符串,而不是其包含的文本。如果某个特定选项不用于搜索(例如,单选下拉列表框中的默认值,如上面示例中的第一个选项),请使用自定义属性 TF_not_used 将其从搜索中排除。

要让搜索在做出选择后立即激活,请覆盖 onChange 以调用主搜索函数 TF_filterTable(table, form),并传入 table form 元素的句柄。

如果使用多选列表(通过在 select 元素中指定 size 属性),则选择以 OR 方式匹配。查看演示以了解其工作原理。

根据复选框状态筛选表格内容

应大众要求,我添加了一个新功能,允许根据复选框的状态筛选行。要使用此功能,您可以通过两种方式指定搜索框;可以是复选框或下拉列表。在上面的演示中,我选择使用下拉列表以便于实现。

请注意,由于需要三种状态来表达搜索条件(即选中、未选中和关闭),并且 HTML 复选框不能用于三态模式,因此您需要实现另一个控件(例如复选框)来启用或禁用搜索复选框以完全表达搜索条件,在我看来,这看起来有些笨拙。无论如何,代码完全支持此用例,并且我已进行了一些初步测试,因此它应该按预期工作。

显示下拉列表搜索条件的代码如下所示

<SELECT onchange="TF_filterTable(dataTable, filter)" 
                TF_colKey="ckbox" TF_searchType="checkbox">
    <OPTION value="" selected TF_not_used>-</OPTION> 
    <OPTION value="true">checked</OPTION> 
    <OPTION value="false">unchecked</OPTION>
</SELECT>        

同样,属性 TF_colKey 应反映此搜索参数适用的列的名称。因此,在上述情况下,列表框中的条目将与 TF_colKey 属性中包含值“ckbox”的任何单元格匹配。

请注意,使用 TF_searchType="checkbox" 对于此代码工作是“强制性”的。此外,checked 的选项值“必须”是值为“true”的字符串,同样,unchecked 的选项值“必须”是值为“false”的字符串。

对于那些感兴趣的人,显示复选框搜索条件的代码如下所示

<INPUT type="checkbox" TF_colKey="ckbox" 
           onclick="TF_filterTable(dataTable, filter)">

构建复杂的查询输入

我在项目中面临的挑战之一是使用多个输入字段构建单个搜索条件。例如,表格值为“100 USD”,输入由一个用于数字部分的文本框和一个用于单位部分的选择列表构成(请参阅上面的演示以获取实时示例)。

最初,我曾想将此功能直接整合到脚本中。但我还没有找到一种优雅的方法来做到这一点;实现不够健壮,无法处理所有组合,而且使用起来变得非常复杂。也许在未来的版本中。但在此期间,这里有一种您可以使用的方法

定义一个从视图中隐藏的中间输入字段(使用隐藏的输入字段或将显示样式设置为 none)。编写一个自定义函数,从构成复杂查询的输入中执行必要的格式化(例如连接值),并将结果放置在隐藏字段中。然后在搜索输入的事件处理程序中,在调用表格筛选函数之前调用格式化函数。就是这样!

这是上面演示中执行复杂查询的代码片段

<input type="text" name="salText" 
    onblur="TF_concat_and_set(salText, salSelect, salHidden);
    TF_filterTable(dataTable, filter);">
<select name="salSelect" 
    onChange="TF_concat_and_set(salText, salSelect, salHidden);
    TF_filterTable(dataTable, filter);">
 <option value="" TF_not_used>-</option>
 <option value=" USD">USD</option>
 <option value=" SGD">SGD</option>
 <option value=" YEN">YEN</option>
</select>
<input type="hidden" name="salHidden" TF_colKey="salary" 
                        TF_searchType="substring">

请注意,文本和选择元素都没有定义自定义属性 TF_colKey,因为我们不希望它们包含在搜索中;我们改为在隐藏输入字段中定义该属性。函数 TF_concat_and_set 将执行两个输入值的连接并将结果放置在隐藏输入中。此实用函数包含在表格筛选脚本中,以方便其他用户使用。

打开/关闭搜索表单

提供了一个实用函数 TF_enableFilter(table, form, checkbox),可以轻松打开或关闭搜索功能。在关闭状态下,表格将显示所有行,搜索表单将被隐藏。要启用此功能,请使用以下代码片段

<input type="checkbox" checked 
       onclick="TF_enableFilter(dataTable, filter, this)">

演示代码

<script type="text/javascript" src="tablefilter/tablefilter.js" language="JavaScript"></script>
<table>
    <tr valign="top" align="left">
        <td>
        <table cellspacing="0" cellpadding="0" border="1">
            <tr valign="middle">
                <td colspan="6">
                <div align="center">
                    <strong>Sales Employee Table </strong></div>
                </td>
            </tr>
            <tr>
                <td>
                <div style="width: 585px;">
                    <table cellspacing="0" cellpadding="2" border="1" id="header">
                        <tr>
                            <th width="20">
                            <input type="checkbox" 
                                onclick="TF_check_uncheck_all_rows(dataTable,this.checked,0,0);" />
                            </th>
                            <th width="80">Name</th>
                            <th width="100">Group</th>
                            <th width="100">Salary</th>
                            <th width="180">Zone</th>
                            <th width="95">Status</th>
                        </tr>
                    </table>
                </div>
                <div style="border: 1px solid gray; padding: 0px; margin: 0px; overflow: auto; width: 585px;height: 132px;">
                    <table cellspacing="0" cellpadding="2" border="1" id="dataTable">
                        <tr id="dataRow">
                            <td width="20" valign="top" tf_colkey="ckbox">
                            <input type="checkbox" /> </td>
                            <td width="80" valign="top" tf_colkey="name">Joe</td>
                            <td width="100" valign="top" tf_colkey="group">Alpha</td>
                            <td width="100" valign="top" tf_colkey="salary">400 
                            USD</td>
                            <td width="180" valign="top" tf_colkey="zone">
                            North,South</td>
                            <td width="80" valign="top" tf_colkey="status">
                            Off-Site</td>
                        </tr>
                        <tr id="dataRow">
                            <td width="20" valign="top" tf_colkey="ckbox">
                            <input type="checkbox" /> </td>
                            <td width="80" valign="top" tf_colkey="name">Celest</td>
                            <td width="100" valign="top" tf_colkey="group">Beta</td>
                            <td width="100" valign="top" tf_colkey="salary">
                            50000 YEN</td>
                            <td width="180" valign="top" tf_colkey="zone">North</td>
                            <td width="80" valign="top" tf_colkey="status">OK</td>
                        </tr>
                        <tr id="dataRow">
                            <td width="20" valign="top" tf_colkey="ckbox">
                            <input type="checkbox" /> </td>
                            <td width="80" valign="top" tf_colkey="name">Brian</td>
                            <td width="100" valign="top" tf_colkey="group">Alpha</td>
                            <td width="100" valign="top" tf_colkey="salary">4000 
                            SGD</td>
                            <td width="180" valign="top" tf_colkey="zone">
                            North,East,South</td>
                            <td width="80" valign="top" tf_colkey="status">
                            Off-Site</td>
                        </tr>
                        <tr id="dataRow">
                            <td width="20" valign="top" tf_colkey="ckbox">
                            <input type="checkbox" /> </td>
                            <td width="80" valign="top" tf_colkey="name">David</td>
                            <td width="100" valign="top" tf_colkey="group">Alpha</td>
                            <td width="100" valign="top" tf_colkey="salary">7000 
                            SGD</td>
                            <td width="180" valign="top" tf_colkey="zone">
                            West,South</td>
                            <td width="80" valign="top" tf_colkey="status">On 
                            Leave</td>
                        </tr>
                        <tr id="dataRow">
                            <td width="20" valign="top" tf_colkey="ckbox">
                            <input type="checkbox" /> </td>
                            <td width="80" valign="top" tf_colkey="name">Pauline</td>
                            <td width="100" valign="top" tf_colkey="group">Gamma</td>
                            <td width="100" valign="top" tf_colkey="salary">450 
                            USD</td>
                            <td width="180" valign="top" tf_colkey="zone">West</td>
                            <td width="80" valign="top" tf_colkey="status">On 
                            Leave</td>
                        </tr>
                        <tr id="dataRow">
                            <td width="20" valign="top" tf_colkey="ckbox">
                            <input type="checkbox" /> </td>
                            <td width="80" valign="top" tf_colkey="name">April</td>
                            <td width="100" valign="top" tf_colkey="group">Gamma</td>
                            <td width="100" valign="top" tf_colkey="salary">2400 
                            SGD</td>
                            <td width="180" valign="top" tf_colkey="zone">North, 
                            West</td>
                            <td width="80" valign="top" tf_colkey="status">OK</td>
                        </tr>
                        <tr id="dataRow">
                            <td width="20" valign="top" tf_colkey="ckbox">
                            <input type="checkbox" /> </td>
                            <td width="80" valign="top" tf_colkey="name">Sharon</td>
                            <td width="100" valign="top" tf_colkey="group">Beta</td>
                            <td width="100" valign="top" tf_colkey="salary">2000 
                            SGD</td>
                            <td width="180" valign="top" tf_colkey="zone">
                            East,South</td>
                            <td width="80" valign="top" tf_colkey="status">
                            Off-Site</td>
                        </tr>
                        <tr id="dataRow">
                            <td width="20" valign="top" tf_colkey="ckbox">
                            <input type="checkbox" /> </td>
                            <td width="80" valign="top" tf_colkey="name">Paul</td>
                            <td width="100" valign="top" tf_colkey="group">Beta</td>
                            <td width="100" valign="top" tf_colkey="salary">2500 
                            SGD</td>
                            <td width="180" valign="top" tf_colkey="zone">
                            North,South,East,West</td>
                            <td width="80" valign="top" tf_colkey="status">On 
                            Leave</td>
                        </tr>
                    </table>
                </div>
                </td>
            </tr>
        </table>
        </td>
    </tr>
    <tr valign="top" align="center">
        <td height="209">
        <table width="601" height="40" cellspacing="0" cellpadding="0" border="0">
            <tr valign="bottom">
                <td height="40">
                <input type="checkbox" checked="true" onclick="TF_enableFilter(dataTable, filter, this)" /> 
                Enable Filter </td>
            </tr>
            <tr>
                <td>
                <form onsubmit="TF_filterTable(dataTable, filter);return false" 
                    onreset="_TF_showAll(dataTable)" name="filter">
                    
                    <table width="604" height="40" cellspacing="0" cellpadding="0" border="0">
                        <tr>
                            <td height="40">
                            <input type="button" value="Reset filters" onclick="filter.reset()" />
                            </td>
                        </tr>
                        <tr valign="bottom">
                            <td width="325" height="40">Name:(substring1 search)</td>
                            <td width="250" height="20">Group:(full string 
                            search, Multi-select)</td>
                            <td width="133" height="20">Status:(full string 
                            search)</td>
                        </tr>
                        <tr>
                            <td width="325" height="34">
                            <input tf_colkey="name" size="40" onkeyup="TF_filterTable(dataTable, filter)" />
                            </td>
                            
                            <td width="250" height="24">
                            <select tf_searchtype="full" tf_colkey="group" size="3" multiple="true" 
                                onchange="TF_filterTable(dataTable, filter)">
                                <option value="Alpha">Alpha</option>
                                <option value="Beta">Beta</option>
                                <option value="Gamma">Gamma</option>
                            </select> </td>
                            
                            <td width="133" height="34">
                            <select tf_searchtype="full" tf_colkey="status" 
                                onchange="TF_filterTable(dataTable, filter)">
                                <option>-</option>
                                <option value="OK">OK</option>
                                <option value="Off-Site">Off-Site</option>
                                <option value="On Leave">On Leave</option>
                            </select> </td>
                        </tr>
                        <tr valign="bottom">
                            <td width="325" height="40">Salary:(complex query)</td>
                            <td width="250" height="20">Zone:(Item search, 
                            Multi-select)</td>
                            <td width="250" height="20">Checkbox: (Filter by 
                            status of checkbox)</td>
                        </tr>
                        <tr>
                            <td width="325" height="34">
                            <input name="salText" size="30" 
                                onblur="TF_concat_and_set(salText, salSelect, salHidden);TF_filterTable(dataTable, filter);" />
                            <select name="salSelect" 
                                onchange="TF_concat_and_set(salText, salSelect, salHidden);TF_filterTable(dataTable, filter);">
                            <option selected="true">-</option>
                            <option value=" USD">USD</option>
                            <option value=" SGD">SGD</option>
                            <option value=" YEN">YEN</option>
                            </select>
                            <input type="hidden" tf_searchtype="substring" tf_colkey="salary" name="salHidden" />
                            </td>
                            <td width="250" height="34">
                            <select tf_searchtype="item" tf_colkey="zone" size="4" multiple="true" 
                                onchange="TF_filterTable(dataTable, filter)">
                            <option value="East">East</option>
                            <option value="West">West</option>
                            <option value="North">North</option>
                            <option value="South">South</option>
                            </select> </td>
                            <td>
                            <select tf_searchtype="checkbox" tf_colkey="ckbox" name="salSelect2" 
                                onchange="TF_filterTable(dataTable, filter)">
                            <option selected="true">-</option>
                            <option value="true">checked</option>
                            <option value="false">unchecked</option>
                            </select></td>
                        </tr>
                    </table>
                </form>
                </td>
            </tr>
            <tr>
                <td></td>
            </tr>
        </table>
        </td>
    </tr>
</table>

浏览器兼容性

此脚本和演示仅在 IE 平台上开发和测试,因为该项目不需要与 Netscape 兼容。使其在 Netscape 上运行应该不会太难,我有时间时可能会着手处理。我也会很乐意在这方面获得任何帮助。

结论

好吧,就这样了,各位。开发这个脚本和撰写这篇文章非常有趣。希望您也会喜欢它!哦,我非常欢迎任何反馈、错误报告或建议。

版本历史

  • 2007 年 6 月 19 日 - 版本 1.0e 发布

    • 添加了便利函数 TF_check_uncheck_all_rows ,用于帮助选中/取消选中表格中的所有行
    • 添加了新功能,允许通过复选框 OR 单选下拉列表根据复选框状态进行筛选
    • 添加了新功能,允许根据复选框状态进行筛选
  • 2001 年 8 月 24 日 - 版本 1.0d 发布

    • 添加了函数 _TF_get_value TF_concat_and_set
    • 隐藏输入现在可以用作搜索字段
    • 实现了“substring”搜索模式
    • 提高了健壮性/灵活性:如果 table 中的单元格 <td> 或搜索表单中的输入 <input>/<select> 未参与搜索(因此没有属性“TF_colKey”),脚本将优雅地忽略它。以前,它会生成脚本错误
    • 将“TF_not_used”自定义属性重新引入到选项元素中。我显然在 v1.0 预发布中丢失了它 *DUH!*
  • 2001 年 8 月 16 日 - 版本 1.0c 发布

    • 修改了 _TF_trimWhitespace 以修剪开头部分
    • 修复了 _TF_filterTable 中的错误,该错误导致 AND 搜索组合无法正常工作
  • 2001 年 8 月 9 日 - 版本 1.0b 发布

    • 添加了 _TF_showAll 函数
    • 修改了 _TF_filterTable 以使用_TF_shouldShow 函数。
    • 添加了 TF_searchType 属性以定义搜索类型
    • 实现了“item”搜索
    • 添加了 _TF_shouldShow 函数
  • 2001 年 7 月 26 日 - 版本 1.0a 发布

    • 添加了 _TF_trimWhitespace 函数
    • 修改了 _TF_filterTable 单条件搜索,如果搜索字符串的最后一个字符是空格,则包含完整模式搜索
  • 2001 年 6 月 14 日 - 版本 1.0 首次发布

© . All rights reserved.