相邻兄弟选择器 element.querySelector("+element") 无效
Adjacent sibling selector element.querySelector("+element") is invalid
这个简单的代码可以工作:
<!DOCTYPE html>
<html>
<body>
<br>
<div>
<a href="#a1">Link 1</a>
<a href="#a2">Link 2</a>
<a href="#a3">Link 3</a>
<a href="#a4">Link 4</a>
</div>
<a href="#c1">Link 1 <span>color me plz!</span></a>
<br><br>
<div>
<a href="#b1">Link 1</a>
<a href="#b2">Link 2</a>
<a href="#b3">Link 3</a>
<a href="#b4">Link 4</a>
</div>
<a href="#c1">Link 1 <span>color me plz!</span></a>
<a href="#c2">Link 2 <span>color me plz!</span></a>
<script>
testing = document.querySelectorAll("div + a");
for (let i = 0; i < testing.length; i++){
testing[i].addEventListener("mouseenter", function(){
const x = testing[i];
x.style.backgroundColor = "cyan";
x.querySelector("span").style.backgroundColor = "pink";
});
}
</script>
</body>
</html>
但我真正的问题是:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style-test.css">
</head>
<body>
<nav>
<div>
<a href="#A1">Menu A.1</a>
<a href="#A2">Menu A.2</a>
</div>
<div class="right">
<div>
<a href="#B1">Menu B.1</a>
<ul>
<li><a href="#B1.1">B.1 Sub 1</a></li>
<li><a href="#B1.2">B.1 Sub 2</a></li>
</ul>
</div>
<div>
<a href="#B2"">Menu B.2</a>
<ul>
<li><a href="#B2.1">B.2 Sub 1</a></li>
<li><a href="#B2.2">B.2 Sub 2</a></li>
</ul>
</div>
<div>
<a href="#B3">Menu B.3</a>
<ul>
<li><a href="#B3.1">B.3 Sub 1 Test Longer Text</a></li>
<li><a href="#B3.2">B.3 Sub 2</a></li>
</ul>
</div>
<div>
<a href="#B4">Menu B.4</a>
<ul>
<li><a href="#B4.1">B.4 Sub 1</a></li>
<li><a href="#B4.2">B.4 Sub 2</a></li>
</ul>
</div>
</div>
</nav>
<div style="float: left; margin-top: 1000px"></div>
<script>
const menu = document.querySelectorAll("nav div > a");
console.log("Get all menu:");
console.log(menu);
for (let i = 0; i < menu.length; i++) {
menu[i].addEventListener("mouseenter", function(){
console.log("mouseEnter");
console.log("menu[i].addEventListener:");
console.log(menu[i]);
//console.log(menu[i].querySelector("+ ul"));
const subMenu = menu[i].querySelector(` + ul`);
/* ^^^ The problem is here above ^^^ --- Everything stops here */
console.log("OK! 'querySelector' is valid"); //<-- this won't display...
//if(window.getComputedStyle(subMenu).getPropertyValue("display") === "block") /*Corrected*/
if(subMenu.style.display === "block")
{
console.log("subMenu.style.display === block");
const subMenuBox = subMenu.getBoundingClientRect();
const posX = (subMenuBox.left + subMenuBox.width) - window.innerWidth;
if(posX > 0)
subMenu.style.left = (-posX - 20) + "px";
/*padding problem (need -20): didn't .getBoundingClientRect() include padding?*/
// /*or just*/ subMenu.style.right = "0px";
console.log("When here successfully!");
}
else{
console.log("Failed...");
}
})
}
</script>
</body>
</html>
css:
body{
color: #fff;
font-size: 20px;
background: #999;
margin: 0;
}
a{
color: #cfc;
}
nav, nav div > a, nav div{
float: left;
}
nav{
width: 100%;
background: #4169E1;
white-space: nowrap;
}
nav div{
margin: 0em 0.2em;
}
nav div:first-child{
margin-left: 0;
}
nav div div{
position: relative;
margin: 0;
}
nav a{
color: #cff;
display: block;
font-weight: 600;
text-decoration: none;
padding: 0.5em 1em;
}
nav a:hover{
color: #fff;
background: #f90;
}
nav div > a + ul{
position: absolute;
top: 2.15em;
float: left;
background: #666;
list-style-type: none;
margin: 0;
padding: 0;
min-width: 180px;
display: none;
}
nav div:hover > a + ul{
display: block;
}
.right{
float: right;
}
我只想得到<a>
紧挨着的兄弟,<a>
之后的<ul>
,也就是css中的a + ul
<div>
<a href="#B1">Menu B.1</a>
<ul>
<li><a href="#B1.1">B.1 Sub 1</a></li>
<li><a href="#B1.2">B.1 Sub 2</a></li>
</ul>
</div>
关注这里:
<script>
const menu = document.querySelectorAll("nav div > a");
for (let i = 0; i < menu.length; i++) {
menu[i].addEventListener("mouseenter", function(){
//Problem is here...
const subMenu = menu[i].querySelector(" + ul");
/*Corrected*/
//if(window.getComputedStyle(subMenu).getPropertyValue("display") === "block")
if(subMenu != null && subMenu.style.display === "block")
{
const subMenuBox = subMenu.getBoundingClientRect();
const posX = (subMenuBox.left + subMenuBox.width) - window.innerWidth;
if(posX > 0)
subMenu.style.left = (-posX -20) + "px";
/*padding problem (need -20): didn't .getBoundingClientRect() include
padding?*/
// /*or just*/ subMenu.style.right = "0px";
}
})
}
</script>
现在,我在这里做了什么:
首先,我select所有<a>
里面的<nav>
。
然后使用 for()
循环并将 mouseenter
事件放入所有 selected <a>
。
当用户将鼠标悬停在 <a>
上时,mouseenter
确切知道悬停在哪个 <a>
上。
现在问题来了:我想 select 悬停 <a>
.
的 a + ul
我试过了:
console.log(document.querySelector("menu[i] + ul"));
给我一个 null
值
console.log(document.querySelector(menu[i] + " + ul"));
给我 SyntaxError: 'file:///C:/Users/path/path/thisPage.html + ul' is not a valid selector
console.log(menu[i].querySelector(" + ul"));
给我 SyntaxError: '+ul' is not a valid selector
我该如何解决这个问题?使用 .querySelector()
继续 selection 但使用相邻的同级标签的正确做法是什么?
一方面,在非古代浏览器上,您可以使用 :scope
来指示调用 querySelector
的元素。但是 querySelector
将 仅 select 个元素,这些元素是当前元素的 children,而 <ul>
你想要一个兄弟姐妹。
取元素的 nextElementSibling
代替,检查它是否存在,检查它是否是 ul
代替:
for (const menu of document.querySelectorAll("nav div > a")) {
menu.addEventListener("mouseenter", function() {
console.log(menu, menu.nextElementSibling);
const subMenu = menu.nextElementSibling;
if (!subMenu || !subMenu.matches('ul')) {
return;
}
if (subMenu.style.display === "block") {
console.log("subMenu.style.display === block");
const subMenuBox = subMenu.getBoundingClientRect();
const posX = (subMenuBox.left + subMenuBox.width) - window.innerWidth;
subMenu.style.left = -posX;
console.log("When here successfully!");
} else {
console.log("Failed...");
}
})
}
body {
color: #fff;
font-size: 20px;
background: #999;
margin: 0;
}
a {
color: #cfc;
}
nav,
nav div>a,
nav div {
float: left;
}
nav {
width: 100%;
background: #4169E1;
white-space: nowrap;
}
nav div {
margin: 0em 0.2em;
}
nav div:first-child {
margin-left: 0;
}
nav div div {
position: relative;
margin: 0;
}
nav a {
color: #cff;
display: block;
font-weight: 600;
text-decoration: none;
padding: 0.5em 1em;
}
nav a:hover {
color: #fff;
background: #f90;
}
nav div>a+ul {
position: absolute;
top: 2.15em;
float: left;
background: #666;
list-style-type: none;
margin: 0;
padding: 0;
min-width: 180px;
display: none;
}
nav div:hover>a+ul {
display: block;
}
.right {
float: right;
}
<nav>
<div>
<a href="#A1">Menu A.1</a>
<a href="#A2">Menu A.2</a>
</div>
<div class="right">
<div>
<a href="#B1">Menu B.1</a>
<ul>
<li><a href="#B1.1">B.1 Sub 1</a></li>
<li><a href="#B1.2">B.1 Sub 2</a></li>
</ul>
</div>
<div>
<a href="#B2">Menu B.2</a>
<ul>
<li><a href="#B2.1 ">B.2 Sub 1</a></li>
<li><a href="#B2.2 ">B.2 Sub 2</a></li>
</ul>
</div>
<div>
<a href="#B3 ">Menu B.3</a>
<ul>
<li><a href="#B3.1 ">B.3 Sub 1 Test Longer Text</a></li>
<li><a href="#B3.2 ">B.3 Sub 2</a></li>
</ul>
</div>
<div>
<a href="#B4 ">Menu B.4</a>
<ul>
<li><a href="#B4.1 ">B.4 Sub 1</a></li>
<li><a href="#B4.2 ">B.4 Sub 2</a></li>
</ul>
</div>
</div>
</nav>
<div style="float: left; margin-top: 1000px "></div>
因为并非所有菜单都有子菜单,所以您做需要先测试 UL 是否存在,然后再尝试使用它。
请注意,subMenu.style.display === "block"
永远不会在给定的代码中实现,因为 <ul>
没有 style
属性 直接在元素上 .如果他们这样做了,测试就会成功。如果您要查看它们当前是否 正在显示,请改用 window.getComputedStyle
:
for (const menu of document.querySelectorAll("nav div > a")) {
menu.addEventListener("mouseenter", function() {
console.log(menu, menu.nextElementSibling);
const subMenu = menu.nextElementSibling;
if (!subMenu || !subMenu.matches('ul')) {
return;
}
if (window.getComputedStyle(subMenu).display === "block") {
console.log("subMenu.style.display === block");
const subMenuBox = subMenu.getBoundingClientRect();
const posX = (subMenuBox.left + subMenuBox.width) - window.innerWidth;
subMenu.style.left = -posX;
console.log("When here successfully!");
} else {
console.log("Failed...");
}
})
}
body {
color: #fff;
font-size: 20px;
background: #999;
margin: 0;
}
a {
color: #cfc;
}
nav,
nav div>a,
nav div {
float: left;
}
nav {
width: 100%;
background: #4169E1;
white-space: nowrap;
}
nav div {
margin: 0em 0.2em;
}
nav div:first-child {
margin-left: 0;
}
nav div div {
position: relative;
margin: 0;
}
nav a {
color: #cff;
display: block;
font-weight: 600;
text-decoration: none;
padding: 0.5em 1em;
}
nav a:hover {
color: #fff;
background: #f90;
}
nav div>a+ul {
position: absolute;
top: 2.15em;
float: left;
background: #666;
list-style-type: none;
margin: 0;
padding: 0;
min-width: 180px;
display: none;
}
nav div:hover>a+ul {
display: block;
}
.right {
float: right;
}
<nav>
<div>
<a href="#A1">Menu A.1</a>
<a href="#A2">Menu A.2</a>
</div>
<div class="right">
<div>
<a href="#B1">Menu B.1</a>
<ul>
<li><a href="#B1.1">B.1 Sub 1</a></li>
<li><a href="#B1.2">B.1 Sub 2</a></li>
</ul>
</div>
<div>
<a href="#B2">Menu B.2</a>
<ul>
<li><a href="#B2.1 ">B.2 Sub 1</a></li>
<li><a href="#B2.2 ">B.2 Sub 2</a></li>
</ul>
</div>
<div>
<a href="#B3 ">Menu B.3</a>
<ul>
<li><a href="#B3.1 ">B.3 Sub 1 Test Longer Text</a></li>
<li><a href="#B3.2 ">B.3 Sub 2</a></li>
</ul>
</div>
<div>
<a href="#B4 ">Menu B.4</a>
<ul>
<li><a href="#B4.1 ">B.4 Sub 1</a></li>
<li><a href="#B4.2 ">B.4 Sub 2</a></li>
</ul>
</div>
</div>
</nav>
<div style="float: left; margin-top: 1000px "></div>
这个简单的代码可以工作:
<!DOCTYPE html>
<html>
<body>
<br>
<div>
<a href="#a1">Link 1</a>
<a href="#a2">Link 2</a>
<a href="#a3">Link 3</a>
<a href="#a4">Link 4</a>
</div>
<a href="#c1">Link 1 <span>color me plz!</span></a>
<br><br>
<div>
<a href="#b1">Link 1</a>
<a href="#b2">Link 2</a>
<a href="#b3">Link 3</a>
<a href="#b4">Link 4</a>
</div>
<a href="#c1">Link 1 <span>color me plz!</span></a>
<a href="#c2">Link 2 <span>color me plz!</span></a>
<script>
testing = document.querySelectorAll("div + a");
for (let i = 0; i < testing.length; i++){
testing[i].addEventListener("mouseenter", function(){
const x = testing[i];
x.style.backgroundColor = "cyan";
x.querySelector("span").style.backgroundColor = "pink";
});
}
</script>
</body>
</html>
但我真正的问题是:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style-test.css">
</head>
<body>
<nav>
<div>
<a href="#A1">Menu A.1</a>
<a href="#A2">Menu A.2</a>
</div>
<div class="right">
<div>
<a href="#B1">Menu B.1</a>
<ul>
<li><a href="#B1.1">B.1 Sub 1</a></li>
<li><a href="#B1.2">B.1 Sub 2</a></li>
</ul>
</div>
<div>
<a href="#B2"">Menu B.2</a>
<ul>
<li><a href="#B2.1">B.2 Sub 1</a></li>
<li><a href="#B2.2">B.2 Sub 2</a></li>
</ul>
</div>
<div>
<a href="#B3">Menu B.3</a>
<ul>
<li><a href="#B3.1">B.3 Sub 1 Test Longer Text</a></li>
<li><a href="#B3.2">B.3 Sub 2</a></li>
</ul>
</div>
<div>
<a href="#B4">Menu B.4</a>
<ul>
<li><a href="#B4.1">B.4 Sub 1</a></li>
<li><a href="#B4.2">B.4 Sub 2</a></li>
</ul>
</div>
</div>
</nav>
<div style="float: left; margin-top: 1000px"></div>
<script>
const menu = document.querySelectorAll("nav div > a");
console.log("Get all menu:");
console.log(menu);
for (let i = 0; i < menu.length; i++) {
menu[i].addEventListener("mouseenter", function(){
console.log("mouseEnter");
console.log("menu[i].addEventListener:");
console.log(menu[i]);
//console.log(menu[i].querySelector("+ ul"));
const subMenu = menu[i].querySelector(` + ul`);
/* ^^^ The problem is here above ^^^ --- Everything stops here */
console.log("OK! 'querySelector' is valid"); //<-- this won't display...
//if(window.getComputedStyle(subMenu).getPropertyValue("display") === "block") /*Corrected*/
if(subMenu.style.display === "block")
{
console.log("subMenu.style.display === block");
const subMenuBox = subMenu.getBoundingClientRect();
const posX = (subMenuBox.left + subMenuBox.width) - window.innerWidth;
if(posX > 0)
subMenu.style.left = (-posX - 20) + "px";
/*padding problem (need -20): didn't .getBoundingClientRect() include padding?*/
// /*or just*/ subMenu.style.right = "0px";
console.log("When here successfully!");
}
else{
console.log("Failed...");
}
})
}
</script>
</body>
</html>
css:
body{
color: #fff;
font-size: 20px;
background: #999;
margin: 0;
}
a{
color: #cfc;
}
nav, nav div > a, nav div{
float: left;
}
nav{
width: 100%;
background: #4169E1;
white-space: nowrap;
}
nav div{
margin: 0em 0.2em;
}
nav div:first-child{
margin-left: 0;
}
nav div div{
position: relative;
margin: 0;
}
nav a{
color: #cff;
display: block;
font-weight: 600;
text-decoration: none;
padding: 0.5em 1em;
}
nav a:hover{
color: #fff;
background: #f90;
}
nav div > a + ul{
position: absolute;
top: 2.15em;
float: left;
background: #666;
list-style-type: none;
margin: 0;
padding: 0;
min-width: 180px;
display: none;
}
nav div:hover > a + ul{
display: block;
}
.right{
float: right;
}
我只想得到<a>
紧挨着的兄弟,<a>
之后的<ul>
,也就是css中的a + ul
<div>
<a href="#B1">Menu B.1</a>
<ul>
<li><a href="#B1.1">B.1 Sub 1</a></li>
<li><a href="#B1.2">B.1 Sub 2</a></li>
</ul>
</div>
关注这里:
<script>
const menu = document.querySelectorAll("nav div > a");
for (let i = 0; i < menu.length; i++) {
menu[i].addEventListener("mouseenter", function(){
//Problem is here...
const subMenu = menu[i].querySelector(" + ul");
/*Corrected*/
//if(window.getComputedStyle(subMenu).getPropertyValue("display") === "block")
if(subMenu != null && subMenu.style.display === "block")
{
const subMenuBox = subMenu.getBoundingClientRect();
const posX = (subMenuBox.left + subMenuBox.width) - window.innerWidth;
if(posX > 0)
subMenu.style.left = (-posX -20) + "px";
/*padding problem (need -20): didn't .getBoundingClientRect() include
padding?*/
// /*or just*/ subMenu.style.right = "0px";
}
})
}
</script>
现在,我在这里做了什么:
首先,我select所有<a>
里面的<nav>
。
然后使用 for()
循环并将 mouseenter
事件放入所有 selected <a>
。
当用户将鼠标悬停在 <a>
上时,mouseenter
确切知道悬停在哪个 <a>
上。
现在问题来了:我想 select 悬停 <a>
.
a + ul
我试过了:
console.log(document.querySelector("menu[i] + ul"));
给我一个 null
值
console.log(document.querySelector(menu[i] + " + ul"));
给我 SyntaxError: 'file:///C:/Users/path/path/thisPage.html + ul' is not a valid selector
console.log(menu[i].querySelector(" + ul"));
给我 SyntaxError: '+ul' is not a valid selector
我该如何解决这个问题?使用 .querySelector()
继续 selection 但使用相邻的同级标签的正确做法是什么?
一方面,在非古代浏览器上,您可以使用 :scope
来指示调用 querySelector
的元素。但是 querySelector
将 仅 select 个元素,这些元素是当前元素的 children,而 <ul>
你想要一个兄弟姐妹。
取元素的 nextElementSibling
代替,检查它是否存在,检查它是否是 ul
代替:
for (const menu of document.querySelectorAll("nav div > a")) {
menu.addEventListener("mouseenter", function() {
console.log(menu, menu.nextElementSibling);
const subMenu = menu.nextElementSibling;
if (!subMenu || !subMenu.matches('ul')) {
return;
}
if (subMenu.style.display === "block") {
console.log("subMenu.style.display === block");
const subMenuBox = subMenu.getBoundingClientRect();
const posX = (subMenuBox.left + subMenuBox.width) - window.innerWidth;
subMenu.style.left = -posX;
console.log("When here successfully!");
} else {
console.log("Failed...");
}
})
}
body {
color: #fff;
font-size: 20px;
background: #999;
margin: 0;
}
a {
color: #cfc;
}
nav,
nav div>a,
nav div {
float: left;
}
nav {
width: 100%;
background: #4169E1;
white-space: nowrap;
}
nav div {
margin: 0em 0.2em;
}
nav div:first-child {
margin-left: 0;
}
nav div div {
position: relative;
margin: 0;
}
nav a {
color: #cff;
display: block;
font-weight: 600;
text-decoration: none;
padding: 0.5em 1em;
}
nav a:hover {
color: #fff;
background: #f90;
}
nav div>a+ul {
position: absolute;
top: 2.15em;
float: left;
background: #666;
list-style-type: none;
margin: 0;
padding: 0;
min-width: 180px;
display: none;
}
nav div:hover>a+ul {
display: block;
}
.right {
float: right;
}
<nav>
<div>
<a href="#A1">Menu A.1</a>
<a href="#A2">Menu A.2</a>
</div>
<div class="right">
<div>
<a href="#B1">Menu B.1</a>
<ul>
<li><a href="#B1.1">B.1 Sub 1</a></li>
<li><a href="#B1.2">B.1 Sub 2</a></li>
</ul>
</div>
<div>
<a href="#B2">Menu B.2</a>
<ul>
<li><a href="#B2.1 ">B.2 Sub 1</a></li>
<li><a href="#B2.2 ">B.2 Sub 2</a></li>
</ul>
</div>
<div>
<a href="#B3 ">Menu B.3</a>
<ul>
<li><a href="#B3.1 ">B.3 Sub 1 Test Longer Text</a></li>
<li><a href="#B3.2 ">B.3 Sub 2</a></li>
</ul>
</div>
<div>
<a href="#B4 ">Menu B.4</a>
<ul>
<li><a href="#B4.1 ">B.4 Sub 1</a></li>
<li><a href="#B4.2 ">B.4 Sub 2</a></li>
</ul>
</div>
</div>
</nav>
<div style="float: left; margin-top: 1000px "></div>
因为并非所有菜单都有子菜单,所以您做需要先测试 UL 是否存在,然后再尝试使用它。
请注意,subMenu.style.display === "block"
永远不会在给定的代码中实现,因为 <ul>
没有 style
属性 直接在元素上 .如果他们这样做了,测试就会成功。如果您要查看它们当前是否 正在显示,请改用 window.getComputedStyle
:
for (const menu of document.querySelectorAll("nav div > a")) {
menu.addEventListener("mouseenter", function() {
console.log(menu, menu.nextElementSibling);
const subMenu = menu.nextElementSibling;
if (!subMenu || !subMenu.matches('ul')) {
return;
}
if (window.getComputedStyle(subMenu).display === "block") {
console.log("subMenu.style.display === block");
const subMenuBox = subMenu.getBoundingClientRect();
const posX = (subMenuBox.left + subMenuBox.width) - window.innerWidth;
subMenu.style.left = -posX;
console.log("When here successfully!");
} else {
console.log("Failed...");
}
})
}
body {
color: #fff;
font-size: 20px;
background: #999;
margin: 0;
}
a {
color: #cfc;
}
nav,
nav div>a,
nav div {
float: left;
}
nav {
width: 100%;
background: #4169E1;
white-space: nowrap;
}
nav div {
margin: 0em 0.2em;
}
nav div:first-child {
margin-left: 0;
}
nav div div {
position: relative;
margin: 0;
}
nav a {
color: #cff;
display: block;
font-weight: 600;
text-decoration: none;
padding: 0.5em 1em;
}
nav a:hover {
color: #fff;
background: #f90;
}
nav div>a+ul {
position: absolute;
top: 2.15em;
float: left;
background: #666;
list-style-type: none;
margin: 0;
padding: 0;
min-width: 180px;
display: none;
}
nav div:hover>a+ul {
display: block;
}
.right {
float: right;
}
<nav>
<div>
<a href="#A1">Menu A.1</a>
<a href="#A2">Menu A.2</a>
</div>
<div class="right">
<div>
<a href="#B1">Menu B.1</a>
<ul>
<li><a href="#B1.1">B.1 Sub 1</a></li>
<li><a href="#B1.2">B.1 Sub 2</a></li>
</ul>
</div>
<div>
<a href="#B2">Menu B.2</a>
<ul>
<li><a href="#B2.1 ">B.2 Sub 1</a></li>
<li><a href="#B2.2 ">B.2 Sub 2</a></li>
</ul>
</div>
<div>
<a href="#B3 ">Menu B.3</a>
<ul>
<li><a href="#B3.1 ">B.3 Sub 1 Test Longer Text</a></li>
<li><a href="#B3.2 ">B.3 Sub 2</a></li>
</ul>
</div>
<div>
<a href="#B4 ">Menu B.4</a>
<ul>
<li><a href="#B4.1 ">B.4 Sub 1</a></li>
<li><a href="#B4.2 ">B.4 Sub 2</a></li>
</ul>
</div>
</div>
</nav>
<div style="float: left; margin-top: 1000px "></div>