如何使用jquery遍历dom中两个已知元素之间的元素?

时间:2009-09-06 12:44:16

标签: jquery dom traversal

我想让用户点击一个起点,然后点击一个结束点,并能够操纵所选择的两个点之间的各种表单元素。

该页面是一个包含大量行的表,每行包含操作/保存该行中问题答案的相关信息。每行都有一个隐藏的值输入,以及是/否单选按钮,主要用于非熟练用户。带有问题的TD单元允许用户在是,否,空之间单击或切换。所以基本上我把页面上的单选按钮留下来显示是/否并使用隐藏字段来存储值(1,0,-1)

这是我在单击问题单元格时设置答案的方法。

    $(".question").bind("click dblclick", function(e) {

        var newClassName = "AnswerUnknown";

        var hiddenAnswerId = $(this).attr('id').replace("question", "answer");

        var answer = parseInt($("#" + hiddenAnswerId).val());

        var newValue;

        switch (answer) {
            case -1:
                newClassName = "AnswerCorrect";
                newValue = 1;
                $("#" + $(this).attr('id').replace("answer", "radioYes")).attr('checked', 'checked');
                $("#" + $(this).attr('id').replace("answer", "radioNo")).attr('checked', '');
                break;
            case 1:
                newClassName = "AnswerWrong";
                newValue = 0;
                $("#" + $(this).attr('id').replace("answer", "radioYes")).attr('checked', '');
                $("#" + $(this).attr('id').replace("answer", "radioNo")).attr('checked', 'checked');
                break;
            default:
                newClassName = "AnswerEmpty";
                newValue = -1;
                $("#" + $(this).attr('id').replace("answer", "radioYes")).attr('checked', '');
                $("#" + $(this).attr('id').replace("answer", "radioNo")).attr('checked', '');
        }
        $("#" + hiddenAnswerId).val(newValue);
        $(this).removeClass().addClass(newClassName);
    });

现在我想让用户点击一个起点并让该答案将所有以下问题填充到他们点击第二个项目的任何地方。可能是10个问题,或20个问题,这是一个未知的变量。可能有一个页面上有130个问题,连续20个问​​题可能是“是”。如上所述,每行都有一个“问题”单元格,之前的单元格是项目单元格。

我知道如何根据绑定到下面列出的click / dblclick事件的jquery选择器/函数设置起始元素和结束元素。

我不确定的是如何遍历dom或选择我需要在页面上两个选定点之间操作的所有元素。

    var StartItem;
    var EndItem;

    $(".item").bind("click dblclick", function(e) {

        var StartClassName = "AnswerUnknown";
        var EndClassName = "AnswerUnknown";
        var StartAnswerId;
        var EndAnswerId;
        var StartAnswer;

        if (StartItem === undefined) {
            StartItem = this;
            StartAnswerId = $(this).attr('id').replace("item", "rs");
            StartAnswer = parseInt($("#" + StartAnswerId).val());
        }
        else {
            if (EndItem === undefined) {
                EndItem = this;
                EndAnswerId = $(this).attr('id').replace("item", "rs");
                EndAnswer = parseInt($("#" + EndAnswerId).val());
            }
        }


        if (StartItem == this) {
            $(this).removeClass().addClass(StartClassName);
        }

        if (EndItem == this) {
            $(this).removeClass().addClass(EndClassName);
        }
    });

3 个答案:

答案 0 :(得分:2)

恕我直言的最佳方式是做下面的事情。您可以使用类名“item”循环遍历元素集合,当您找到start元素时,您可以开始执行您描述的处理。既然你有'这个',你就可以把这个id带到你在question.click函数中做的事情。

        var counter = 0;

    // This will loop over each element with classname "item", so make sure you take that into account
            $('.item').each(function(i) {
        // function returns this, but you can see what index your on with 'i'
                if (this == StartItem) {
                    // You can start processing rows
                    counter = 1;
                }
                else {
                    if (counter > 0) {
                        // Process rows/items after the first item above
                        counter = counter + 1;
                    }
                }
                if (this == EndItem) {
                    counter = 0
                    // Finish up processing if any
                    //Break out of each;
                }

            });

答案 1 :(得分:0)

听起来最简单的方法是将起始类添加到起始元素,将结束类添加到结束元素。然后,当在开始和结束之间遍历元素时,您可以检查开始或结束类名称并执行/阻止适当的操作。

修改

像这个插件这样的东西会做到这一点。该插件假定定义范围边界的两个元素具有相同的父元素并且具有相同的元素类型(nodeName)。您可以使用自己的开始和结束类名称,或者只使用默认的“开始”和“结束”。

(function($) {

  $.fn.rangeSelector = function(options) {   

    var settings = $.extend({ startClass : 'start', endClass: 'end'},options||{}); 
    var name = this[0].nodeName.split(':'); 
    name = name[name.length -1];
    var startIndex = $(name + '.' + settings.startClass).prevAll().length;
    var endIndex = $(name + '.' + settings.endClass).prevAll().length + 1;
    return this.slice(startIndex,endIndex);
  }

})(jQuery);

然后你可以这样使用

/*
 * will get all textboxes between textboxes 
 * with className start and end, inclusive
 */
$('input:text').rangeSelector();

这是 Working Demo 。如果要查看代码,请将 / edit 添加到URL的末尾。我正在考虑编写一个实用程序来返回一个基于startClass,endClass和元素类型参数的jQuery对象来包含,但这对你所需要的东西来说太过分了。

编辑2:

根据你的评论,我可以通过它来谈谈你

  1. 获取一个包含有问题元素的jQuery对象,在你的情况下我认为是文本输入,所以它就像$('parent > input:text'),其中parent是父元素(传入输入:文本本身如果在父元素之外的页面中有其他文本输入,因为插件依赖于索引),将无法正常工作。

  2. 如果需要,您可以将options对象传递给具有不同开始和结束类名称的rangeSelector(例如.rangeSelector({ start: "myStartClass", end: "myEndClass"}),或者只使用默认的startend在哪种情况下,您不需要传递任何对象。

  3. 设置变量将默认值(定义为对象的属性)与传入的选项对象的属性(如果未定义选项对象,则没有属性的对象)合并。

  4. 计算我们在jQuery对象中处理的元素的类型,并存储在name变量中。这是通过将jQuery对象中第一个元素的nodeName字符串拆分为数组并将名称分配给数组中最后一个字符串项的值来完成的。

  5. 计算标有startend类名的项的开始和结束索引。在这种情况下,索引是指元素在其父元素中的基于0的位置。

  6. 只返回jQuery对象中起始和结束索引(包括)之间的那些元素作为jQuery对象(以便可以链接更多的jQuery命令)。这使用slice()命令,该命令在jQuery对象上的功能与Array.slice()在数组上的功能相同。

答案 2 :(得分:0)

问题有点旧,但这是我用于项目的解决方案:

jQuery选择器

(function ($) {
    $.fn.between = function (elm0, elm1) {
        var index0 = $(this).index(elm0);
        var index1 = $(this).index(elm1);

        if (index0 <= index1)
            return this.slice(index0, index1 + 1);
        else
            return this.slice(index1, index0 + 1);
    }
})(jQuery);

用法

$('body').between($('#someid'), $('#someid2')).each(function () {
    // Do what you want.
});