使用jQuery

时间:2019-06-12 17:16:51

标签: javascript jquery dom jquery-traversing

在以下示例中。我想为项目.invalid-feedback.valid-feedback找到第一个#main#secondary

很明显,我对通用案例很感兴趣,这就是我为jQuery编写原型扩展的原因。

$.fn.extend({
  closestNext: function (selector) {
    let found = null    
    let search = (el, selector) => {
      if (!el.length) return
      if (el.nextAll(selector).length) {
        found = el.nextAll(selector).first()
        return
      }
      search(el.parent(), selector)
    }

    search($(this), selector)
    return found
  }
})

// Proof
$('#main').closestNext('.invalid-feedback').text('main-invalid')
$('#secondary').closestNext('.invalid-feedback').text('secondary-invalid')
$('#main').closestNext('.valid-feedback').text('any-valid')
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
    <div>
        <input id="main"/>
    </div>
    <div class="dummy"></div>
    <div class="invalid-feedback"></div>
    <div>
        <input id="secondary"/>
    </div>
    <div class="invalid-feedback"></div>
</div>
<div class="valid-feedback"></div>

我写的内容似乎很复杂,我希望这种DOM遍历功能可以成为jQuery的一部分。不幸的是,我没有在手册中找到任何相关功能。

是否有一种更简单的方法来获得与closestNext相同的结果?

编辑

从更算法的角度来看,我正在寻找一种按以下顺序运行的树遍历函数,但其​​复杂性比我在示例中实现的要好。

.
├── A1
│   ├── B1
│   │   ├── C1
│   │   ├── C2
│   │   └── C3
│   ├── B2
│   │   ├── C4 <--- Entry point
│   │   ├── C5
│   │   └── C6
│   └── B3
│       ├── C7
│       ├── C8
│       └── C9
└── A2
    ├── B4 
    │   ├── C10
    │   └── C11
    └── B5
        ├── C12
        └── C13

C4入口点开始,探索顺序为:

>>> traverse(C4)
C5, C6, B3, C7, C8, C9, A2, B4, C10, C11, B5, C12, C13

4 个答案:

答案 0 :(得分:2)

我看不出您的初始代码如何更简单。毕竟,它需要迭代标记。

我确实看到了如何对其进行优化,使用return代替let found = null并只调用一次el.nextAll(selector)

我还解决了找不到该元素的情况,好像找不到一个异常。

堆栈片段

$.fn.extend({
  closestNext: function (selector) {
    let search = (el, selector) => {
      if (!el.length) return el
      let f = el.nextAll(selector)
      return f.length ? f.first() : search(el.parent(), selector)
    }
    return search($(this), selector)
  }
})

// Proof
$('#main').closestNext('.invalid-feedback').text('main-invalid')
$('#secondary').closestNext('.invalid-feedback').text('secondary-invalid')
$('#main').closestNext('.valid-feedback').text('any-valid')
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
    <div>
        <input id="main"/>
    </div>
    <div class="dummy"></div>
    <div class="invalid-feedback"></div>
    <div>
        <input id="secondary"/>
    </div>
    <div class="invalid-feedback"></div>
</div>
<div class="valid-feedback"></div>

答案 1 :(得分:-1)

我没有机会运行此命令(编辑:此后一直运行,并且已进行了更正),但这可以解决问题。我们有2个函数-第一个函数查找与我们要搜索的目标节点匹配的元素的同级。如果getSiblings不返回目标元素的匹配项,则第二个函数使球滚动并提升节点树。 希望对您有所帮助。.

[2019-06-12T18:58:33.696088 #9217]  WARN -- : LTI Authentication error: Invalid Signature

如您所见,该解决方案不需要您对DOM有任何深入的了解,而是有条不紊地搜索目标(除非找到目标,除非它停止运行)并继续提升,直到有效地用尽搜索为止。

答案 2 :(得分:-1)

不确定这是否完全可行,但我认为是这样,这取决于标记的复杂程度,但是即使那样,我仍然认为它将为您提供下一次出现的相对于元素的有效或无效反馈类有问题的是,因为您的ID是唯一的,并且匹配集中的索引+ 1应该是您要查找的。可能是矫kill过正,但它应该在DOM树中倒数第二个,不仅仅是兄弟姐妹,孩子等。我放入CSS更改以验证其作用。

$("#main, #secondary").on("click", function(e) {
  var invalid = $(this).add('.invalid-feedback');
  var valid = $(this).add('.valid-feedback');
  $(invalid.get(invalid.index( $(this)) +1)).css("background", "black");
  $(valid.get(valid.index( $(this)) +1)).css("background", "blue");
});

答案 3 :(得分:-1)

因此,这可行,但绝对不干净。我必须确保不包括“上一个”节点,所以我将它们过滤掉了...

我添加了更多测试用例,以证明它仅对“下一个”项目起作用。

我会采用您现有的解决方案。

$.fn.extend({
  closestNext: function(selector, originalMe) {
    const me = $(this);
    // try next first
    let nextSibling = me.next(selector);
    if (nextSibling.length) return nextSibling;
    // try descendents
    let descendents = me.find(selector).not((i, e) => (originalMe || me).prevAll().is(e));
    if (descendents.length) return descendents.first();
    // try next parent
    const parent = me.parent().not((i, e) => (originalMe || me).parent().prevAll().is(e));
    return parent.closestNext(selector, me);
  }
})

// Proof
$('#main').closestNext('.invalid-feedback').text('main-invalid')
$('#secondary').closestNext('.invalid-feedback').text('secondary-invalid')
$('#main').closestNext('.valid-feedback').text('any-valid')
.dummy {
  color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="valid-feedback dummy">should not change</div>
<div>
  <div class="invalid-feedback dummy">should not change</div>
  <div>
    <input id="main" />
  </div>
  <div class="dummy">should not change</div>
  <div class="invalid-feedback">should change</div>
  <div>
    <input id="secondary" />
  </div>
  <div class="invalid-feedback">should change</div>
</div>
<div class="valid-feedback">should change</div>