【问题标题】:Why does my logic, using closest, not work?为什么我的逻辑,使用最接近,不起作用?
【发布时间】:2019-04-09 18:26:07
【问题描述】:

我试图在单击第一个元素时引用第二个元素,但它不起作用。我尝试了几种不同的方法,但都不起作用。

$(function(){
  $('#firstName').on('blur', function(e){
    // I tried to get the closest first name to the input
    var $firstNameLabel = $(e.target).closest('.firstName');
    
    if (e.target.value.trim() === '') {
      $firstNameLabel.addClass('error');
    } else {
      $firstNameLabel.removeClass('error');
    }
  });

  $('#lastName').on('blur', function(e){
    // I also tried to use the parent get the closest last name to the input
    var $lastNameLabel = $(e.target).closest('.form-group .lastName');
    
    if (e.target.value.trim() === '') {
      $lastNameLabel.addClass('error');
    } else {
      $lastNameLabel.removeClass('error');
    }
  });
});
.form-group label { display: inline-block; min-width: 80px; }
.error { color: rgb(240, 0, 0); }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="form-group">
  <label for="firstName" class="firstName">First Name:</label>
  <input type="text" name="firstName" value="" id="firstName">
</div>

<div class="form-group">
  <label for="lastName" class="lastName">Last Name:</label>
  <input type="text" name="lastName" value="" id="lastName">
</div>

【问题讨论】:

    标签: jquery


    【解决方案1】:

    根本问题是对jQuery closest() 运作方式的误解。正如 API 中指定的...

    对于集合中的每个元素,通过测试元素本身并向上遍历其在 DOM 树中的祖先来获取与选择器匹配的第一个元素。

    与我们的问题相关的重要部分是“它的祖先”。这是什么意思?与 DOM 相关的 祖先 是元素的(n 间接)父元素。例如,让我们看看下面的 HTML 示例...

    <html>
        <head>
        </head>
        <body>
            <div id="header">
                Welcome to my Site!
            </div>
            <div id="content">
                <p>Hope you like it!</p>
                <p>More to come later!</p>
            </div>
        </body>
    </html>
    

    如果我们查看段落标签,我们可以看到它们被 div 标签包围(或“封装”)。像这样格式化段落表示它们是该 div 的子级,因此该 div 是这些段落的父级。都属于同一个 div 父级的段落被视为兄弟姐妹

    另外,div标签被body标签封装,所以body就是div的父级。由于 body 是 div 的直接父级,而 div 是段落的直接父级;这意味着正文是段落的间接父级。


    那么,现在让我们看看这与我们的问题有何关系。在第一个事件监听器中,我们尝试使用closest('.firstName') 在 firstName 输入之前获取 firstName 标签。然而,正如我们现在所知,closest 只寻找直接或间接的父母。参考我们的 HTML 结构,标签是输入的父级吗?不,它是前面的兄弟姐妹

    第二次尝试如何,试图在 secondName 输入之前获取 secondName 标签?那个选择器正在使用'.form-group .lastName',所以它正在寻找有lastName 的孩子的父form-group,对吗?那么它应该可以工作吗?

    没有。第二次尝试失败的原因是您提供给 closest 的选择器旨在匹配 only 父元素。它不执行任何嵌套遍历来查看选择器是否匹配 some 元素。它必须与父级匹配。而且由于单个元素无法匹配包含嵌套的选择器,因此它不会找到执行操作的元素。


    既然我们知道了这些问题,我们该如何解决它们?好吧,让我们看看第一个...

    $(function(){
      $('#firstName').on('blur', function(e){
        var $firstNameLabel = $(e.target).prev('.firstName');
        
        if (e.target.value.trim() === '') {
          $firstNameLabel.addClass('error');
        } else {
          $firstNameLabel.removeClass('error');
        }
      });
    });
    .form-group label { display: inline-block; min-width: 80px; }
    .error { color: rgb(240, 0, 0); }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <div class="form-group">
      <label for="firstName" class="firstName">First Name:</label>
      <input type="text" name="firstName" value="" id="firstName">
    </div>

    在这种特殊情况下,我们知道标签是输入的紧接在前的兄弟。鉴于这一事实,我们可以选择使用jQuery prev() 方法来获取我们元素的前一个兄弟。在上面的示例中,我给了它一个可选的选择器来过滤,但在这种情况下不是必需的。使用prev(),我们可以获取输入之前的元素,也就是标签,然后对它做任何我们想做的事情。

    但是,如果您想使用closest() 来避免prev() 涉及的固有脆弱的基于位置的逻辑怎么办?通过稍微改变我们的逻辑,我们仍然可以使用它。

    $(function(){
      $('#firstName').on('blur', function(e){
        var $firstNameLabel = $(e.target).closest('.form-group').find('.firstName');
        
        if (e.target.value.trim() === '') {
          $firstNameLabel.addClass('error');
        } else {
          $firstNameLabel.removeClass('error');
        }
      });
    });
    .form-group label { display: inline-block; min-width: 80px; }
    .error { color: rgb(240, 0, 0); }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <div class="form-group">
      <label for="firstName" class="firstName">First Name:</label>
      <input type="text" name="firstName" value="" id="firstName">
    </div>

    现在我们已经更改了最接近标签和输入的共享父 div。一旦找到父节点,我们就可以执行查找以获取嵌套标签。使用这种方法,标签在 div 中的位置无关紧要,只要它是一个孩子。因此,如果您在今天输入之前有标签并且在未来某个时间决定移动它(或者可能将其嵌套在 div 中的其他结构中),使用此逻辑它仍然会找到它。

    第二种方法也适用于我们的姓氏问题。与其尝试将整个选择器放入 closest(),不如将​​最接近的选择器变成父 div 的查找,然后是标签的 find()

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-10-01
      • 2022-01-07
      • 2013-02-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多