javascript - 为什么链接 offsetLeft 考虑列表填充?
问题描述
我正在阅读链接元素的 offsetLeft 属性并相应地更改另一个元素的位置。但是,这仅在没有任何(甚至浏览器默认)样式应用于位置属性的情况下按预期工作。例如:ul padding 的变化会影响 li offsetLeft 并导致偏离预期位置。
navbarElementsList = document.getElementsByClassName('js-element');
navbarUnderline = document.getElementById('js-underline');
let navbarElement;
for (let i = 0, len = navbarElementsList.length; i < len; i++) {
navbarElement = navbarElementsList[i];
navbarElementsList[i].addEventListener('click', function(event){
let underlineStart = this.offsetLeft;
let underlineWidth = this.offsetWidth;
document.getElementById('js-underline').style.left = underlineStart.toString() + "px";
document.getElementById('js-underline').style.width = underlineWidth.toString() + "px";
});
}
ul {
list-style-type: none;
}
li {
display: inline;
}
a {
cursor: pointer;
}
#js-underline {
position: relative;
left: 0;
width: 25px;
height: 5px;;
background-color: blue;
transition: 0.5s ease;
-moz-transition: 0.5s ease;
-webkit-transition: 0.5s ease;
}
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test</title>
</head>
<body>
<ul style=" margin-left: 40px ;">
<li><a class="c-navbar__element js-element">aaaaaaa</a></li>
<li><a class="c-navbar__element js-element">bbbb</a></li>
<li><a class="c-navbar__element js-element">c</a></li>
<li><a class="c-navbar__element js-element">ddddddddddddddd</a></li>
<li><div id="js-underline" class="c-navbar__underline"></div></li>
</ul>
</body>
</html>
在上面的示例中,我将 ul margin-left 更改为 40px,不幸的是它加到了最终的 #underline 位置。谁能解释这种行为并告诉我如何正确实施?我将非常感谢您的帮助。
解决方案
Element.offsetNNN
是相对于 its 的offsetParent
,这里所有的元素都offsetParent
设置为<body>
元素。
您#js-underline
也受到该填充的影响,或者更准确地说,它的父级是。
因此,当您将该元素的 left 设置为 others'offsetLeft
时,它自己的元素offsetLeft
也仍然存在。
left
一种丑陋的解决方法是在样式为0
;时测量 offsetLeft 。
const navbarElementsList = document.getElementsByClassName('js-element');
const navbarUnderline = document.getElementById('js-underline');
const default_left = navbarUnderline.offsetLeft;
let navbarElement;
for (let i = 0, len = navbarElementsList.length; i < len; i++) {
navbarElement = navbarElementsList[i];
navbarElementsList[i].addEventListener('click', function(event){
let underlineStart = this.offsetLeft;
let underlineWidth = this.offsetWidth;
navbarUnderline.style.left = underlineStart - default_left + "px";
navbarUnderline.style.width = underlineWidth.toString() + "px";
});
}
ul {
list-style-type: none;
}
li {
display: inline;
}
a {
cursor: pointer;
}
#js-underline {
position: relative;
left: 0;
width: 25px;
height: 5px;;
background-color: blue;
transition: 0.5s ease;
-moz-transition: 0.5s ease;
-webkit-transition: 0.5s ease;
}
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test</title>
</head>
<body>
<ul style=" margin-left: 40px ;">
<li><a class="c-navbar__element js-element">aaaaaaa</a></li>
<li><a class="c-navbar__element js-element">bbbb</a></li>
<li><a class="c-navbar__element js-element">c</a></li>
<li><a class="c-navbar__element js-element">ddddddddddddddd</a></li>
<li><div id="js-underline" class="c-navbar__underline"></div></li>
</ul>
</body>
</html>
另一种方法是绝对定位下划线,以便边距不再影响它。
const navbarElementsList = document.getElementsByClassName('js-element');
const navbarUnderline = document.getElementById('js-underline');
let navbarElement;
for (let i = 0, len = navbarElementsList.length; i < len; i++) {
navbarElement = navbarElementsList[i];
navbarElementsList[i].addEventListener('click', function(event){
let underlineStart = this.offsetLeft;
let underlineWidth = this.offsetWidth;
navbarUnderline.style.left = underlineStart + "px";
navbarUnderline.style.width = underlineWidth + "px";
});
}
// set to firt item
navbarElementsList[0].click();
ul {
list-style-type: none;
}
li {
display: inline;
}
a {
cursor: pointer;
}
#js-underline {
position: absolute;
left: 0;
width: 25px;
height: 5px;;
background-color: blue;
transition: 0.5s ease;
-moz-transition: 0.5s ease;
-webkit-transition: 0.5s ease;
}
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test</title>
</head>
<body>
<ul style=" margin-left: 40px ;">
<li><a class="c-navbar__element js-element">aaaaaaa</a></li>
<li><a class="c-navbar__element js-element">bbbb</a></li>
<li><a class="c-navbar__element js-element">c</a></li>
<li><a class="c-navbar__element js-element">ddddddddddddddd</a></li>
<li>
<div id="js-underline" class="c-navbar__underline"></div>
</li>
</ul>
</body>
</html>
推荐阅读
- dialogflow-es - 如何为我的操作设置另一个显式调用?
- c# - Azure SDK C# - 从具有指定磁盘类型的映像创建 VM(标准 SSD)
- react-native - 反应原生谷歌登录要求谷歌驱动器权限
- groovy - 将列表拆分为子列表,类似于整理,但结果的最大大小
- apache - Tomcat 忽略 Apache 反向代理后面的 X-Forwarded-Proto
- sql - 当两个 CTE 上的 Flag=1 时,如何设置 Flag =0?
- android - 使用 Room 将资产中的 JSON 数据存储到数据库中
- c++ - 从斐波那契序列c ++中的数组中查找正确元素时出错
- asp.net-core - 使用 Yarn 安装 Font Awesome 后如何使用
- c++ - 从组件的 std::type_index 获取最多派生类型