jQuery 具有特定类型的下一个兄弟 child
jQuery next sibling that has a particular kind of child
我的 HTML 有一个包含许多兄弟 div
元素的容器元素,每个兄弟元素包含一个 contenteditable
p
。然而,这些同级 div
被不包含可编辑元素的其他 div
“中断”。
目前我面临的挑战是如何在使用左右箭头键从 C 移动到 D 或从 D 返回 C 时“跳过”这些中断 div
(参见代码段) .当遇到这些 div
缺少可编辑元素时,导航将停止。我该如何纠正?
$('#foo p[contenteditable = "true"]').bind("keydown", function(e) {
switch (e.key) {
case "ArrowLeft":
var $P = $(this).parent().prev().children('p[contenteditable = "true"]');
setTimeout(() => $P.focus(), 0);
e.stopImmediatePropagation();
e.preventDefault();
break;
case "ArrowRight":
var $P = $(this).parent().next().children('p[contenteditable = "true"]');
setTimeout(() => $P.focus(), 0);
e.stopImmediatePropagation();
e.preventDefault();
break;
}
});
#foo p[contenteditable="true"] {
/* font-size: 22px;*/
height: 22px;
width: 22px;
color: cyan;
font-weight: bold;
background-color: cyan;
}
#foo p.const {
background-color: inherit;
border: none;
height: 22px;
width: 22px;
}
#foo div {
text-align: center;
display: inline-block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="foo">
<div>
<p contenteditable="true" tabindex="0"></p>
<p>A</p>
</div>
<div>
<p contenteditable="true" tabindex="1"></p>
<p>B</p>
</div>
<div>
<p contenteditable="true" tabindex="2"></p>
<p>C</p>
</div>
<div>
<p class="const"> </p>
<p> </p>
</div>
<div>
<p class="const">"</p>
<p>"</p>
</div>
<div>
<p contenteditable="true" tabindex="3"></p>
<p>D</p>
</div>
<div>
<p contenteditable="true" tabindex="4"></p>
<p>E</p>
</div>
</div>
代替prev()
或next()
,使用.prevAll(":has(p[contenteditable])").first()
和.nextAll(":has(p[contenteditable])").first()
:
$('#foo p[contenteditable = "true"]').bind("keydown", function(e) {
switch (e.key) {
case "ArrowLeft":
var $P = $(this).parent().prevAll(":has(p[contenteditable])").first().children('p[contenteditable = "true"]');
setTimeout(() => $P.focus(), 0);
e.stopImmediatePropagation();
e.preventDefault();
break;
case "ArrowRight":
var $P = $(this).parent().nextAll(":has(p[contenteditable])").first().children('p[contenteditable = "true"]');
setTimeout(() => $P.focus(), 0);
e.stopImmediatePropagation();
e.preventDefault();
break;
}
});
#foo p[contenteditable="true"] {
/* font-size: 22px;*/
height: 22px;
width: 22px;
color: cyan;
font-weight: bold;
background-color: cyan;
}
#foo p.const {
background-color: inherit;
border: none;
height: 22px;
width: 22px;
}
#foo div {
text-align: center;
display: inline-block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="foo">
<div>
<p contenteditable="true" tabindex="0"></p>
<p>A</p>
</div>
<div>
<p contenteditable="true" tabindex="1"></p>
<p>B</p>
</div>
<div>
<p contenteditable="true" tabindex="2"></p>
<p>C</p>
</div>
<div>
<p class="const"> </p>
<p>
<p>
</div>
<div>
<p class="const">"</p>
<p>"
<p>
</div>
<div>
<p contenteditable="true" tabindex="3"></p>
<p>D</p>
</div>
<div>
<p contenteditable="true" tabindex="4"></p>
<p>E</p>
</div>
</div>
prevAll
/nextAll
匹配所有匹配选择器的 previous/following 兄弟,返回一个 jQuery 对象 按顺序 (所以最接近的兄弟是第一个,然后是第二近的,依此类推);使用 .first()
然后将集合减少到最近的兄弟。
我在其中使用了 :has
pseudo-selector,但您最好将相关元素改为 class,因为 :has
是 jQuery-specific 除了 CSS。这里我使用了 class stop
所以它是 .xxxxAll(".stop").first()
:
$('#foo p[contenteditable = "true"]').bind("keydown", function(e) {
switch (e.key) {
case "ArrowLeft":
var $P = $(this).parent().prevAll(".stop").first().children('p[contenteditable = "true"]');
setTimeout(() => $P.focus(), 0);
e.stopImmediatePropagation();
e.preventDefault();
break;
case "ArrowRight":
var $P = $(this).parent().nextAll(".stop").first().children('p[contenteditable = "true"]');
setTimeout(() => $P.focus(), 0);
e.stopImmediatePropagation();
e.preventDefault();
break;
}
});
#foo p[contenteditable="true"] {
/* font-size: 22px;*/
height: 22px;
width: 22px;
color: cyan;
font-weight: bold;
background-color: cyan;
}
#foo p.const {
background-color: inherit;
border: none;
height: 22px;
width: 22px;
}
#foo div {
text-align: center;
display: inline-block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="foo">
<div class="stop">
<p contenteditable="true" tabindex="0"></p>
<p>A</p>
</div>
<div class="stop">
<p contenteditable="true" tabindex="1"></p>
<p>B</p>
</div>
<div class="stop">
<p contenteditable="true" tabindex="2"></p>
<p>C</p>
</div>
<div>
<p class="const"> </p>
<p>
<p>
</div>
<div>
<p class="const">"</p>
<p>"
<p>
</div>
<div class="stop">
<p contenteditable="true" tabindex="3"></p>
<p>D</p>
</div>
<div class="stop">
<p contenteditable="true" tabindex="4"></p>
<p>E</p>
</div>
</div>
要完成您需要的操作,您需要使用 prevAll()
和 nextAll()
,而不是 prev()
和 next()
,因为您需要跳过中间元素。您可以将此 :has()
选择器结合起来,以仅查找具有后代 contenteditable
的容器,并与 first()
一起检索最接近的匹配项。
另请注意,bind()
已弃用,将很快从 jQuery 中删除;使用 on()
代替。也可以稍微修改逻辑以减少对 switch
的依赖并避免不必要的重复。最后,您在 HTML.
中的几个地方使用了 <p>
而不是 </p>
话虽如此,试试这个:
let keyMethodLookup = {
ArrowLeft: 'prevAll',
ArrowRight: 'nextAll'
}
$('#foo p[contenteditable="true"]').on("keydown", e => {
if (!keyMethodLookup.hasOwnProperty(e.key))
return;
let method = keyMethodLookup[e.key];
$(e.currentTarget).parent()[method]('div:has(p[contenteditable="true"])').first().children('p[contenteditable="true"]').focus();
e.stopImmediatePropagation();
e.preventDefault();
});
#foo p[contenteditable="true"] {
/* font-size: 22px;*/
height: 22px;
width: 22px;
color: cyan;
font-weight: bold;
background-color: cyan;
}
#foo p.const {
background-color: inherit;
border: none;
height: 22px;
width: 22px;
}
#foo div {
text-align: center;
display: inline-block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="foo">
<div>
<p contenteditable="true" tabindex="0"></p>
<p>A</p>
</div>
<div>
<p contenteditable="true" tabindex="1"></p>
<p>B</p>
</div>
<div>
<p contenteditable="true" tabindex="2"></p>
<p>C</p>
</div>
<div>
<p class="const"> </p>
<p> </p>
</div>
<div>
<p class="const">"</p>
<p>"</p>
</div>
<div>
<p contenteditable="true" tabindex="3"></p>
<p>D</p>
</div>
<div>
<p contenteditable="true" tabindex="4"></p>
<p>E</p>
</div>
</div>
我的 HTML 有一个包含许多兄弟 div
元素的容器元素,每个兄弟元素包含一个 contenteditable
p
。然而,这些同级 div
被不包含可编辑元素的其他 div
“中断”。
目前我面临的挑战是如何在使用左右箭头键从 C 移动到 D 或从 D 返回 C 时“跳过”这些中断 div
(参见代码段) .当遇到这些 div
缺少可编辑元素时,导航将停止。我该如何纠正?
$('#foo p[contenteditable = "true"]').bind("keydown", function(e) {
switch (e.key) {
case "ArrowLeft":
var $P = $(this).parent().prev().children('p[contenteditable = "true"]');
setTimeout(() => $P.focus(), 0);
e.stopImmediatePropagation();
e.preventDefault();
break;
case "ArrowRight":
var $P = $(this).parent().next().children('p[contenteditable = "true"]');
setTimeout(() => $P.focus(), 0);
e.stopImmediatePropagation();
e.preventDefault();
break;
}
});
#foo p[contenteditable="true"] {
/* font-size: 22px;*/
height: 22px;
width: 22px;
color: cyan;
font-weight: bold;
background-color: cyan;
}
#foo p.const {
background-color: inherit;
border: none;
height: 22px;
width: 22px;
}
#foo div {
text-align: center;
display: inline-block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="foo">
<div>
<p contenteditable="true" tabindex="0"></p>
<p>A</p>
</div>
<div>
<p contenteditable="true" tabindex="1"></p>
<p>B</p>
</div>
<div>
<p contenteditable="true" tabindex="2"></p>
<p>C</p>
</div>
<div>
<p class="const"> </p>
<p> </p>
</div>
<div>
<p class="const">"</p>
<p>"</p>
</div>
<div>
<p contenteditable="true" tabindex="3"></p>
<p>D</p>
</div>
<div>
<p contenteditable="true" tabindex="4"></p>
<p>E</p>
</div>
</div>
代替prev()
或next()
,使用.prevAll(":has(p[contenteditable])").first()
和.nextAll(":has(p[contenteditable])").first()
:
$('#foo p[contenteditable = "true"]').bind("keydown", function(e) {
switch (e.key) {
case "ArrowLeft":
var $P = $(this).parent().prevAll(":has(p[contenteditable])").first().children('p[contenteditable = "true"]');
setTimeout(() => $P.focus(), 0);
e.stopImmediatePropagation();
e.preventDefault();
break;
case "ArrowRight":
var $P = $(this).parent().nextAll(":has(p[contenteditable])").first().children('p[contenteditable = "true"]');
setTimeout(() => $P.focus(), 0);
e.stopImmediatePropagation();
e.preventDefault();
break;
}
});
#foo p[contenteditable="true"] {
/* font-size: 22px;*/
height: 22px;
width: 22px;
color: cyan;
font-weight: bold;
background-color: cyan;
}
#foo p.const {
background-color: inherit;
border: none;
height: 22px;
width: 22px;
}
#foo div {
text-align: center;
display: inline-block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="foo">
<div>
<p contenteditable="true" tabindex="0"></p>
<p>A</p>
</div>
<div>
<p contenteditable="true" tabindex="1"></p>
<p>B</p>
</div>
<div>
<p contenteditable="true" tabindex="2"></p>
<p>C</p>
</div>
<div>
<p class="const"> </p>
<p>
<p>
</div>
<div>
<p class="const">"</p>
<p>"
<p>
</div>
<div>
<p contenteditable="true" tabindex="3"></p>
<p>D</p>
</div>
<div>
<p contenteditable="true" tabindex="4"></p>
<p>E</p>
</div>
</div>
prevAll
/nextAll
匹配所有匹配选择器的 previous/following 兄弟,返回一个 jQuery 对象 按顺序 (所以最接近的兄弟是第一个,然后是第二近的,依此类推);使用 .first()
然后将集合减少到最近的兄弟。
我在其中使用了 :has
pseudo-selector,但您最好将相关元素改为 class,因为 :has
是 jQuery-specific 除了 CSS。这里我使用了 class stop
所以它是 .xxxxAll(".stop").first()
:
$('#foo p[contenteditable = "true"]').bind("keydown", function(e) {
switch (e.key) {
case "ArrowLeft":
var $P = $(this).parent().prevAll(".stop").first().children('p[contenteditable = "true"]');
setTimeout(() => $P.focus(), 0);
e.stopImmediatePropagation();
e.preventDefault();
break;
case "ArrowRight":
var $P = $(this).parent().nextAll(".stop").first().children('p[contenteditable = "true"]');
setTimeout(() => $P.focus(), 0);
e.stopImmediatePropagation();
e.preventDefault();
break;
}
});
#foo p[contenteditable="true"] {
/* font-size: 22px;*/
height: 22px;
width: 22px;
color: cyan;
font-weight: bold;
background-color: cyan;
}
#foo p.const {
background-color: inherit;
border: none;
height: 22px;
width: 22px;
}
#foo div {
text-align: center;
display: inline-block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="foo">
<div class="stop">
<p contenteditable="true" tabindex="0"></p>
<p>A</p>
</div>
<div class="stop">
<p contenteditable="true" tabindex="1"></p>
<p>B</p>
</div>
<div class="stop">
<p contenteditable="true" tabindex="2"></p>
<p>C</p>
</div>
<div>
<p class="const"> </p>
<p>
<p>
</div>
<div>
<p class="const">"</p>
<p>"
<p>
</div>
<div class="stop">
<p contenteditable="true" tabindex="3"></p>
<p>D</p>
</div>
<div class="stop">
<p contenteditable="true" tabindex="4"></p>
<p>E</p>
</div>
</div>
要完成您需要的操作,您需要使用 prevAll()
和 nextAll()
,而不是 prev()
和 next()
,因为您需要跳过中间元素。您可以将此 :has()
选择器结合起来,以仅查找具有后代 contenteditable
的容器,并与 first()
一起检索最接近的匹配项。
另请注意,bind()
已弃用,将很快从 jQuery 中删除;使用 on()
代替。也可以稍微修改逻辑以减少对 switch
的依赖并避免不必要的重复。最后,您在 HTML.
<p>
而不是 </p>
话虽如此,试试这个:
let keyMethodLookup = {
ArrowLeft: 'prevAll',
ArrowRight: 'nextAll'
}
$('#foo p[contenteditable="true"]').on("keydown", e => {
if (!keyMethodLookup.hasOwnProperty(e.key))
return;
let method = keyMethodLookup[e.key];
$(e.currentTarget).parent()[method]('div:has(p[contenteditable="true"])').first().children('p[contenteditable="true"]').focus();
e.stopImmediatePropagation();
e.preventDefault();
});
#foo p[contenteditable="true"] {
/* font-size: 22px;*/
height: 22px;
width: 22px;
color: cyan;
font-weight: bold;
background-color: cyan;
}
#foo p.const {
background-color: inherit;
border: none;
height: 22px;
width: 22px;
}
#foo div {
text-align: center;
display: inline-block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="foo">
<div>
<p contenteditable="true" tabindex="0"></p>
<p>A</p>
</div>
<div>
<p contenteditable="true" tabindex="1"></p>
<p>B</p>
</div>
<div>
<p contenteditable="true" tabindex="2"></p>
<p>C</p>
</div>
<div>
<p class="const"> </p>
<p> </p>
</div>
<div>
<p class="const">"</p>
<p>"</p>
</div>
<div>
<p contenteditable="true" tabindex="3"></p>
<p>D</p>
</div>
<div>
<p contenteditable="true" tabindex="4"></p>
<p>E</p>
</div>
</div>