【问题标题】:How to implement "prevUntil" in Vanilla JavaScript without libraries?如何在没有库的 Vanilla JavaScript 中实现“prevUntil”?
【发布时间】:2011-09-08 20:35:54
【问题描述】:

我需要在 Vanilla JavaScript 中实现 jQuery 的 prevUntil() 方法的功能。

我在同一级别上有几个 <div> 元素:

<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>

我正在尝试使用onclick 事件来查找event.targetpreviousSiblings直到达到某个条件(例如,类名匹配)然后停止。

我如何做到这一点?

【问题讨论】:

  • @glowcoder:我个人觉得了解 jQuery 实际 在做什么 很有趣。
  • @pimvdb, jQuery 是开源的,如果您对它实际在做什么感兴趣,请不要犹豫查阅它的源代码,最重要的是 如何 它是如何做到的.
  • @Darin Dimitrov:我知道,我的意思是询问幕后发生的事情并没有错。
  • @pimvdb,不,当然没有错。
  • 我不能在运行这个的环境中使用 jQuery。

标签: javascript dom siblings


【解决方案1】:

此答案先前已在 here 发布以回应类似问题。

有几种方法可以做到。

以下任何一种都可以解决问题。

// METHOD A (ARRAY.FILTER, STRING.INDEXOF)
var siblings = function(node, children) {
    siblingList = children.filter(function(val) {
        return [node].indexOf(val) != -1;
    });
    return siblingList;
}

// METHOD B (FOR LOOP, IF STATEMENT, ARRAY.PUSH)
var siblings = function(node, children) {
    var siblingList = [];
    for (var n = children.length - 1; n >= 0; n--) {
        if (children[n] != node) {
            siblingList.push(children[n]);
        }  
    }
    return siblingList;
}

// METHOD C (STRING.INDEXOF, ARRAY.SPLICE)
var siblings = function(node, children) {
   siblingList = children;
   index = siblingList.indexOf(node);
   if(index != -1) {
       siblingList.splice(index, 1);
   }
   return siblingList;
}

仅供参考:jQuery 代码库是观察 A 级 Javascript 的绝佳资源。

这是一个出色的工具,它以非常精简的方式展示了 jQuery 代码库。 http://james.padolsey.com/jquery/

【讨论】:

    【解决方案2】:

    Example 使用 previousElementSibling:

        var className = "needle";
        var element = clickedElement;
        while(element.previousElementSibling && element.previousElementSibling.className != className) {
           element = element.previousElementSibling;
        }
        element.previousElementSibling; // the element or null
    

    【讨论】:

    • 这个element.previousSibling.className 有问题。如果之前的兄弟姐妹没有所需的类,element.previousSibling 最终将返回null,因此element.previousSibling.className 将抛出错误。
    • 那是为了防止死循环!只是在开玩笑。我已经更新了
    • 谢谢你,名字很长的人。
    【解决方案3】:

    .children.parentNode 结合使用。然后过滤NodeList,转换成数组后:http://jsfiddle.net/pimvdb/DYSAm/

    var div = document.getElementsByTagName('div')[0];
    var siblings = [].slice.call(div.parentNode.children) // convert to array
                     .filter(function(v) { return v !== div }); // remove element itself
    console.log(siblings);
    

    【讨论】:

    • NodeList 使用[].slice.call( nl ) 进行数组转换?不错:)
    【解决方案4】:

    这个怎么样:

    while ( node = node.previousElementSibling ) {
        if ( ( ' ' + node.className + ' ' ).indexOf( 'foo' ) !== -1 ) {
            // found; do your thing
            break;
        }
    }
    

    不要告诉我这在 IE8 中不起作用...

    【讨论】:

    • 你愿意被骗吗?因为我不会欺骗你,所以我不能回答你的问题,因为你让我不要。
    • @Wayne 不,我不喜欢被欺骗。我没有要求你不要回答我的问题。请回答!我问了什么?我以为我回答了一个问题,而不是问了一个问题。
    • 对不起,我的误解。我以为你别告诉我它在 IE8 中不起作用......不是你已经知道的。
    【解决方案5】:

    看看how jQuery does it

    prevUntil: function( elem, i, until ) {
        return jQuery.dir( elem, "previousSibling", until );
    },
    

    其中使用了一个名为 dir() 的 while / 循环函数。 prevUntil 一直持续到 previousSiblinguntil 元素相同。

    dir: function( elem, dir, until ) {
        var matched = [],
            cur = elem[ dir ];
    
        while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
            if ( cur.nodeType === 1 ) {
                matched.push( cur );
            }
            cur = cur[dir];
        }
        return matched;
    },
    

    【讨论】:

      【解决方案6】:

      HTML DOM 中有一个 previousSibling 属性

      这里有一些参考

      http://reference.sitepoint.com/javascript/Node/previousSibling

      【讨论】:

      • 属性previousSibling是对DOM节点的引用,而不是函数。
      • 我完全理解。但是通过一些简单的迭代,您可以使用它来找到与他的条件匹配的前一个元素。
      【解决方案7】:

      您可以使用indexOf 来确定兄弟元素的索引是否小于目标元素的索引:

      // jshint esversion: 9
      
      // get the target node
      const node = document.querySelector("div:nth-child(3)");
      
      // get the target node's index
      const node_index = node.parentNode.indexOf(node);
      
      // get the siblings of the target node
      const siblings = node => [...node.parentNode.children].filter(child => 
        child !== node
      );
      console.log(siblings);
      
      // get the prevUntil
      const class_name = "\bmy_class\b";
      const prevUntil = siblings.filter((sibling, i) =>
        i < node_index && (sibling.getAttribute("class") || "").includes(class_name)
      );
      console.log(prevUntil);
      

      祝你好运。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-12-13
        • 2018-07-17
        • 1970-01-01
        • 2020-10-16
        • 2014-09-24
        • 1970-01-01
        相关资源
        最近更新 更多