一、元素偏移量 offset 系列属性
1、offset 概述
offset系列属性可以动态的获得页面中某元素的偏移量,也就是元素位置,以及元素的宽度高度等属性。但是要注意,获得的元素的偏移量是元素相对于带有定位的父元素的位置,如果没有带定位的父元素,则是相对于页面的位置。而且获得的元素的宽度和高度是包括元素的border、padding的。最后所有属性的返回值都是数值型,不带单位,而且如果元素的offset系列属性是小数,如:22.5,则通过offset系列获取的值会向上取整。
2、offset系列属性
总结:
offsetWidth=width+padding+border
offsetHeight=height+padding+border
// 案例代码
// 获得鼠标指针在盒子内的坐标以及盒子的宽高
<div class="box"></div>
<script>
var box = document.querySelector('.box');
box.addEventListener('mousemove', function(e) {
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
var h = this.offsetHeight;
var w = this.offsetWidth;
this.innerHTML = 'x坐标是' + x + ' y坐标是' + y + '盒子高度是' + h + '盒子宽度是' + w;
})
</script>
3、offset和style的区别
① offset 可以获得任意样式表中元素的宽高等样式的值,而style只能获得行内样式表中的所有样式值。
② offsetWidth等属性获得样式值都是没有单位的数值型,而style.width等属性获得的样式值是带有单位的字符串型。
③ offsetWidth 包含padding+border+width ,而style.width 不包含padding和border 的值,只是width的值。
④ offsetWidth 等属性是只读属性,只能获取不能赋值,而style.width 是可读写属性,既可以获取也可以赋值。所以如果我们只是想获取元素大小位置,用offset;如果我们想更改元素的大小位置,用style。
二、元素可视区 client 系列
1、client概述
client 系列相关属性可以动态的获得元素可视区的相关信息,比如: 元素边框的大小、元素本身的大小等。获得的元素的宽度和高度是包括元素的padding但不包括元素的border的。而且所有属性的返回值都是数值型,不带单位。
2、client系列属性
总结:
clientWidth=width+padding
clientHeight=height+padding
// 案例代码
// 获得盒子的宽高以及上边框、左边框
<div class="box"></div>
<script>
var box = document.querySelector('.box');
var t = box.clientTop;
var l = box.clientLeft;
var h = box.clientHeight;
var w = box.clientWidth;
console.log('上边框的宽度'+ t + '左边框的宽度' + l + '高度(不包含border)' + h + '宽度(不包含border)' + w);
</script>
三、元素滚动scroll系列属性
1、scroll 概述
scroll 系列的相关属性可以动态的获得元素的大小、滚动距离等。获得的元素的宽度和高度是包括滚动条隐藏的部分以及显示出来的部分的实际的宽度和高度,而且包括元素的padding但不包含元素的border的。所有属性的返回值都是数值型,不带单位。
2、scroll 系列属性
总结:
scrollWidth=width+padding
scrollHeight=height+padding
// 案例代码
// 获得盒子的实际宽高以及元素被卷去的头部和左侧
<div class="box"></div>
<script>
var box = document.querySelector('.box');
var t = box.scrollTop;
var l = box.scrollLeft;
var h = box.scrolHeight;
var w = box.scrollWidth;
console.log('元素被卷去的头部'+ t + '元素被卷去的左侧' + l + '实际高度(不包含border)' + h + '实际宽度(不包含border)' + w);
</script>
3、页面滚动
如果浏览器的高度或者宽度小于页面的高度或宽度,窗口就会自动出现滚动条。当页面开始滚动时,页面被隐藏掉的高度,我们就称为页面被卷去的头部。而且页面滚动时会触发 scroll 事件,因为是页面滚动,所以事件源是document。
注意:页面被卷去的头部和元素被卷去的头部是不一样的。元素被卷去的头部通过 element.scrollTop 获得,页面被卷去的头部通过 window.pageYOffset 获得。同理,元素被卷去的左侧是 element.scrollLeft ,页面被卷去的左侧是 window.pageXOffset 。而且可以通过 window.scroll(x,y) 方法直接滚动到页面的某个位置。
后续补充:
Window.scrollTo(x,y) : 滚动到页面的某个坐标中去,与window.scroll(x,y) 作用相同,两个参数都为数字型,分别是文档中的横轴坐标和文档中的纵轴坐标。但是该方法有第二种形式的参数,window.scrollTo(options),options包含三个属性:top - 相对于页面顶部的距离,相当于前面的 y、left - 相对于页面左侧的距离,相当于前面的 x、behavior - 类型String,表示滚动行为动画,支持参数 smooth(平滑滚动),instant(瞬间滚动),默认值auto,auto的效果与instant相同。比window.scroll() 的优秀之处就在于平滑的滚动动画,可以应用于页面的导航跳转等场景。
但是该方法的window.scrollTo(options)
形式在IE11及以下版本不兼容,只支持Window.scrollTo(x,y)
形式,所以要相兼容IE则需要做好兼容性处理:
// 解决scrollTo behavior 缓动动画不兼容问题
// 判断document中是否存在scrollBehavior属性 存在则支持缓动动画 否则不支持
const supportsNativeSmoothScroll = 'scrollBehavior' in document.documentElement.style
if (supportsNativeSmoothScroll) {
console.log('这里支持缓动动画')
window.scrollTo({
top: 100,
behavior: 'smooth'
})
} else {
console.log('这里不支持缓动动画')
window.scrollTo(0, 100)
}
而且该方法的滚动动画在ios中不兼容,滚动行为兼容,会议瞬间滚动的形式呈现。如果想要在ios中兼容滚动动画可以通过下面的方法:
// 前提:Vue项目 或 Nuxt项目
// 1、安装转插件
yarn add smoothscroll-polyfill 或者 npm i smoothscroll-polyfill
// 2、在需要滚动效果的页面引入
import smoothscroll from 'smoothscroll-polyfill';
// 3、在点击滚动到页面某位置的事件中 执行下面方法
smoothscroll.polyfill();
四、总结
主要应用场景:
-
offset系列 通常应用于获得元素的位置, offsetLeft offsetTop。
-
client系列 通常应用于获得元素的大小 ,clientWidth clientHeight。
-
scroll系列 通常应用于获取元素的滚动距离, scrollTop scrollLeft 。
-
页面的滚动距离通过
window.pageYOffset
和window.pageXOffset
获得。 -
都有一个共同点,返回值都是数字且不带单位。
-
获取页面在Y轴上的滚动距离,可以通过
window.pageYOffset
、document.documentElement.scrollTop
、document.body.scrollTop
三种方式。
后续补充:
1、不同浏览器兼容获取页面在Y轴上的滚动距离的方法:
① IE8及以下:支持 document.documentElement.scrollTop
。
② IE9及以上:支持 document.documentElement.scrollTop
和 window.pageYOffset
。
③ Safari:支持document.body.scrollTop
和 window.pageYOffset
。
④ Chrome: 支持document.body.scrollTop(低版本,已验证的有:Chrome/55.0)
、document.documentElement.scrollTop(高版本,已验证的有:Chrome/63.0)
和 window.pageYOffset
。
⑤ Firefox: 支持 document.documentElement.scrollTop
和 window.pageYOffset
。
2、兼容写法:
// 无论移动端还是pc都可以兼容
let scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
因为这两个方法有个特殊点,就是同时只会有一个值生效。比如document.body.scrollTop能取到值的时候,document.documentElement.scrollTop就会始终为0;反之亦然。所以可通过该特性来兼容的获取 scrollTop 的值。
3、踩坑经历:
最近写了一个移动端的h5页面,是嵌入到app里面的,安卓端使用的document.documentElement.scrollTop
没有任何问题,但是ios端document.documentElement.scrollTo
的值一直是0,于是改用document.body.scrollTop
,在我测试的6p机型上兼容了,于是我信心满满的提测了,但是过了一会儿测试提刀上门了…
发现6s机型和XR机型,document.body.scrollTop
不起作用,应该是不兼容。最后还是使用了上面的兼容写法,才得以从测试的刀下逃生。所以建议大家都是用兼容写法。
五、仿淘宝侧边栏综合案例
案例要求:
- 原先侧边栏是绝对定位
- 当页面滚动到一定位置,侧边栏改为固定定位
- 页面继续滚动,会让 返回顶部显示出来
案例代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.slider-bar {
position: absolute;
left: 50%;
top: 300px;
margin-left: 600px;
width: 45px;
height: 130px;
background-color: pink;
}
.w {
width: 1200px;
margin: 10px auto;
}
.header {
height: 150px;
background-color: purple;
}
.banner {
height: 250px;
background-color: skyblue;
}
.main {
height: 1000px;
background-color: yellowgreen;
}
span {
display: none;
position: absolute;
bottom: 0;
}
</style>
</head>
<body>
<div class="slider-bar">
<span class="goBack">返回顶部</span>
</div>
<div class="header w">头部区域</div>
<div class="banner w">banner区域</div>
<div class="main w">主体部分</div>
<script>
//1. 获取元素
var sliderbar = document.querySelector('.slider-bar');
var banner = document.querySelector('.banner');
// banner.offestTop 就是被卷去头部的大小 一定要写到滚动的外面
var bannerTop = banner.offsetTop
// 当我们侧边栏固定定位之后应该变化的数值
var sliderbarTop = sliderbar.offsetTop - bannerTop;
// 获取main 主体元素
var main = document.querySelector('.main');
var goBack = document.querySelector('.goBack');
var mainTop = main.offsetTop;
// 2. 页面滚动事件 scroll
document.addEventListener('scroll', function() {
// console.log(11);
// window.pageYOffset 页面被卷去的头部
// console.log(window.pageYOffset);
// 3 .当我们页面被卷去的头部大于等于了 172 此时 侧边栏就要改为固定定位
if (window.pageYOffset >= bannerTop) {
sliderbar.style.position = 'fixed';
sliderbar.style.top = sliderbarTop + 'px';
} else {
sliderbar.style.position = 'absolute';
sliderbar.style.top = '300px';
}
// 4. 当我们页面滚动到main盒子,就显示 goback模块
if (window.pageYOffset >= mainTop) {
goBack.style.display = 'block';
} else {
goBack.style.display = 'none';
}
})
goBack.addEventListener('click',function () {
// window.scroll(x,y); x y 代表页面的坐标
// 直接跳到页面顶部
window.scroll(0,0);
});
</script>
</body>
</html>