当我单击第一个元素时,我试图引用第二个元素,但是它不起作用。我尝试了几种不同的方法,但是都没有用。
$(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>
答案 0 :(得分: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的父代。由于主体是div的直接父级,而div是段落的直接父级;这意味着正文是段落的间接父级。
因此,现在让我们看一下这与我们的问题有何关系。在第一个事件侦听器中,我们尝试使用closest('.firstName')
在firstName输入之前获取firstName标签。但是,正如我们现在所知道的,closest
仅查找直接或间接父母。引用我们的HTML结构,标签是否是输入的父项?否。这是兄弟的前身。
第二次尝试如何尝试在secondName输入之前获取secondName标签?该选择器正在使用'.form-group .lastName'
,因此它正在寻找具有form-group
子项的父项lastName
,对吗?这样应该可以吗?
不。第二次尝试失败的原因是,您赋予closest
的选择器旨在仅匹配父元素。它不会执行任何嵌套遍历,以查看选择器是否匹配 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()
。