基础示例代码-祖先元素无定位元素
<html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>offsetLeft研究
title>
head> <body style="border: 20px solid #000;"> <div id="box1" style="border: 20px solid #666; width:300px; height:300px; padding-left:20px; margin-left:20px;"> <div id="box2" style="border: 20px solid #999; width:200px; height: 200px; padding-left:20px; margin-left:20px;"> <div id="box3" style="border: 20px solid [[bbb]];width:100px; height: 100px; padding-left:20px; margin-left: 20px; overflow:scroll; white-space: nowrap;"> <div id="box4">这里是内容区域,父级为box3,父级超出部分滚动
div>
div>
div>
div>
body> <script> function clickFun(e){
console.log('鼠标点击点的ClientX:', e.clientX); console.log('鼠标点击点的layerX:', e.layerX); console.log('鼠标点击点的pageX:', e.pageX); console.log('鼠标点击点的offsetX:', e.offsetX); console.log('鼠标点击点的screenX:', e.screenX); console.log('鼠标点击点的x:', e.x); console.log('box1的offsetLeft', $('box1').offsetLeft); console.log('box2的offsetLeft', $('box2').offsetLeft); console.log('box3的offsetLeft', $('box3').offsetLeft); console.log('box4的offsetLeft', $('box4').offsetLeft); } function $(id){
return document.getElementById(id); } function addListener(type, fun) {
if (typeof window.addEventListener != "undefined") {
window.addEventListener(type, fun, false); } else {
window.attachEvent('on' + type, fun) } } window.onload = function(){
addListener('click', clickFun); };
script>
html>
我们设计了实验代码结构,由body中的四层嵌套盒子组成,除最里层的box4外每个盒子都有20像素宽度的边框,20像素的左内边距,和20像素的左外边距。
当鼠标点击页面时,控制台输出当前点击位置的一些位置数据(只研究横向的,所以只打印横坐标值),同时打印输入四层盒子的offsetLeft的值。
同时,box3设计了内容宽度超出容器后显示滚动条,以便验证滚动条对offsetLeft的影响。
先看默认状态下点击box4的左侧边框位置后输出的结果:
将截图放大观察,得出我们的
结论1 :在祖先元素中没有定位元素时,元素的offset值为其左边框的最左侧位置到html页面左边框的距离值
一点引申
根据输出结果,我们还可以猜想以下两个值的意义:
offsetX: 根据值的大小猜测为当前位置距离当前点击对象(e.target,这里为box4)左边框的值,至于是左边框的左侧还是右侧,需要进一步验证;
layerX: 当前点击位置距离当前点击元素(e.target,这里为box4)父级元素左边框左侧的距离值
我们验证一下,这次点击box2 左边框和box3左边框中间的位置:

可以看到,此时的offset值为20,正好是当前点击对象(box2)的左边框右侧位置到当前点击位置的距离。
而此时的layerX值为148,并不是当前点击位置距离当前点击对象父级元素box1的左边框左侧的距离值,与我们的猜想不符,我们看看MDN的说明:
The
UIEvent.layerXread-only property returns the horizontal coordinate of the event relative to the current layer.
UIEvent.layerX只读属性返回事件相对于当前层的水平坐标。This property takes scrolling of the page into account and returns a value relative to the whole of the document unless the event occurs inside a positioned element, where the returned value is relative to the top left of the positioned element.
此属性将页面滚动考虑在内,并返回一个相对于整个文档的值,除非事件发生在定位元素内,其中返回值相对于定位元素的左上角
按照该说明,这个属性返回事件相对于当前层的坐标,那么很明显,当前层并不是事件目标元素的父元素,对于层的概念,大概和盒子的渲染模型有关,没有深入研究过,鉴于这个属性并不是W3C标准属性,各个浏览器实现也没有统一标准,不再深究。
滚动的影响
为了验证滚动是否对offsetLeft的值,我们拖动box3的滚动条,然后同样点击box4的左边框位置,看下结果:

可以看到,滚动条滚动后,box4在页面上的绝对位置时改变了的,但是它(以及祖先元素)的offsetLeft属性并没有变化,得到
结论2: 滚动区域内的内容滚动后,其offsetLeft不受影响。
body元素定位
因为offsetLeft是相对于其offsetParent属性指向的元素(离它最新的定位祖先元素)的偏移量,所以必须研究当它的offsetParent发生改变时它的值的变化。首先,为body添加相对定位。
<body style="border: 20px solid #000; position: relative;">
使用变量控制实验法,仍旧点击box4的左边框,看看控制台输出:

这次比我们第一次点击,位置时相同的(clientX都是208),但是所有元素的offsetLeft的值都少了8px,而这正好是我们第一张图中标识的body元素左边框左侧到html边框的距离。
这种变化是因为一开始box4的祖先元素中没有定位元素,所以其默认定位元素时body,但此时的offsetLeft包含了body的margin-left值(在chrome中默认为8px),而此时body被明确定义为了定位元素,此时的offsetLeft则不再包含body的margin-left值。
我们在代码中把body的margin值去掉,来验证下以上说法:
<body style="border: 20px solid #000; position: relative;margin:0;">
然后再看:

这里没有了margin值,所以我们修正一下
结论1:当元素的祖先元素中没有定位元素时,offsetLeft 就是元素相对于其offsetParent所指向的元素(body)的左边框的左侧到元素左边框左侧的距离;
现在就有疑问了,根据offsetParent的特征,第一张图那里offsetParent明显也是body元素,为什么它定位和不定位会有包含不包含margin值的区别呢?
body取消定位,box1定位
<body style="border: 20px solid #000; margin:0;">
<div id="box1" style="border: 20px solid #666; width:300px; height:300px; padding-left:20px; margin-left:20px; position: relative;">
我们取消body元素的定位,给box1定位,此时,根据offsetParent的规则,box1/box2/box3的offsetParent应该是box1,我们点击相同位置,看输出结果:

此时,这些值都发生了变化:
box1当前的offsetParent还是body元素,所以其offsetLeft还是它的左边框左侧到body左边框左侧的距离(40),这个距离包含它自己的margin-left值。box2的offsetParent是box1,所以它的offsetLeft值是它的左边框左侧到box1左边框左侧的距离(60)减去它自己的margin-left值(20)之后的值(40)。box3的offsetParent是box1,所以它的offsetLeft值是它的左边框左侧到box1左边框左侧的距离(120)减去它自己的margin-left值(20)之后的值(100)。box4的offsetParent是box1,所以它的offsetLeft是它的左边框左侧到box1左边框左侧的距离 (160)减去 它自己的margin-left值(20)之后的值(140)。
我们得到了
结论3:当祖先元素中有定位元素时,元素的offsetLeft的值等于它的左边框左侧到它的offsetParent元素左边框的距离减去它自身的margin-left值。
元素自身为fixed定位
由于元素自身为fixed定位时,它的offsetParent总是为null,那么作为一个基于offsetParent的偏移量,元素的offsetLeft的结果又将是什么呢?
我们修改代码,在上一个例子的基础上,将box2的定位设为fiexd:
<body style="border: 20px solid #000; margin:0;">
<div id="box1" style="border: 20px solid #666; width:300px; height:300px; padding-left:20px; margin-left:20px; position: relative;">
<div id="box2" style="border: 20px solid #999; width:200px; height: 200px; padding-left:20px; margin-left:20px; position:fixed">
再次实验:

这次的结果变化比较有意思,我们逐一分析:
- 此时
box1的offsetParent仍旧是body元素,所以其offsetLeft还是它的左边框左侧到body左边框左侧的距离(40),这个距离包含它自己的margin-left值。 box2由于其自身是fiexd定位,我们可以看到它的offsetParent为null,可是它的offsetLeft却并不为null而是其左边框左侧到body左边框左侧的距离,这个距离包含它自己的margin-left值。box3的offsetParent此时变成离它最近的定位祖先元素box2,它的offsetLeft值则是它自己的左边框左侧到box2的左边框左侧的距离,减去它自己的margin-left值。box4的offsetParent此时也变成了box2,它的offsetLeft值是它自己的左边框左侧到box2的左边框左侧的距离,减去它自己的margin-left值。
我们得到
结论4:当元素自身为fixed定位时,它的offsetLeft值等于它自己的左边框左侧到body左边框左侧的距离,这个距离包含其自身的margin-left值
元素自身隐藏
根据offsetParent的规则,当元素自身的display为none时, 它的offsetParnt是null,那么它的offsetLeft会不会发生变化呢?
我们在上一个例子的基础上将box3的display设置为none:
<body style="border: 20px solid #000; margin:0;">
<div id="box1" style="border: 20px solid #666; width:300px; height:300px; padding-left:20px; margin-left:20px; position: relative;">
<div id="box2" style="border: 20px solid #999; width:200px; height: 200px; padding-left:20px; margin-left:20px; position: relative;">
<div id="box3" style="border: 20px solid [[bbb]];width:100px; height: 100px; padding-left:20px; margin-left: 20px; overflow:scroll; white-space: nowrap; display: none;">
此时由于box3 设置为了隐藏,所以box3和box4在页面上不可见了,我们无法再点击box4来进行试验,但是其实根据我们上面的试验,也同时发现,无论鼠标点击哪里,元素的offsetLeft值不会随着鼠标点击位置的不同而变化,所以我们就随意点击页面了,看下结果:

观察后发现:
box1与box2的offsetLeft仍旧遵循之前的规则box3与box4的offsetParent为null,而他们的offsetLeft为0
我们得到
结论5:当元素自身display为none时,它的offsetLeft值为0
至此,关于offsetLeft,我们得出了以下结论:
- 当元素的祖先元素中没有定位元素时,它的
offsetLeft值等于它自己的左边框左侧到body左边框左侧的距离,这个距离包含其自身的margin-left值。 - 当祖先元素中有定位元素时,元素的
offsetLeft的值等于它的左边框左侧到它的offsetParent元素左边框的距离减去它自身的margin-left值。 - 当元素自身为
fixed定位时,它的offsetLeft值等于它自己的左边框左侧到body左边框左侧的距离,这个距离包含其自身的margin-left值。 - 当元素自身
display为none时,它的offsetLeft值为0 - 滚动区域内的内容滚动后,内容所在元素的
offsetLeft值不受影响。
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/210925.html原文链接:https://javaforall.net
