9.offset、client、scroll 系列
大约 10 分钟学习笔记前端基础JavaScript
一、 网页偏移量 offset
系列
offset
: 网页偏移量,动态获取 该元素的 位置及大小等
注意:
- 获取元素距离带有定位父元素的位置
- 获取元素自身的大小(宽度和高度)
- 返回 的数值没有单位
常用属性:
属性 | 作用 |
---|---|
element.offsetParent | 返回作为该元素的带有定位的父级元素, 如果父级都没有定位,则返回 body |
element.offsetTop | 返回元素 相对带有定位的,父元素上方的偏移 |
element.offsetLeft | 返回元素 相对带有定位的,父元素左边框的偏移 |
element.offsetWidth | 返回自身包括 padding 、 边框 、 内容区的宽度(不带单位) |
element.offsetHeight | 返回自身包括 padding 、 边框 、 内容区的高度(不带单位) |
HTML
<div class="father">
<div class="son"></div>
</div>
<div class="w"></div>
<script>
// offset 系列
var father = document.querySelector('.father');
var son = document.querySelector('.son');
// 1.可以得到元素的偏移 位置 返回的不带单位的数值
console.log(father.offsetTop); // 150
console.log(father.offsetLeft); // 150
// 它以带有定位的父亲为准 如果么有父亲或者父亲没有定位 则以 body 为准
console.log(son.offsetLeft); // 45
var w = document.querySelector('.w');
// 2.可以得到元素的大小 宽度和高度 是包含padding + border + width
console.log(w.offsetWidth);
console.log(w.offsetHeight);
// 3. 返回带有定位的父亲 否则返回的是body
console.log(son.offsetParent); // 返回带有定位的父亲 否则返回的是body
console.log(son.parentNode); // 返回父亲 是最近一级的父亲 亲爸爸 不管父亲有没有定位
</script>
CSS
* {
margin: 0;
padding: 0;
}
.father {
/* position: relative; */
width: 200px;
height: 200px;
background-color: pink;
margin: 150px;
}
.son {
width: 100px;
height: 100px;
background-color: purple;
margin-left: 45px;
}
.w {
height: 200px;
background-color: skyblue;
margin: 0 auto 200px;
padding: 10px;
border: 15px solid red;
}
offset 和 style 的区别
offset(用于获取元素大小、位置) | style(用于更改元素样式) |
---|---|
offset 可以得到任意样式表中的样式值 | style 只能得到行内样式表中的样式值 |
offset 获得的值 没有单位 | style.width 获得的是带有单位的字符串 |
offsetWidth 包含 padding+border+width | style.width 获得不包含 padding 和 border 的值 |
offsetWidth 等属性是 只读属性 只能获取不能复制 | style.width 是可读可写属性, 可以获取,也可以赋值 |
案例 --- 动态获取 鼠标在盒子中的坐标
详情
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<style type="text/css">
.demo{
margin: 100px auto;
width: 200px;
height: 200px;
background-color: #55ffff;
}
</style>
</head>
<body>
<div class="demo"></div>
<script type="text/javascript">
var div = document.querySelector('.demo');
div.addEventListener('mousemove', function (e) {
var x = e.pageX - div.offsetLeft;
var y = e.pageY - div.offsetTop;
div.innerHTML = 'x 坐标为:'+ x + '<br> y 坐标为:' + y;
})
</script>
</body>
</html>
案例 --- 模态框的拖拽
详情
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
* {
padding: 0px;
margin: 0px;
}
.login-header {
width: 100%;
text-align: center;
height: 30px;
font-size: 24px;
line-height: 30px;
}
.login {
display: none;
width: 512px;
height: 280px;
position: fixed;
border: #ebebeb solid 1px;
left: 50%;
top: 50%;
background: #ffffff;
box-shadow: 0px 0px 20px #ddd;
z-index: 9999;
transform: translate(-50%, -50%);
}
.login-title {
width: 100%;
margin: 10px 0px 0px 0px;
text-align: center;
line-height: 40px;
height: 40px;
font-size: 18px;
position: relative;
cursor: move;
}
.login-input-content {
margin-top: 20px;
}
.login-button {
width: 50%;
margin: 30px auto 0px auto;
line-height: 40px;
font-size: 14px;
border: #ebebeb 1px solid;
text-align: center;
}
.login-bg {
display: none;
width: 100%;
height: 100%;
position: fixed;
top: 0px;
left: 0px;
background: rgba(0, 0, 0, .3);
}
a {
text-decoration: none;
color: #000000;
}
.login-button a {
display: block;
}
.login-input input.list-input {
float: left;
line-height: 35px;
height: 35px;
width: 350px;
border: #ebebeb 1px solid;
text-indent: 5px;
}
.login-input {
overflow: hidden;
margin: 0px 0px 20px 0px;
}
.login-input label {
float: left;
width: 90px;
padding-right: 10px;
text-align: right;
line-height: 35px;
height: 35px;
font-size: 14px;
}
.login-title span {
position: absolute;
font-size: 12px;
right: -20px;
top: -30px;
background: #ffffff;
border: #ebebeb solid 1px;
width: 40px;
height: 40px;
border-radius: 20px;
}
</style>
</head>
<body>
<div class="login-header"><a id="link" href="javascript:;">点击,弹出登录框</a></div>
<div id="login" class="login">
<div id="title" class="login-title">登录会员
<span><a id="closeBtn" href="javascript:void(0);" class="close-login">关闭</a></span>
</div>
<div class="login-input-content">
<div class="login-input">
<label>用户名:</label>
<input type="text" placeholder="请输入用户名" name="info[username]" id="username" class="list-input">
</div>
<div class="login-input">
<label>登录密码:</label>
<input type="password" placeholder="请输入登录密码" name="info[password]" id="password" class="list-input">
</div>
</div>
<div id="loginBtn" class="login-button"><a href="javascript:void(0);" id="login-button-submit">登录会员</a></div>
</div>
<!-- 遮盖层 -->
<div id="bg" class="login-bg"></div>
<script>
// 1. 获取元素
var login = document.querySelector('.login');
var mask = document.querySelector('.login-bg');
var link = document.querySelector('#link');
var closeBtn = document.querySelector('#closeBtn');
var title = document.querySelector('#title');
// 2. 点击弹出层这个链接 link 让mask 和login 显示出来
link.addEventListener('click', function () {
mask.style.display = 'block';
login.style.display = 'block';
})
// 3. 点击 closeBtn 就隐藏 mask 和 login
closeBtn.addEventListener('click', function () {
mask.style.display = 'none';
login.style.display = 'none';
})
// 4. 开始拖拽
// (1) 当我们鼠标按下, 就获得鼠标在盒子内的坐标
title.addEventListener('mousedown', function (e) {
var x = e.pageX - login.offsetLeft;
var y = e.pageY - login.offsetTop;
// (2) 鼠标移动的时候,把鼠标在页面中的坐标,减去 鼠标在盒子内的坐标就是模态框的left和top值
document.addEventListener('mousemove', move)
function move(e) {
login.style.left = e.pageX - x + 'px';
login.style.top = e.pageY - y + 'px';
}
// (3) 鼠标弹起,就让鼠标移动事件移除
document.addEventListener('mouseup', function () {
document.removeEventListener('mousemove', move);
})
})
</script>
</body>
</html>
案例 --- 放大镜
详情
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
* {
padding: 0px;
margin: 0px;
}
.demo {
margin-top: 100px;
margin-left: 100px;
width: 400px;
height: 400px;
border: 2px solid #ccc;
}
.box {
width: 400px;
height: 400px;
position: relative;
}
.box img {
width: 100%;
height: 100%;
}
.box span {
display: none;
position: absolute;
left: 0;
top: 0;
width: 70%;
height: 70%;
background: rgba(245, 132, 3, 0.3);
}
.big {
display: none;
position: absolute;
left: 505px;
top: 100px;
width: 500px;
height: 500px;
border: 2px solid #ccc;
overflow: hidden;
}
.big img {
position: absolute;
}
</style>
</head>
<body>
<div class="demo">
<div class="box">
<img src="https://img.pupper.cn/img/202112281645931.png" alt="">
<span></span>
</div>
<div class="big">
<img src="https://img.pupper.cn/img/202112281645385.png" alt="">
</div>
</div>
<script>
var box = document.querySelector('.box')
var sp = box.querySelector('span')
var big = document.querySelector('.big');
var big_img = big.querySelector('img');
// 鼠标进过,盒子显示
box.addEventListener('mouseover', function () {
sp.style.display = 'block';
big.style.display = 'block';
})
// 鼠标离开, 盒子隐藏
box.addEventListener('mouseout', function () {
sp.style.display = 'none';
big.style.display = 'none';
})
// 移动 遮罩小图
box.addEventListener('mousemove', function (e) {
// 鼠标在盒子中的位置
var x = e.pageX - box.offsetLeft;
var y = e.pageY - box.offsetTop;
// 将鼠标置于 遮罩的中心位置,其计算结果为遮罩的实际位置
var sp_x = x - sp.offsetWidth / 2;
var sp_y = y - sp.offsetHeight / 2;
// 遮罩最大移动距离, 因为是正方形,所以x y 移动距离 一致
var sp_max = box.offsetWidth - sp.offsetWidth;
// 使遮罩始终保持在 盒子中移动
if(sp_x < 0){
sp_x = 0;
}else if (sp_x > sp_max){
sp_x = sp_max;
}
if(sp_y < 0){
sp_y = 0;
}else if (sp_y > sp_max){
sp_y = sp_max;
}
sp.style.left = sp_x + 'px';
sp.style.top = sp_y + 'px';
// 大图片的移动距离 = 遮挡层移动距离 * 大图片最大移动距离 / 遮挡层的最大移动距离
// 大图 最大移动距离
var big_max = big_img.offsetWidth - big.offsetWidth;
// 大图移动距离 x y
var bigx = sp_x * big_max / sp_max;
var bigy = sp_y * big_max / sp_max;
big_img.style.left = -bigx + 'px';
big_img.style.top = -bigy + 'px';
})
</script>
</body>
</html>
二、 client
系列
client
: 客户端,用于获取元素可视区的相关信息,通过 client 相关属性可以动态得到元素的大小、边框大小等。
属性 | 作用 |
---|---|
element.clientTop | 返回元素 上边框的大小 |
element.clientLeft | 返回元素 左边框的大小 |
element.clientWidth | 返回元素 自身包括 padding、内容区宽度, 不包含边框,返回值 不带单位 |
element.clientHeight | 返回元素 自身包括 padding 、内容区高度, 不包含边框,返回值不带单位 |
立即执行函数
立即执行函数 : 不需要调用,立即能够自己执行的函数
写法:
(function () {})();
或者((function () {})());
示例:
(function (a, b) {
console.log(a + b);
})(1, 2); // 3
(function (a, b) {
console.log(a + b);
})(1, 2); // 3
注意:
- 立即执行函数 可以命名,也可以传参数;
- 多个立即执行函数时,需要用 ';' 分号隔开;
- 立即执行函数 是一个独立的作用域,里面的变量都是局部变量,不存在命名冲突;
三、 scroll
系列
scroll
: 滚动,使用相关属性可以动态的获得元素的大小、滚动距离等
属性 | 作用 |
---|---|
element.scrollTop | 返回 被卷去的上侧距离,返回值不带单位 |
element.scrollLeft | 返回 被卷去的 左侧距离,返回值不带单位 |
element.scrollWidth | 返回 自身实际的宽度,不包含边框,返回值不带单位 |
element.scrollHeight | 返回 自身实际的高度,不包含边框,返回值不带单位 |
注意
元素被卷曲使用 : element.scrollTop
、element.scrollLeft
页面被卷去使用 : window.pageYOffset
、 window.pageXOffset
案例 --- 返回顶部按钮
详情
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
* {
padding: 0px;
margin: 0px;
}
.demo {
/* position: relative; */
margin: 5px auto;
width: 600px;
}
.handr {
width: 100%;
height: 100px;
background-color: aquamarine;
}
.banner {
width: 100%;
height: 500px;
margin-top: 10px;
background-color: chocolate;
}
.bodyr {
width: 100%;
height: 800px;
margin-top: 10px;
background-color: #00A4FF;
}
.loos {
position: absolute;
right: 35px;
top: 200px;
width: 50px;
height: 100px;
background-color: chartreuse;
}
.loos span {
display: none;
}
</style>
</head>
<body>
<div class="demo">
<div class="handr"></div>
<div class="banner"></div>
<div class="bodyr"></div>
<div class="loos">
<span>返回顶部</span>
</div>
</div>
<script>
var loos = document.querySelector('.loos')
var banner = document.querySelector('.banner')
var bodyr = document.querySelector('.bodyr')
var span = loos.querySelector('span')
// banner 距离页面顶部的高度
var bannertop = banner.offsetTop
// 返回块 停止的位置
var loostop = loos.offsetTop - bannertop
// body 距离页面顶部的高度
var bodyrtop = bodyr.offsetTop;
// 页面滚动事件
document.addEventListener('scroll', function() {
if (window.pageYOffset >= bannertop) {
// 固定定位 是以 浏览器可视区域为参考的
// 绝对定位 是以 有定位的父元素 为参考的
loos.style.position = 'fixed';
loos.style.top = loostop + 'px';
} else {
loos.style.position = 'absolute';
loos.style.top = '200px';
}
if (window.pageYOffset >= bodyrtop) {
span.style.display = 'block'
} else {
span.style.display = 'none'
}
})
</script>
</body>
</html>
四、 三大系列的总结
对比 | 作用 |
---|---|
element.offsetWidth | 返回自身包括 padding、 内容区的宽度、边框,返回值不带单位 |
element.clientWidth | 返回自身包括 padding、 内容区的宽度,不含边框,返回值不带单位 |
element.scrollWidth | 返回自身实际的宽度,不含边框, 返回值不带单位 |
1. 作用
offset
系列,经常用于获得元素的 位置 (offsetLeft
、offsetTop
)client
系列,经常用于获取元素的 大小 (clientWidth
、clientHeight
)scroll
系列,经常用于获取 滚动的 距离 (scrollTop
、scrollLeft
)- 页面的滚动距离 通过
window.pageXOffset
获得
五、 mouseenter
和 mouseover
的区别
mouseover
: 鼠标经过父盒子和子盒子时,都会打印;
mouseeenter
: 鼠标经过父盒子会打印,子盒子不会打印(因为 它不会冒泡)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.father {
width: 300px;
height: 300px;
background-color: pink;
margin: 100px auto;
}
.son {
width: 200px;
height: 200px;
background-color: purple;
}
</style>
</head>
<body>
<div class="father">
<div class="son"></div>
</div>
<script>
var father = document.querySelector('.father');
var son = document.querySelector('.son');
// 父盒子、子盒子都会打印
father.addEventListener('mouseover', function() {
console.log(11);
})
// 只有父盒子会打印
father.addEventListener('mouseenter', function() {
console.log(11);
})
</script>
</body>
</html>