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>