为什么使用最接近的逻辑不起作用? [英] Why does my logic, using closest, not work?

查看:52
本文介绍了为什么使用最接近的逻辑不起作用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

 $(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是如何产生误解最近操作()运行.如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的父级.由于主体是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中的其他结构中),它仍然会找到它.

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

I'm trying to reference a second element when my first element is clicked, but it is not working. I've tried a couple different ways, but neither work.

$(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>

解决方案

The root issue is a misunderstanding of how jQuery closest() operates. As specified in the API...

For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.

The important part related to our issue is "its ancestors". What does this mean? An ancestor, in relation to the DOM, is a(n indirect) parent of an element. For instance, lets look at the following example 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>

If we look at the paragraph tags we can see that they are surrounded (or "encapsulated") by a div tag. Formatting the paragraphs like this denotes them as a child of that div, thus that div is the parent of those paragraphs. The paragraphs, both belonging to the same div parent, are considered to be siblings.

Furthermore, the div tag is encapuslated by the body tag, so the body is the parent of the div. Since the body is the direct parent of the div, and the div is the direct parent of the paragraphs; that means the body is an indirect parent of the paragraphs.


So, now lets see how this relates to our problem. In the first event listener, we are trying to get the firstName label before the firstName input using closest('.firstName'). However, as we know now, closest only looks for direct or indirect parents. Referencing our HTML structure, is the label a parent of the input? No. It is a preceeding sibling.

What about the second attempt, trying to get the secondName label before the secondName input? That selector is using '.form-group .lastName', so it's looking for the parent form-group that has a child of lastName, right? So it should work?

No. The reason the second attempt fails is because the selector you give to closest is intended to match only the parent element. It does not perform any nesting traversals to see if the selector matches some element. It must match the parent. And since a single element cannot match a selector that includes a nesting, it will not find an element to perform your actions upon.


Now that we know the issues, how can we fix them? Well, lets look at the firstName one...

$(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>

In this particular case, we know that the label is the immediately preceeding sibling to the input. Given that fact, we could choose to use the jQuery prev() method to get the previous sibling to our element. In the example above, I gave it an optional selector to filter by, but it is not necessary in this case. Using prev(), we can grab the element before our input, which is the label, and then do whatever we want to it.

But, what if you wanted to use closest() in order to avoid the inheriently brittle positional based logic that prev() involves? We still could use it, by changing up our logic slightly.

$(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>

Now we have changed the closest to find the shared parent div to both the label and the input. Once we find the parent, we can then perform a find to get the nested label. Using this approach, it does not matter where the label is in the div, just so long as it is a child. So, using this logic if you had the label before the input today and some time in the future decided to move it (or maybe nest it in some other structure in the div) it would still find it.

This second approach also works for our lastName issue. Rather than trying to put the entire selector into the closest(), the closest becomes a lookup for the parent div, followed by a find() for the label.

这篇关于为什么使用最接近的逻辑不起作用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆