元素偏移量

hxyfdsal發表於2020-12-21

元素偏移量

1. 元素偏移量offset系列

1.1 offset概述

offset 翻譯過來就是偏移量, 我們使用 offset系列相關屬性可以動態的得到該元素的位置(偏移)、大小等。

  1. 獲得元素距離帶有定位父元素的位置,無論子元素是通過 margin、padding 還是絕對定位設定的與父元素的距離,都可以獲取
  2. 獲得元素自身的大小(寬度高度),使用js動態設定的寬度,也可以獲取
  3. 注意:返回的數值都不帶單位
offset系列屬性作用
element.offsetParent返回作為改元素帶有定位的父級元素如果父級都沒有定位則返回body
element.offsetTop返回元素相對帶有定位父元素上方的偏移
element.offsetLeft返回元素相對帶有定位父元素左邊框的偏移
element.offsetWidth返回自身包括padding、邊框、內容區的寬度,返回數值不帶單位
element.offsetHeight返回自身包括padding、邊框、內容區的高度,返回數值不帶單位

程式碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
	<style>
		* {
			margin: 0;
			padding: 0;
		}
		.parent {
			position: relative;
			width: 500px;
			height: 300px;
			margin: 100px;
			background-color: #ccc;
			padding-top: 50px;
		}
		.son {
			width: 200px;
			padding: 20px;
			height: 100px;
			background-color: orange;
			margin-left: 100px;
		}
		.daughter{
			position: absolute;
			left: 50px;
			top: 100px;
			width: 200px;
			height: 100px;
			background-color: red;
		}
		.sonBorder{
			border: 10px solid black;
		}
	</style>
</head>
<body>
	<div class="parent">
		<div class="son"></div>
		<div class="daughter"></div>
	</div>
	<script>
		/*
		* offsetTop 屬效能夠獲取當前元素距離父元素(有定位)的上邊框的距離,通過如下幾種方式設定的距離都可以獲取到
		1)通過子元素的 margin-top
		2)通過父元素的 padding-top
		3)通過絕對定位
		* offsetWidth 獲取的元素寬度為 width+padding+border
		*/
		var son = document.querySelector('.son')
		var daughter=document.querySelector('.daughter')
		// 元素距離父元素(一定要有定位)左邊框的距離
		console.log(son.offsetLeft);
		// 元素距離父元素(一定要有定位)上邊框的距離
		console.log(son.offsetTop);
		console.log(daughter.offsetLeft);
		// 獲取元素自身寬度
		console.log(son.offsetWidth);
		// 為元素動態新增寬度後,offsetWidth 還可以獲取馬
		son.addEventListener('click',function(){
			this.className=this.className+' sonBorder'
			console.log(son.offsetWidth);
		})
		// 返回父級元素
		console.log(son.offsetParent==daughter.offsetParent);
	</script>
</body>
</html>

1.2 offset於style區別

offset

  • offset 可以得到任意樣式表中的樣式值
  • offset 系列獲得的數值是沒有單位的
  • offsetWidth 包含padding+border+width
  • offsetWidth 等屬性是隻讀屬性,只能獲取不能賦值
  • 所以,我們想要獲取元素大小位置,用offset更合適

style

  • style 只能得到行內樣式表中的樣式值
  • style.width 獲得的是帶有單位的字串
  • style.width 獲得不包含padding和border 的值
  • style.width 是可讀寫屬性,可以獲取也可以賦值
  • 所以,我們想要給元素更改值,則需要用style改變

1.3案例:獲取滑鼠在盒子內的座標

  1. 我們在盒子內點選,想要得到滑鼠距離盒子左右的距離。
  2. 首先得到滑鼠在頁面中的座標(e.pageX, e.pageY)
  3. 其次得到盒子在頁面中的距離 ( box.offsetLeft, box.offsetTop)
  4. 用滑鼠距離頁面的座標減去盒子在頁面中的距離,得到 滑鼠在盒子內的座標
  5. 如果想要移動一下滑鼠,就要獲取最新的座標,使用滑鼠移動
var box = document.querySelector('.box');
box.addEventListener('mousemove', function(e) {
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
this.innerHTML = 'x座標是' + x + ' y座標是' + y;
})

1.4 案例:拖拽盒子

<!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>
			* {
				margin: 0;
				padding: 0;
			}

			.box {
				position: relative;
				width: 300px;
				height: 200px;
				border: 1px solid black;
				margin-left: 100px;
				background-color: orange;
			}
		</style>
	</head>
	<body>
		<div class="box">
		</div>
		<script>
			/* 思路
			* 1)在盒子內部按下滑鼠左鍵,在頁面中拖動,也就是說
			觸發盒子的 mousedown 事件,觸發頁面的 mouseover 事件
			* 2)滑鼠在頁面中移動時,計算滑鼠移動的距離,然後設定盒子位置加上
			這個距離
			**/
			var box = document.querySelector('.box')
			box.addEventListener('mousedown', function(event) {
				// 獲取滑鼠按下時的橫座標
				var old_x = event.pageX
				var old_y = event.pageY
				// 獲取盒子的左側距離
				var offsetLeft = this.offsetLeft
				var offsettop = this.offsetTop
				// console.log(offsettop)
				document.addEventListener('mousemove', move)

				function move(e) {
					// 獲取滑鼠在文件中移動時的新的橫座標
					var new_x = e.pageX
					var new_y = e.pageY
					// 計算滑鼠移動的x軸距離
					var x = new_x - old_x
					var y = new_y - old_y
					// console.log(y)
					// 設定盒子的 left 的值=原來left 的值+移動距離
					box.style.left = (offsetLeft + x - 100) + 'px'
					box.style.top = (offsettop + y) + 'px'
				}
				// 為盒子註冊 mouseup 事件
				document.addEventListener('mouseup', function() {
					// console.log('up');
					document.removeEventListener('mousemove', move)
				})
			})
		</script>
	</body>
</html>

1.5 案例:偽京東放大鏡

案例分析:

  1. 黃色的遮擋層跟隨滑鼠功能。
  2. 把滑鼠座標給遮擋層不合適。因為遮擋層座標以父盒子為準。
  3. 首先是獲得滑鼠在盒子的座標。
  4. 之後把數值給遮擋層做為left 和top值。
  5. 此時用到滑鼠移動事件,但是還是在小圖片盒子內移動。
  6. 發現,遮擋層位置不對,需要再減去盒子自身高度和寬度的一半。
  7. 遮擋層不能超出小圖片盒子範圍。
  8. 如果小於零,就把座標設定為0
  9. 如果大於遮擋層最大的移動距離,就把座標設定為最大的移動距離
  10. 遮擋層的最大移動距離:小圖片盒子寬度 減去 遮擋層盒子寬度
<!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>
			* {
				margin: 0;
				padding: 0;
			}

			.preview {
				width: 250px;
				height: 250px;
				border: 1px solid #ebebeb;
				margin: 50px 0 0 50px;
				text-align: center;
			}

			.preview_img {
				position: relative;
				width: 250px;
			}

			.mask {
				display: none;
				position: absolute;
				width: 150px;
				height: 150px;
				background-color: rgba(245, 201, 56, 0.4);
				top: 0;
				left: 0;
				border: 1px solid #ccc;
				margin: 50px 0 0 50px;
				cursor: move;
			}

			.big {
				display: none;
				position: absolute;
				width: 600px;
				height: 600px;
				left: 450px;
				top: 20px;
				z-index: 999;
				border: 1px solid #ccc;
				overflow: hidden;
			}

			.big_img {
				position: absolute;
				/*新增了定位才可以移動*/
				top: 0;
				left: 0;
				width: 1000px;
			}
		</style>
	</head>
	<body>
		<div class="preview">
			<img src="./xiao.jpg" alt="" class="preview_img">
			<div class="mask"></div>
			<div class="big">
				<img src="./xiao.jpg" alt="" class="big_img">
			</div>
		</div>
		<script>
			// 因為是外部的js,所以要等頁面載入完畢執行
			window.addEventListener('load', function() {
				var preview = document.querySelector('.preview');
				var mask = document.querySelector('.mask');
				var big = document.querySelector('.big');
				//1.當我們滑鼠經過preview就顯示和隱藏mask遮擋層和big大盒子
				preview.addEventListener('mouseover', function() {
					mask.style.display = 'block';
					big.style.display = 'block';
				})
				preview.addEventListener('mouseout', function() {
					mask.style.display = 'none';
					big.style.display = 'none';
				})
				//2.滑鼠移動事件
				preview.addEventListener('mousemove', function(e) {
					//(1)先計算出滑鼠在盒子內的座標
					var x = e.pageX - preview.offsetLeft;
					var y = e.pageY - preview.offsetTop;
					//(2)減去盒子寬度和高度的一半(x - mask.offsetWidth / 2)
					//(3)限制遮擋層移動範圍
					var maskX = x - mask.offsetWidth / 2;
					var maskY = y - mask.offsetHeight / 2;
					//遮擋層的最大移動距離
					var maskMax = preview.offsetWidth - mask.offsetWidth; //因為是正方形,width和height用一個就行
					if (maskX <= 0) {
						maskX = 0;
					} else if (maskX >= maskMax) {
						maskX = maskMax;
					}
					if (maskY <= 0) {
						maskY = 0;
					} else if (maskY >= maskMax) {
						maskY = maskMax;
					}
					mask.style.left = maskX + 'px';
					mask.style.top = maskY + 'px';
					//3.大圖片跟隨移動功能
					// 大圖片移動距離=遮擋層移動距離*大圖片最大移動距離/遮擋層最大移動距離
					var bigImg = document.querySelector('.big_img');
					//大圖片最大移動距離
					var bigMax = big.offsetWidth - bigImg.offsetWidth;
					//大圖片的移動距離
					var bigX = maskX * bigMax / maskMax;
					var bigY = maskY * bigMax / maskMax;
					bigImg.style.left = bigX + 'px'; //這個地方視訊上說加-號,我沒有加的效果是好的,不清楚?
					bigImg.style.top = bigY + 'px';
				})
			})
		</script>
	</body>
</html>

偽京東放大鏡

2. 元素可視區client系列

client概述

client 翻譯過來就是客戶端,我們使用 client 系列的相關屬性來獲取元素可視區的相關資訊。通過 client系列的相關屬性可以動態的得到該元素的邊框大小、元素大小等。

client系列屬性作用
element.clientTop返回元素上邊框的大小
element.clientLeft返回元素左邊框的大小
element.clientWidht返回自身包括padding、內容區的寬度,不含邊框,返回值不帶單位
element.clientHeight返回自身包括padding、內容區的高度,不含邊框,返回數值不帶單位

3 元素滾動scroll系列

3.1 scroll概述

scroll 翻譯過來就是滾動的,我們使用 scroll 系列的相關屬性可以動態的得到該元素的大小、滾動距離等。

scroll系列屬性作用
element.scrollTop返回被捲去的上側距離,返回數值不帶單位
element.scrollLeft返回被捲去的左側距離,返回數值不帶單位
element.scrollWidth返回自身實際的寬度,不含邊框,返回數值不帶單位
element.scrollHeight返回自身實際的高度,不含邊框,返回數值不帶單位

3.2 頁面被捲去的頭部相容性解決方案

需要注意的是,頁面被捲去的頭部,有相容性問題,因此被捲去的頭部通常有如下幾種寫法:

  1. 宣告瞭 DTD,使用 document.documentElement.scrollTop
  2. 未宣告 DTD,使用 document.body.scrollTop
  3. 新方法 window.pageYOffset和 window.pageXOffset,IE9 開始支援
function getScroll() {
	return {
		left: window.pageXOffset || document.documentElement.scrollLeft ||document.body. scrollLeft ||0,
		top: window.pageYOffset || document.documentElement.scrollTop ||document.body.scrollTop || 0
	};
}
使用的時候 getScroll().left

4 三大系列總結

三大系列大小對比作用
element.offsetWidth返回自身包括padding、邊框、內容區的寬度,返回數值不帶單位
element.clientWidth返回自身包括padding、內容區的寬度,不含邊框,返回數值不帶單位
element.scrollWidth返回自身實際的寬度,不含邊框,返回數值不帶單位

他們主要用法:

  1. offset系列 經常用於獲得元素位置 offsetLeft offsetTop
  2. client經常用於獲取元素大小 clientWidth clientHeight
  3. scroll 經常用於獲取滾動距離 scrollTop scrollLeft
  4. 注意頁面滾動的距離通過 window.pageXOffset 獲得

5.mouseenter和mouseover的區別

  • 當滑鼠移動到元素上時就會觸發mouseenter 事件
  • 類似 mouseover,它們兩者之間的差別是
  • mouseover 滑鼠經過自身盒子會觸發,經過子盒子還會觸發。mouseenter 只會經過自身盒子觸發
  • 之所以這樣,就是因為mouseenter不會冒泡
  • 跟mouseenter搭配滑鼠離開 mouseleave 同樣不會冒泡

6.動畫函式封裝

動畫函式給不同元素記錄不同定時器
如果多個元素都使用這個動畫函式,每次都要var 宣告定時器。我們可以給不同的元素使用不同的定時器(自己專門用自己的定時器)。
核心原理:利用 JS 是一門動態語言,可以很方便的給當前物件新增屬性。

function animate(obj, target) {
		// 當我們不斷的點選按鈕,這個元素的速度會越來越快,因為開啟了太多的定時器
		// 解決方案就是 讓我們元素只有一個定時器執行
		// 先清除以前的定時器,只保留當前的一個定時器執行
		clearInterval(obj.timer);
		obj.timer = setInterval(function() {
			if (obj.offsetLeft >= target) {
				// 停止動畫 本質是停止定時器
				clearInterval(obj.timer);
			}
			obj.style.left = obj.offsetLeft + 1 + 'px';
		}, 30);
	}

相關文章