四、ASP.NET 中的 DOM 遍历和操作

本章将介绍用于遍历 DOM 树的方法以及可用于操作这些方法的技术。 我们将在本章中讨论以下配方:

  • 添加/移除 DOM 元素
  • 访问父控件和子控件
  • 访问兄弟控制
  • 使用过滤器细化选择
  • 在运行时向控件添加项

简介

文档对象模型(DOM)为 web 页面提供了一种树状格式的结构化文档的表示。 树中的每个节点都绑定到属性、方法和事件处理程序。 web 页面本身被称为document对象,可以使用window.documentwindow对象访问。 页面上的 HTML 元素成为元素节点,比如head元素或body元素。 这些节点又可以有子节点,如tabledivinput等等。 有些节点可能是文本节点,而有些节点也可能是注释节点。

需要注意的是,DOM 不是一种编程语言,而是一种可跨各种语言(如 JavaScript、HTML 和 XML)使用的面向对象模型。 因此,它是语言独立的,并且提供了一个通用的应用编程接口(API),可以由各种语言实现。 通过将网页连接到编程语言,你可以操纵它们的样式、结构和内容。

jQuery 提供了许多遍历 DOM 树的方法,比如访问父元素、子元素、兄弟元素或下一个/前一个元素。 使用 jQuery,可以在运行时使用客户机代码添加、删除或克隆 DOM 元素。 在本章中,我们将看到这是如何实现的。

添加/删除 DOM 元素

这个食谱演示了如何在 DOM 上克隆元素。 我们还将看到如何从 DOM 树中完全删除元素。 本例中使用的编程结构总结于下表:

|

构造

|

类型

|

描述

| | --- | --- | --- | | $("#identifier") | jQuery 选择器 | 这将根据元素的 ID 选择一个元素 | | $("html_tag") | jQuery 选择器 | 这将选择具有指定 HTML 标记的所有元素。 | | .addClass() | jQuery 方法 | 这会将指定的CSS类添加到每个匹配的元素中。 | | .attr("name").attr("name", "value") | jQuery 方法 | 这将返回一个字符串,其中包含第一个匹配元素所需的属性值。 它还可以用于将属性设置为所需的值。 | | [attribute= "value"] | jQuery 选择器 | 这将选择具有指定属性等于"value"字符串的元素。 | | .appendTo() | jQuery 方法 | 这将在目标的末尾插入元素。 | | click | jQuery 的事件 | 当您单击一个元素时,它就会触发。 它对应于 JavaScript 的click事件。 | | .clone() | jQuery 方法 | 这将对匹配的元素进行深度复制,也就是说,将复制匹配的元素及其子代和文本节点。 | | event.preventDefault() | jQuery 方法 | 这将防止触发事件的默认动作。 | | .find() | jQuery 方法 | 这将查找与筛选器匹配的所有元素。 | | .length | jQuery 的财产 | 这将返回 jQuery 对象中的元素数量。 | | .on() | jQuery 事件绑定 | 这将一个或多个事件的事件处理程序附加到匹配的元素。 | | .remove() | jQuery 方法 | 这将从文档中删除匹配的元素及其后代元素。 所有相关的数据和事件也将被删除。 | | .removeClass() | jQuery 方法 | 这将从每个匹配的元素中移除指定的 CSS 类。 | | .val() | jQuery 方法 | 返回第一个匹配元素的值,或者设置每个匹配元素的值。 |

准备

按照的步骤创建一个页面来显示添加和移除 DOM 元素:

  1. In this recipe, let's create a subsection of a job application form where the applicant needs to key in the current and past working experience. Since this is a variable section and different applicants can have different number of job experiences, we will let the user add new subsections if required. Once the page is loaded, the following form will be displayed:

    Getting ready

  2. When you click on the Add Work Experience link, a new subsection is added as follows:

    Getting ready

  3. When you click on the Remove Work Experience link, a prompt message is displayed to the user, as shown in the following screenshot:

    Getting ready

    通过单击取消,取消该操作。 通过点击OK,前一个小节将从表单中永久删除。

  4. 首先,创建一个新的ASP.NET Web 应用项目在 Visual Studio 中使用模板,并将其命名为Recipe1(或任何其他合适的名称)。

  5. 在项目中添加一个Scripts文件夹,并将 jQuery 库文件包含在该文件夹中。
  6. 添加一个新 web 表单,并在此表单中包含 jQuery 库。
  7. 添加两个表单字段:Company NameDesignation到表单中。 在这些字段下面拖放两个LinkButton控件:一个用于添加新的部分,另一个用于删除前面的部分。 另外,为窗体添加两个 Button 控件,分别用于SubmitReset功能。 因此,表单的标记如下:

    <div id="container"> <asp:Panel ID="pnlWorkExp" runat="server" CssClass="addPanel"> <table> <tr> <td> <asp:Label ID="lblCompany" runat="server" Text="Company Name:"></asp:Label> </td> <td> <asp:TextBox ID="txtCompany" runat="server"></asp:TextBox> </td> </tr> <tr> <td> <asp:Label ID="lblDesignation" runat="server" Text="Designation:"></asp:Label> </td> <td> <asp:TextBox ID="txtDesignation" runat="server"></asp:TextBox> </td> </tr> </table> </asp:Panel> </div> <asp:LinkButton ID="lnkAddWorkExp" runat="server">Add Work Experience</asp:LinkButton> &nbsp;&nbsp; <asp:LinkButton ID="lnkRemWorkExp" runat="server">Remove Work Experience</asp:LinkButton> <br /><br /> <asp:Button ID="btnSubmit" runat="server" Text="Submit" /> &nbsp;&nbsp; <asp:Button ID="btnReset" runat="server" Text="Reset" />

  8. 注意表单有一个容器 div 区域,由Panel控件的组成。 我们将克隆这个Panel每次点击添加工作经验链接。 添加以下样式到这个Panel:

  9. 我们还将在页面上的disabled控件中添加样式:

    .disabled{ color:gray; text-decoration:none; }

怎么做……

在窗体中添加以下 jQuery 代码到<script>块:

<script type="text/javascript">
$(document).ready(function() {
  $("#<%=lnkRemWorkExp.ClientID%>").attr("disabled", true).addClass("disabled");
  $("#<%=lnkAddWorkExp.ClientID%>").on("click", function(evt) {
    evt.preventDefault();
    var cnt = $(".addPanel").length + 1;
    var clone = $("#<%=pnlWorkExp.ClientID%>").clone();
    clone.attr("ID", "<%=pnlWorkExp.ClientID%>_" + cnt);
    clone.find("#<%=lblCompany.ClientID%>").attr("ID", "<%=lblCompany.ClientID%>_" + cnt);
    clone.find("#<%=txtCompany.ClientID%>").attr("ID", "<%=txtCompany.ClientID%>_" + cnt).attr("name", "<%=txtCompany.ClientID%>_" + cnt).val("");
    clone.find("#<%=lblDesignation.ClientID%>").attr("ID", "<%=lblDesignation.ClientID%>_" + cnt);
    clone.find("#<%=txtDesignation.ClientID%>").attr("ID", "<%=txtDesignation.ClientID%>_" + cnt).attr("name", "<%=txtDesignation.ClientID%>_" + cnt).val("");
    clone.appendTo("#container");
    $("#<%=lnkRemWorkExp.ClientID%>").attr("disabled", false).removeClass("disabled");
  });
  $("#<%=lnkRemWorkExp.ClientID%>").on("click", function(evt) {
    evt.preventDefault();
    var cnt = $(".addPanel").length;
    if (cnt > 1) {
      if (confirm("Are you sure you want to remove the above section?")) {
        $("#<%=pnlWorkExp.ClientID%>_" + cnt).remove();
        cnt--;
        if (cnt == 1)
          $("#<%=lnkRemWorkExp.ClientID%>").attr("disabled", false).addClass("disabled");
      }
    }
  });
  $("#<%=btnSubmit.ClientID%>").on("click", function(evt) {
    evt.preventDefault();
    //handle form submission using AJAX here
  });
  $("#<%=btnReset.ClientID%>").on("click", function(evt) {
    evt.preventDefault();
    $("input[type=text]").val("");
  });
});
</script>

How it works…

让我们看看如何添加和删除 DOM 元素:

  1. In the jQuery code, the Remove Work Experience link is initially disabled by setting its disabled attribute to true as follows:

    $("#<%=lnkRemWorkExp.ClientID%>").attr("disabled", true).addClass("disabled");

    因此,最初在页面加载时,链接是不可点击的。

  2. 事件处理程序附加到LinkButton控件以添加和删除子部分,以及Button控件以提交和重置表单:

    $("#<%=lnkAddWorkExp.ClientID%>").on("click", function (evt) {…}); $("#<%=lnkRemWorkExp.ClientID%>").on("click", function (evt) {…}); $("#<%=btnSubmit.ClientID%>").on("click", function (evt) {…}); $("#<%=btnReset.ClientID%>").on("click", function (evt) {…});

  3. In the event handler of the Add Work Experience link, we are going to make a deep copy of the Panel control using the .clone() function. We will need to update the ID, name, and value of each child control to avoid duplicates on the page. To get started with this, first prevent posting of the form due to the button click action:

    evt.preventDefault();

    因为我们需要为每个元素设置唯一的ID,所以让我们将每个克隆元素的ID设置为OriginalID_N,其中OriginalID等于被克隆元素的IDN等于原始元素的第 n 个实例。

    要确定N的值,首先确定表单上具有addPanelCSS 类的Panel控件的总数。 将该计数增加1以获得下一个实例的数目,如下所示:

    var cnt = $(".addPanel").length + 1;

    复制原始Panel控件:

    var clone = $("#<%=pnlWorkExp.ClientID%>").clone();

    将克隆PanelID更新为OriginalID_N:

    clone.attr("ID", "<%=pnlWorkExp.ClientID%>_" + cnt);

    现在,开始将其子元素的IDname更新为OriginalID_N。 如果在控件中输入了任何数据,也将复制该数据。 因此,重置克隆文本控件的数据,如下所示:

    clone.find("#<%=lblCompany.ClientID%>").attr("ID", "<%=lblCompany.ClientID%>_" + cnt); clone.find("#<%=txtCompany.ClientID%>").attr("ID", "<%=txtCompany.ClientID%>_" + cnt).attr("name", "<%=txtCompany.ClientID%>_" + cnt).val(""); clone.find("#<%=lblDesignation.ClientID%>").attr("ID", "<%=lblDesignation.ClientID%>_" + cnt); clone.find("#<%=txtDesignation.ClientID%>").attr("ID", "<%=txtDesignation.ClientID%>_" + cnt).attr("name", "<%=txtDesignation.ClientID%>_" + cnt).val("");

    现在,克隆的 Panel 已经准备好被添加到容器 div 区域:

    clone.appendTo("#container");

    通过将其disabled属性更新为false来启用移除工作经验链接:

    $("#<%=lnkRemWorkExp.ClientID%>").attr("disabled", false).removeClass("disabled");

  4. When you click on the Remove Work Experience link, we will remove the most recently added Panel from the form. To do this, first prevent posting of the form on the click event:

    evt.preventDefault();

    获取表格上最后添加的Panel编号,如下:

    var cnt = $(".addPanel").length;

    如果面板是原始元素,即表单上的第一个面板,它将不会被删除。 如果表单上有多个 Panel 控件,我们需要向用户显示确认对话框。 用户可以通过点击取消来关闭对话框。 如果用户单击OK,我们使用.remove()函数删除 Panel 及其子元素。

    由于 Panels 的数量减少了1,我们可以减少1的数量。 如果只剩下一个面板,禁用remove链接,避免移除原来的面板:

    if (cnt > 1) { if (confirm("Are you sure you want to remove the above section?")){ $("#<%=pnlWorkExp.ClientID%>_" + cnt).remove(); cnt--; if (cnt == 1) $("#<%=lnkRemWorkExp.ClientID%>").attr("disabled", false).addClass("disabled"); } }

    注意事项

    由于 DOM 元素是使用客户机代码添加的,所以服务器端无法访问这些元素。 因此,在Submit按钮的事件处理程序中,检索所有 DOM 元素的内容并使用AJAX将其发布到服务器。 在第 9 章的序列化表单数据配方中,有用的 jQuery 配方为 ASP.NET Sites,网址:https://www.packtpub.com/sites/default/files/downloads/4836OT_Chapter_09

  5. Reset按钮的事件处理程序中,阻止提交表单,并将所有文本控件的值重置如下:

    evt.preventDefault(); $("input[type=text]").val("");

参见 also

访问同级控件配方

访问父控件和子控件

这个配方演示了在对示例表单执行客户端验证时,如何访问 DOM 中的父元素和子元素。 本例中使用的结构总结如下:

|

构造

|

类型

|

描述

| | --- | --- | --- | | $("#identifier") | jQuery 选择器 | 这将基于其ID选择一个元素。 | | $("html_tag") | jQuery 选择器 | 这将选择具有指定 HTML 标记的所有元素 | | $(this) | jQuery 对象 | 它引用当前 jQuery 对象 | | .addClass() | jQuery 方法 | 这会将指定的CSS类添加到每个匹配的元素中 | | :checked | jQuery 选择器 | 这将选择选中的输入元素 | | .children() | jQuery 方法 | 这会返回匹配元素的直接后代元素 | | .each() | jQuery 方法 | 这将遍历匹配的元素,并为每个元素执行一个函数 | | event.preventDefault() | jQuery 方法 | 这将防止触发事件的默认动作 | | .find() | jQuery 方法 | 这将查找与筛选器匹配的所有元素 | | .length | jQuery 的财产 | 这将返回 jQuery 对象中的元素数量 | | .parent() | jQuery 方法 | 这将返回匹配元素的直接父元素 | | .prop(propertyName).prop(propertyName, value) | jQuery 方法 | 这会为第一个匹配的元素返回指定属性的值,或者为所有匹配的元素设置指定属性的值 | | .removeClass() | jQuery 方法 | 这将从每个匹配的元素中删除指定的 CSS 类 | | :selected | jQuery 选择器 | 这将检索选定的输入元素 | | .val() | jQuery 方法 | 返回第一个匹配元素的值,或者设置每个匹配元素的值 |

准备

下面是创建一个页面来演示访问父控件和子控件的步骤:

  1. We will be validating a form that registers interested volunteers with the school museum. The form consists of the following fields:

    Getting ready

    当您点击提交按钮时,按照以下规则对字段进行验证:

    • 所有的字段都是强制性的,也就是说,它们应该是非空的
    • 可用性字段应该至少选择了三个条目

    未通过验证的字段将用红色高亮显示,如下所示:

    Getting ready

  2. 为了创建这个表单,启动一个新的ASP.NET Web 应用在 Visual Studio 中使用空的模板并将其命名为Recipe2(或其他合适的名称)。

  3. 添加一个Scripts文件夹,并将 jQuery 库包含在此文件夹中。
  4. 创建一个 web 表单,并在表单中包含 jQuery 库。
  5. 将以下标记添加到页面:

    <table id="container"> <tr><td> <asp:Label ID="lblSalutation" runat="server" Text="Salutation:"></asp:Label></td> <td><asp:DropDownList ID="ddlSalutation" runat="server"> <asp:ListItem Text="---Please Select---" Value=""></asp:ListItem> <asp:ListItem Text="Mr" Value="Mr"></asp:ListItem> <asp:ListItem Text="Ms" Value="Ms"></asp:ListItem> <asp:ListItem Text="Mrs" Value="Mrs"></asp:ListItem> <asp:ListItem Text="Dr" Value="Dr"></asp:ListItem> <asp:ListItem Text="Prof" Value="Prof"></asp:ListItem> </asp:DropDownList> </td> </tr> <tr> <td> <asp:Label ID="lblName" runat="server" Text="Name:"></asp:Label> </td> <td> <asp:TextBox ID="txtName" runat="server"></asp:TextBox> </td> </tr> <tr> <td> <asp:Label ID="lblAffiliation" runat="server" Text="Type of Affiliation:"></asp:Label> </td> <td> <asp:RadioButtonList ID="rdlAffiliation" runat="server"> <asp:ListItem Text="Staff" Value="Staff"></asp:ListItem> <asp:ListItem Text="Student" Value="Student"></asp:ListItem> <asp:ListItem Text="Alumni" Value="Alumni"></asp:ListItem> </asp:RadioButtonList> </td> </tr> <tr> <td> <asp:Label ID="lblLanguages" runat="server" Text="Spoken Languages:"></asp:Label> </td> <td> <asp:CheckBoxList ID="chkLanguages" runat="server"> <asp:ListItem Text="English" Value="English"></asp:ListItem> <asp:ListItem Text="Chinese" Value="Chinese"></asp:ListItem> <asp:ListItem Text="Malay" Value="Malay"></asp:ListItem> <asp:ListItem Text="Tamil" Value="Tamil"></asp:ListItem> </asp:CheckBoxList> </td> </tr> <tr> <td> <asp:Label ID="lblAvailability" runat="server" Text="Availability (Select any 3):"></asp:Label> </td> <td> <asp:ListBox ID="lstAvailability" runat="server" SelectionMode="Multiple" Width="100%" Height="82px" > <asp:ListItem Text="Weekdays AM" Value="WeekdaysAM"></asp:ListItem> <asp:ListItem Text="Weekdays PM" Value="WeekdaysPM"></asp:ListItem> <asp:ListItem Text="Weekend AM" Value="WeekendAM"></asp:ListItem> <asp:ListItem Text="Weekend PM" Value="WeekendPM"></asp:ListItem> <asp:ListItem Text="Public Holidays" Value="PublicHolidays"></asp:ListItem> </asp:ListBox> </td> </tr> <tr> <td colspan="2"> <asp:Button ID="btnSubmit" runat="server" Text="Submit" /> <asp:Button ID="btnReset" runat="server" Text="Reset" /> </td> </tr> </table>

  6. 要显示无效控件的边框和背景色,请包含以下样式:

    .error{ border-style:solid; border-color:red; background-color:lightpink; }

  7. container表中添加以下样式,以便在两个控件之间提供足够的padding:

    ```

    container{

    padding:10px; } ```

怎么做……

将下面的 jQuery 代码添加到窗体的<script>块中:

<script type="text/javascript">
$(document).ready(function() {
  $("#<%=btnSubmit.ClientID%>").click(function(evt) {
    evt.preventDefault();
    //Salutation field
    if ($("#<%=ddlSalutation.ClientID%>").val() == "") $("#<%=ddlSalutation.ClientID%>").parent().addClass("error");
    else $("#<%=ddlSalutation.ClientID%>").parent().removeClass("error");
    //Name field
    if ($("#<%=txtName.ClientID%>").val() == "")
      $("#<%=txtName.ClientID%>").parent().addClass("error");
    else
      $("#<%=txtName.ClientID%>").parent().removeClass("error");
    //Affiliation field
    var rdlAffCount = $("#<%=rdlAffiliation.ClientID%>").find("input:checked").length;
    if (rdlAffCount == 0) $("#<%=rdlAffiliation.ClientID%>").parent().addClass("error");
    else $("#<%=rdlAffiliation.ClientID%>").parent().removeClass("error");
    //Languages field
    var chkLanguagesCount = $("#<%=chkLanguages.ClientID%>").find("input:checked").length;
    if (chkLanguagesCount == 0) $("#<%=chkLanguages.ClientID%>").parent().addClass("error");
    else $("#<%=chkLanguages.ClientID%>").parent().removeClass("error");
    //Availability field
    var lstAvailCount = $("#<%=lstAvailability.ClientID%>").children("option:selected").length;
    if (lstAvailCount != 3) $("#<%=lstAvailability.ClientID%>").parent().addClass("error");
    else $("#<%=lstAvailability.ClientID%>").parent().removeClass("error");
  });
  $("#<%=btnReset.ClientID%>").click(function(evt) {
    evt.preventDefault();
    //Salutation field
    $("#<%=ddlSalutation.ClientID%>").val("");
    $("#<%=ddlSalutation.ClientID%>").parent().removeClass("error");
    //Name field
    $("#<%=txtName.ClientID%>").val("");
    $("#<%=txtName.ClientID%>").parent().removeClass("error");
    //Affiliation field
    $("#<%=rdlAffiliation.ClientID%> input").each(function() {
      $(this).prop("checked", false);
    });
    $("#<%=rdlAffiliation.ClientID%>").parent().removeClass("error");
    //Languages field
    $("#<%=chkLanguages.ClientID%> input").each(function() {
      $(this).prop("checked", false);
    });
    $("#<%=chkLanguages.ClientID%>").parent().removeClass("error");
    //Availability field
    $("#<%=lstAvailability.ClientID%> option").each(function() {
      $(this).prop("selected", false);
    });
    $("#<%=lstAvailability.ClientID%>").parent().removeClass("error");
  });
});
</script>

How it works…

让我们看看如何访问父控件和子控件:

  1. 当您点击提交按钮时,页面将被阻止发送回服务器:

    evt.preventDefault();

  2. 接下来,从第一个控件DropDownList开始,一步一步地验证字段。 如果该控件中没有选择任何选项,则需要将其标记为无效。 为此,获取它的parent元素——即表格单元格容器,并通过添加errorCSS 样式突出显示它。 但是,如果该字段不是空的,那么应该从parent表格单元格中删除任何高亮显示:

    if ($("#<%=ddlSalutation.ClientID%>").val() == "") $("#<%=ddlSalutation.ClientID%>").parent().addClass("error" ); else $("#<%=ddlSalutation.ClientID%>").parent().removeClass("err or");

  3. 接下来,验证文本框字段。 如果字段为空,则获取其parent元素——即容器表单元格,并向其添加errorCSS 样式。 如果该字段不是空的,移除任何附加到它的高亮显示:

    if ($("#<%=txtName.ClientID%>").val() == "") $("#<%=txtName.ClientID%>").parent().addClass("error"); else $("#<%=txtName.ClientID%>").parent().removeClass("error");

  4. The third field on the form is the Affiliation field, which is defined as a RadioButtonList control. To determine whether any radio button is selected, we use the :checked selector:

    var rdlAffCount = $("#<%=rdlAffiliation.ClientID%>").find("input:checked").le ngth;

    注意,在运行时,RadioButtonList控件作为表元素呈现,而每个ListItem控件作为输入元素呈现,type = radio作为表行元素呈现,如下面的 HTML 源代码所示:

    How it works…

    因此,我们使用.find()函数搜索表的子代,以找到所需的输入元素。

    如果没有选择选项,将突出显示parent表单元格,表明它是一个无效字段。 否则,任何附加到单元格的高亮显示都可以删除:

    if (rdlAffCount == 0) $("#<%=rdlAffiliation.ClientID%>").parent().addClass("error "); else $("#<%=rdlAffiliation.ClientID%>").parent().removeClass("er ror");

  5. Next, we will validate the Spoken Languages field, which is defined as a CheckBoxList control. At runtime, the CheckBoxList control is rendered as a table element, and each ListItem control is rendered as an input element with type = checkbox in a table row element, as shown in the following HTML source:

    How it works…

    因此,我们再次使用.find()函数搜索表的所有子代,以确定输入元素,如下所示:

    var chkLanguagesCount = $("#<%=chkLanguages.ClientID%>").find("input:checked").length;

    如果没有选中复选框,则将字段标记为无效; 否则,标记为有效,如下所示:

    if (chkLanguagesCount == 0) $("#<%=chkLanguages.ClientID%>").parent().addClass("error"); else$("#<%=chkLanguages.ClientID%>").parent().removeClass("error");

  6. Lastly, we check the Availability field, which is defined as a ListBox control. Here, the condition for a successful validation is that at least three entries should be selected. So, first find out the total number of selected choices by filtering the options using the :selected selector:

    var lstAvailCount = $("#<%=lstAvailability.ClientID%>").children("option:select ed").length;

    注意,在运行时,ListBox控件作为select元素呈现,而每个ListItem控件作为option元素呈现,如下所示:

    How it works…

    使用.children()函数是因为option元素是select元素的直接后代,我们不需要遍历所有后代。

    如果所选选项的数量不等于3,则将该字段标记为无效; 否则,标记为有效如下:

    if (lstAvailCount != 3)$("#<%=lstAvailability.ClientID%>").parent().addClass("error"); else$("#<%=lstAvailability.ClientID%>").parent().removeClass("e rror");

  7. 当您点击Reset按钮时,我们需要清除输入到表单字段中的数据(如果有的话)。 同时,附加到任何表单元格的errorCSS 类也应该被删除。

  8. 当点击Reset按钮时,首先阻止表单发送到服务器:

    evt.preventDefault();

  9. 接下来,重置第一个DropDownList字段的值,并删除附加到它的任何错误样式:

    $("#<%=ddlSalutation.ClientID%>").val(""); $("#<%=ddlSalutation.ClientID%>").parent().removeClass("error");

  10. 接下来,对TextBox字段重复相同的过程:

    $("#<%=txtName.ClientID%>").val(""); $("#<%=txtName.ClientID%>").parent().removeClass("error");

  11. 对于RadioButtonListCheckBoxListListBox控件,循环遍历每个选项并重置选择(如果有的话)。 此外,删除错误样式(如果有):

参见 also

添加/删除 DOM 元素配方

访问同级控件

在前面的配方中,我们从 DOM 树中的一个元素向上和向下遍历。 在这个配方中,让我们遍历同一级别上的其他控件。 本例中使用的结构总结如下:

|

构造

|

类型

|

描述

| | --- | --- | --- | | $(".class") | jQuery 选择器 | 它匹配指定的CSS类中的所有元素 | | $("html_tag") | jQuery 选择器 | 这将选择具有指定 HTML 标记的所有元素 | | $(this) | jQuery 对象 | 它引用当前 jQuery 对象 | | .click() | jQuery 事件绑定 | 这将处理程序绑定到元素的单击事件 | | event.preventDefault() | jQuery 方法 | 这将防止触发事件的默认动作 | | .focus() | jQuery 事件绑定 | 这将触发元素的焦点事件或将事件处理程序绑定到焦点事件 | | .prop(propertyName).prop(propertyName, value) | jQuery 方法 | 这将为第一个匹配的元素返回指定属性的值,或者为所有匹配的元素设置指定属性的值 | | .siblings() | jQuery 方法 | 这将检索匹配元素的兄弟元素 | | .text() | jQuery 方法 | 这将返回每个匹配元素的组合文本内容,或者设置每个匹配元素的文本内容 |

准备

按照以下步骤构建访问同级控件的页面:

  1. To demonstrate how to access sibling controls, create the following content management interface to edit reports. All text sections are read-only and are provided with EDIT links for any updates required, as shown in the following screenshot:

    Getting ready

  2. When you click on any EDIT link, the corresponding sibling text field is made editable as follows:

    Getting ready

  3. 通过单击SAVE链接,文本字段再次变为只读。

  4. 要创建这个表单,启动一个新的ASP.NET Web 应用项目在 Visual Studio 中使用模板,并将其命名为Recipe3(或其他合适的名称)。
  5. 向项目中添加一个Scripts文件夹,并将 jQuery 库包含在此文件夹中。
  6. 添加一个新的 web 表单,并在表单中包含 jQuery 库。
  7. 对于表单中的每个文本字段,我们将在MultiLine模式下使用TextBox控件。 因此,将以下标记添加到.aspx页面。 控件的内容可以是任意的文本,如下所示:
  8. 为了区分只读模式和更新模式,在只读模式下,我们可以通过添加以下样式给TextBox控件一个背景色:

    .readtext{ background-color:powderblue; }

  9. 另外,在EDIT/SAVE链接和 section header 中添加以下样式:

    .edit { font-variant: small - caps; text-decoration: none; } .sectionHeader { font-size: 20 px; font-variant: small-caps; font-weight: 700; padding: 10 px; }

怎么做……

将下面的 jQuery 代码添加到窗体的<script>块中:

<script type="text/javascript">
$(document).ready(function() {
  $("textarea").prop("readonly", true).addClass("readtext");
  $(".edit").click(function(evt) {
    evt.preventDefault();
    var lnkText = $(this).text();
    if (lnkText == "Edit") {
      $(this).siblings("textarea").prop("readonly", false).removeClass("readtext").focus();
      $(this).text("Save");
    } else if (lnkText == "Save") {
      $(this).siblings("textarea").prop("readonly", true).addClass("readtext");
      $(this).text("Edit");
    }
  });
});
</script>

How it works…

让我们看看如何访问同级控件:

  1. Initially, when the page loads in the browser, all TextBox controls are made uneditable by setting their readonly property to true. At runtime, the TextBox controls in the MultiLine mode are rendered as textarea elements. Hence, we can use the .prop() method as follows:

    $("textarea").prop("readonly", true).addClass("readtext");

    注意事项

    前面添加的CSS类确保将背景色应用于TextBox控件。

  2. 所有的EDITLinkButton控件都绑定到一个editCSS 类上。 因此,我们可以使用 CSS 选择器为每个链接的click事件附加处理程序,如下所示:

    $(".edit").click(function (evt) {..});

  3. When you click on any of the preceding links, firstly, prevent page submission:

    evt.preventDefault();

    其次,获取链接的text。 这个text可以是EDIT或者SAVE,这取决于用户的操作:

    var lnkText = $(this).text();

  4. If the link text is EDIT, we use the .siblings() method to traverse through other elements on the same level until we come across a textarea element. Once the element is located, the following needs to be done:

    • textarea元素的readonly属性设置为false,即使该字段可编辑
    • 通过删除相应的样式来删除背景色
    • 将光标聚焦在字段上

    这可以通过在一条语句中链接这些方法来实现:

    ``` $(this).siblings("textarea").prop("readonly", false).removeClass("readtext").focus();

    ```

    最后,更新链接SAVEtext:

    $(this).text("Save");

  5. If you click on the SAVE link, the following needs to be done:

    • 将兄弟元素textareareadonly属性设置为true,即使该字段不可编辑
    • textarea元素添加背景色

    这可以通过以下语句中的方法链接来实现:

    $(this).siblings("textarea").prop("readonly", true).addClass("readtext");

    接下来,更新链接text以显示EDIT:

    $(this).text("Edit");

    注意事项

    注意,通过单击SAVE链接,您可能还需要执行一些服务器端操作,例如使用 AJAX 将内容保存到数据库或文件中。

还有更多的…

让我们使用浏览器窗口中的开发人员工具来查看活动textarea字段属性的变化。 开发工具可以如下启动:

  • 在 Internet Explorer 中,从主菜单进入Tools|F12 Developer Tools
  • 从主菜单,在 Firefox 开发人员去|切换调试器工具|(Ctrl +【显示】+转变我)* 在谷歌 Chrome,从主菜单,去更多的工具|开发工具(Ctrl+【T7 转变】+【显示】我*)*

****将所需的断点添加到 jQuery 脚本中,如下截图所示:

There's more…

逐步遍历代码,查看活动元素的readonly属性和背景颜色的变化。

参见 also

访问父控件和子控件配方

使用过滤器细化选择

jQuery 提供了一个有用的.filter()方法来使用selectorcustom函数过滤元素。 在此配方中,我们将使用此方法在客户端筛选GridView控件的行。 本例中使用的结构总结如下表:

|

构造

|

类型

|

描述

| | --- | --- | --- | | $(#identifier) | jQuery 选择器 | 这将基于其ID选择一个元素。 | | $(".class") | jQuery 选择器 | 它匹配指定 CSS 类的所有元素 | | $("html_tag") | jQuery 选择器 | 这将选择具有指定 HTML 标记的所有元素 | | $(this) | jQuery 对象 | 它引用当前 jQuery 对象 | | .click() | jQuery 事件绑定 | 这将处理程序绑定到元素的click事件 | | :eq(i) | jQuery 选择器 | 这将选择索引为i的所有元素。 | | event. preventDefault() | jQuery 方法 | 这将防止触发事件的默认动作 | | .filter() | jQuery 方法 | 返回匹配选择器或自定义函数的元素 | | .find() | jQuery 方法 | 这将查找与筛选器匹配的所有元素 | | :first-child | jQuery 选择器 | 这将选择父元素的第一个子元素 | | .hide() | jQuery 方法 | 这将隐藏匹配的元素 | | :not(selector) | jQuery 选择器 | 这将选择与指定选择器不匹配的元素 | | .show() | jQuery 方法 | 这会显示匹配的元素 | | .substring(startIndex, [endIndex]) | JavaScript 函数 | 它返回给定字符串的子字符串,从startIndexendIndex或到字符串的末尾 | | .text() | jQuery 方法 | 这将返回每个匹配元素的组合文本内容,或者设置每个匹配元素的文本内容 | | :visible | jQuery 选择器 | 这将选择可见的元素,即宽度或高度为> 0 的元素 |

准备

让我们构建一个页面来使用过滤器来细化选择:

  1. Let's create a web page with a GridView control that reads data from the Products table in the Northwind database. When you run the page, all records are retrieved and displayed, as shown here:

    Getting ready

  2. When you click on any letter from A to Z above the GridView control, the rows are filtered to show the product names that begin with the selected letter. For example, when you click on the letter R, the page will display all product names beginning with the letter R, as shown in the following screenshot:

    Getting ready

    如果没有以开头的产品名称,选择的字母没有,则会向用户显示提示信息,如下图所示:

    Getting ready

  3. 首先,创建一个新的ASP.NET Web 应用项目在 Visual Studio 中使用模板,并将其命名为Recipe4(或任何其他合适的名称)。

  4. 添加一个Scripts文件夹到项目中,包含 jQuery 库文件在此文件夹中。
  5. 创建一个新的 web 表单,并添加 jQuery 库到表单中。
  6. 转到工具箱|Data,将GridView控件拖放到窗体上。
  7. In the Design mode, mouse over the GridView control until a small arrow icon appears in the top-right corner of the screen. Click on the arrow to show the GridView Tasks menu, as shown here:

    Getting ready

  8. Select the option from the Choose Data Source field from the preceding menu. This will launch the Data Source Configuration Wizard, Select SQL Database from the available options, and click on OK to proceed:

    Getting ready

  9. On the next screen, add a connection to the Northwind database. This will launch the Configure the Select Statement screen, as shown in the following screenshot. Select the Products table, and choose few columns for display such as ProductID, ProductName, UnitPrice, and UnitsInStock. Click on Next to proceed. Test the query to complete the wizard.

    Getting ready

  10. To display a list of letters from A to Z for filtering the GridView control, we will use a Repeater control. Hence, drag and drop a Repeater control by navigating to Toolbox | Data. In the code-behind file, populate the Repeater control using DataTable as follows:

    对于 VB,代码如下:

    ``` Private Sub Repeater1_BindData() Dim dt As DataTable = New DataTable() dt.Columns.Add("Alphabet") Dim cnt As Integer

    For cnt = 65 To 90 Step 1 dt.Rows.Add(Chr(cnt)) Next

    dt.AcceptChanges() Repeater1.DataSource = dt Repeater1.DataBind() End Sub ```

    对于 c#,代码如下:

    ``` private void Repeater1_BindData() { DataTable dt = new DataTable(); dt.Columns.Add("Alphabet");

    for (int cnt= 65; cnt <= 90; ++cnt) dt.Rows.Add((char)cnt);

    dt.AcceptChanges(); Repeater1.DataSource = dt; Repeater1.DataBind(); } ```

    在前面的过程中,我们使用 ASCII 码来生成字母列表。 由于A的 ASCII 码为65Z的 ASCII 码为90,循环从65运行到90,从 ASCII 码生成所需的字符。 生成的字符存储在DataTable中的Alphabet列中。 此列将在 Repeater 标记中用于显示。

  11. To populate the Repeater control, call the preceding procedure on loading the page:

    对于 VB,代码如下:

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load Repeater1_BindData End Sub

    对于 c#,代码如下:

    protected void Page_Load(object sender, EventArgs e) { Repeater1_BindData(); }

  12. 设计模式下,在Repeater控件的<ItemTemplate>元素中,添加一个LinkButton控件以链接按钮的形式显示每个字母。

  13. 另外,向窗体添加一个Label控件。 当没有为特定筛选器检索记录时,将显示此Label
  14. .aspx页面的最终标记如下:

    <table> <tr> <td> <asp:Repeater ID="Repeater1" runat="server" > <ItemTemplate> <asp:LinkButton CssClass="filterLink" runat="server"><%#Eval("Alphabet") %></asp:LinkButton> </ItemTemplate> </asp:Repeater> </td> </tr> </table> <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="ProductID" DataSourceID="SqlDataSource1"> <Columns> <asp:BoundField DataField="ProductID" HeaderText="Product ID" InsertVisible="False" ReadOnly="True" SortExpression="ProductID" /> <asp:BoundField DataField="ProductName" HeaderText="Product Name" SortExpression="ProductName" /> <asp:BoundField DataField="UnitPrice" HeaderText="Unit Price" SortExpression="UnitPrice" /> <asp:BoundField DataField="UnitsInStock" HeaderText="Units In Stock" SortExpression="UnitsInStock" /> </Columns> </asp:GridView> <br /> <asp:Label ID="lblMessage" runat="server" Text="No records found" CssClass="message"></asp:Label>

  15. Add the following style to display information messages to the user:

    .message{ color:red; }

    下面的样式将给各自的元素填充:

    .filterLink{ padding:2px; } th,td{ padding:5px; }

怎么做……

将以下 jQuery 代码添加到窗体的<script>块中:

<script type="text/javascript">
$(document).ready(function () {
  $("#<%=lblMessage.ClientID%>").hide();
  $(".filterLink").click(function (evt) {
    evt.preventDefault();
    var filterLetter = $(this).text();
    $("#<%=GridView1.ClientID%> tr:not(:first-child)").hide().filter(function () {
      if ($(this).find("td:eq(1)").text().substring(0, 1) == filterLetter)
      return this;
      }).show();
    if (($("#<%=GridView1.ClientID%> tr:visible").length - 1) == 0)
    $("#<%=lblMessage.ClientID%>").show();
    else
    $("#<%=lblMessage.ClientID%>").hide();
  });
});
</script>

How it works…

下面的步骤显示了使用过滤器细化选择:

  1. 当页面在浏览器中启动时,最初,用于向用户显示信息消息的Label控件是隐藏的:

    $("#<%=lblMessage.ClientID%>").hide();

  2. GridView控件上面的AZ的每个字母被分配一个filterLinkCSS 类。 使用 CSS 选择器将事件处理程序附加到这些链接的click事件,如下所示:

  3. If you click on any of the preceding links, the page will be prevented from posting back, as follows:

    evt.preventDefault();

    接下来,检索被单击的字母。 这可以通过检索text link来实现:

    var filterLetter = $(this).text();

    若要只返回产品名称以所单击字母开头的行,请使用tr:not(:first-child)选择器选择除标题行以外的所有行。 这些行最初是隐藏的:

    $("#<%=GridView1.ClientID%> tr:not(:first-child)").hide()

    接下来,应用filter()方法。 读取td:eq(1)产品名称单元格,并比较其字符是否以单击的字母开头:

    .filter(function () { if ($(this).find("td:eq(1)").text().substring(0, 1) == filterLetter) return this; })

    只有满足.filter()方法的行才会返回并显示:

    .show();

  4. 接下来,如果从筛选中没有检索到行,则显示信息消息,我们使用:visible筛选器检查可见的行数。 如果只有标题行可见,我们可以显示消息来通知用户没有返回行:

    if (($("#<%=GridView1.ClientID%> tr:visible").length - 1) == 0) $("#<%=lblMessage.ClientID%>").show(); Otherwise, the message is hidden: else $("#<%=lblMessage.ClientID%>").hide();

还有更多的…

.children()方法是.find()方法的替代方法。 这两个方法之间的区别在于.children()方法只沿着 DOM 树向下移动了一层。 由于td元素是tr元素的直接后代,让我们看看<script>块中的以下语句:

if ($(this).find("td:eq(1)").text().substring(0, 1) == filterLetter)

可以使用children()方法修改如下:

if ($(this).children("td:eq(1)").text().substring(0, 1) == filterLetter)

参见 also

添加/删除 DOM 元素配方

在运行时向控件添加项

在本教程中,我们将使用 jQuery 向不同的 ASP 中添加项目.NET 控件,如DropDownListListBoxBulletedList在运行时。 本例中使用的结构总结如下:

|

构造

|

类型

|

描述

| | --- | --- | --- | | $("#identifier") | jQuery 选择器 | 它使用其ID来选择一个元素。 | | $.map() | jQuery 函数 | 这将数组或对象转换为另一个数组 | | .append() | jQuery 方法 | 这将在每个匹配元素的末尾插入内容 | | .click() | jQuery 事件绑定 | 这将处理程序绑定到元素的click事件 | | event.preventDefault() | JavaScript 函数 | 这将防止触发事件的默认动作 | | .focus() | jQuery 事件绑定 | 这将触发元素的焦点事件或将事件处理程序绑定到焦点事件 | | .prepend() | jQuery 方法 | 这将在每个匹配元素的开头插入内容 | | .split() | JavaScript 函数 | 这将使用指定的字符作为分隔符将字符串拆分为子字符串 | | .trim() | JavaScript 函数 | 这将从字符串的开头和结尾删除一个空格 | | .val() | jQuery 方法 | 返回第一个匹配元素的值,或者设置每个匹配元素的值 |

准备

让我们构建一个页面,在运行时向控件添加项:

  1. In this recipe, let's create a web page with different types of controls to which items will be added at runtime. We will also provide a textbox field where the user can enter the items that need to be added.

    Getting ready

    让我们假设用户需要向控件添加多个项。 这可以通过输入用逗号分隔的项目来完成,如下面的截图所示:

    Getting ready

  2. When you click on the Add Items button, the new items are reflected in the controls, as shown in the following screenshot:

    Getting ready

  3. 让我们通过创建一个新的ASP 来开始.NET Web 应用项目在 Visual Studio 中使用空的模板,并将其命名为Recipe5(或其他合适的名称)。

  4. 在项目中创建一个Scripts文件夹,并将 jQuery 库添加到该文件夹中。
  5. 创建一个新的 web 表单,并在表单中包含 jQuery 库。
  6. 在窗体上拖放所需的控件,以在页面上创建以下标记:

    <div> <asp:Label ID="lblDescription" runat="server" Text="Key in the items to add in the text field below. To add more than one item, separate by comma."></asp:Label> <br /><br /> <asp:TextBox ID="txtAddItem" runat="server"></asp:TextBox> <asp:Button ID="btnAdd" runat="server" Text="Add Items" /> <br /> <p class="sectionHeader">ListBox control</p> <asp:ListBox ID="lstBox" runat="server" Width="200px"> <asp:ListItem Text="First Item" Value="First Item"></asp:ListItem> </asp:ListBox> <br /> <p class="sectionHeader">DropDownList control</p> <asp:DropDownList ID="ddlList" runat="server" Width="200px"> <asp:ListItem Text="First Item" Value="First Item"></asp:ListItem> </asp:DropDownList> <br /> <p class="sectionHeader">BulletedList control</p> <asp:BulletedList ID="lstList" runat="server"> <asp:ListItem Text="First Item" Value="First Item"></asp:ListItem> </asp:BulletedList> </div>

  7. 添加一些样式到节标题:

    .sectionHeader{ font-size:20px; font-variant:small-caps; font-weight:700; }

怎么做……

将以下 jQuery 代码添加到窗体的<script>块中:

<script type="text/javascript">
$(document).ready(function() {
  $("#<%=txtAddItem.ClientID%>").focus();
  $("#<%=btnAdd.ClientID%>").click(function(evt) {
    evt.preventDefault();
    var addItemText = $("#<%=txtAddItem.ClientID%>").val().trim();
    if (addItemText != "") {
      var arrString = addItemText.split(",");
      $("#<%=lstBox.ClientID%>").prepend(
        $.map(arrString, function(v) {
          return $("<option value=" + v.trim() + ">" + v.trim() + "</option>");
        }));
      $("#<%=ddlList.ClientID%>").append(
        $.map(arrString, function(v) {
          return $("<option>").val(v.trim()).text(v.trim());
        }));
      $("#<%=lstList.ClientID%>").append(
        $.map(arrString, function(v) {
          return $("<li>" + v.trim() + "</li>");
        }));
    }
    $("#<%=txtAddItem.ClientID%>").val("").focus();
  });
});
</script>

How it works…

下面的是在运行时向控件添加项的步骤:

  1. 在浏览器中加载页面时,通过使用.focus()函数将光标聚焦在文本字段中:

    $("#<%=txtAddItem.ClientID%>").focus();

  2. 事件处理程序被附加到Add Items按钮的click事件:

    $("#<%=btnAdd.ClientID%>").click(function (evt) {…});

  3. 如果单击前面的按钮,第一个任务是防止将页面发布到服务器:

    evt.preventDefault();

  4. 接下来,检索文本字段的内容和trim以删除空白:

    var addItemText = $("#<%=txtAddItem.ClientID%>").val().trim();

  5. Check whether the content of the preceding field is empty:

    if (addItemText != "")

    如果它不为空,通过使用逗号作为分隔符来分割字符串,从输入的文本构建一个数组:

    var arrString = addItemText.split(",");

    注意事项

    如果字符串中没有逗号,则数组将由单个元素组成。

  6. 现在,使用.map()函数将该数组转换为包含<option>元素的列表,以便<option>元素的文本和值都等于该下标处的数组元素。

  7. option元素列表前置到ListBox控件,即新元素将作为ListBox控件中的起始元素出现:

    $("#<%=lstBox.ClientID%>").prepend($.map(arrString, function (v) { return $("<option value=" + v.trim() + ">" + v.trim() + "</option>"); }));

  8. 同样的option元素列表也可以添加到DropDownList控件中。 当使用.append()函数时,新项目将出现在列表的末尾:

    $("#<%=ddlList.ClientID%>").append($.map(arrString, function (v) { return $("<option>").val(v.trim()).text(v.trim()); }));

  9. 为了向BulletedList控件添加项目,我们使用.map()函数来构建一个包含<li>元素的列表,因为在运行时,BulletedList控件将每个ListItem控件呈现为<li>元素。 所以,增加的项目如下:

    $("#<%=lstList.ClientID%>").append($.map(arrString, function(v){ return $("<li>" + v.trim() + "</li>"); }));

  10. 最后,在向前面的控件添加元素之后,清除文本字段并将光标聚焦于该字段,以便准备接受下一组输入:

    $("#<%=txtAddItem.ClientID%>").val("").focus();

参见 also

添加/删除 DOM 元素配方****