JS動(dòng)畫的三大家族offset/scroll/client
我們知道,JS動(dòng)畫的三大家族包括:offset/scroll/client竞滓。
本文對(duì)三大家族以及與其相關(guān)的勻速動(dòng)畫講解
offset 家族的組成
offset的中文是:偏移橡娄,補(bǔ)償,位移蹲姐。
js中有一套方便的獲取元素尺寸的辦法就是offset家族阱表。offset家族包括:
- offsetWidth
- offsetHight
- offsetLeft
- offsetTop
- offsetParent
下面分別介紹。
1馁菜、offsetWidth 和 offsetHight
offsetWidth
和 offsetHight
:獲取元素的寬高 + padding + border茴扁,不包括margin。如下:
- offsetWidth = width + padding + border
- offsetHeight = Height + padding + border
這兩個(gè)屬性火邓,他們綁定在了所有的節(jié)點(diǎn)元素上丹弱。獲取元素之后,只要調(diào)用這兩個(gè)屬性铲咨,我們就能夠獲取元素節(jié)點(diǎn)的寬和高。
舉例如下:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
div {
width: 100px;
height: 100px;
padding: 10px;
border: 10px solid #000;
margin: 100px;
background-color: pink;
}
</style>
</head>
<body>
<div class="box"></div>
<script>
var div1 = document.getElementsByTagName("div")[0];
console.log(div1.offsetHeight); //打印結(jié)果:140(100+20+20)
console.log(typeof div1.offsetHeight); //打印結(jié)果:number
</script>
</body>
</html>
2蜓洪、offsetParent
offsetParent
:獲取當(dāng)前元素的定位父元素纤勒。
- 如果當(dāng)前元素的父元素,有CSS定位(position為absolute隆檀、relative摇天、fixed),那么
offsetParent
獲取的是最近的那個(gè)父元素恐仑。 - 如果當(dāng)前元素的父元素泉坐,沒有CSS定位(position為absolute、relative裳仆、fixed)腕让,那么
offsetParent
獲取的是body。
舉例:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div class="box1" style="position: absolute;">
<div class="box2" style="position: fixed;">
<div class="box3"></div>
</div>
</div>
<script>
var box3 = document.getElementsByClassName("box3")[0];
console.log(box3.offsetParent);
</script>
</body>
</html>
打印結(jié)果:
3歧斟、offsetLeft 和 offsetTop
offsetLeft
:當(dāng)前元素相對(duì)于其定位父元素的水平偏移量纯丸。
offsetTop
:當(dāng)前元素相對(duì)于其定位父元素的垂直偏移量。
備注:從父親的 padding 開始算起静袖,父親的 border 不算在內(nèi)觉鼻。
舉例:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
.box1 {
width: 300px;
height: 300px;
padding: 100px;
margin: 100px;
position: relative;
border: 100px solid #000;
background-color: pink;
}
.box2 {
width: 100px;
height: 100px;
background-color: red;
/*position: absolute;*/
/*left: 10px;*/
/*top: 10px;*/
}
</style>
</head>
<body>
<div class="box1">
<div class="box2" style="left: 10px"></div>
</div>
<script>
var box2 = document.getElementsByClassName("box2")[0];
//offsetTop和offsetLeft
console.log(box2.offsetLeft); //100
console.log(box2.style.left); //10px
</script>
</body>
</html>
在父盒子有定位的情況下,offsetLeft == style.left(去掉px之后)队橙。注意坠陈,后者只識(shí)別行內(nèi)樣式萨惑。但區(qū)別不僅僅于此,下面會(huì)講仇矾。
offsetLeft 和 style.left 區(qū)別
(1)最大區(qū)別在于:
offsetLeft 可以返回?zé)o定位父元素的偏移量庸蔼。如果父元素中都沒有定位,則body為準(zhǔn)若未。
style.left 只能獲取行內(nèi)樣式朱嘴,如果父元素中都沒有設(shè)置定位,則返回""(意思是粗合,返回空字符串);
(2)offsetTop 返回的是數(shù)字萍嬉,而 style.top 返回的是字符串,而且還帶有單位:px隙疚。
比如:
div.offsetLeft = 100;
div.style.left = "100px";
(3)offsetLeft 和 offsetTop 只讀壤追,而 style.left 和 style.top 可讀寫(只讀是獲取值,可寫是修改值)
總結(jié):我們一般的做法是:用offsetLeft 和 offsetTop 獲取值供屉,用style.left 和 style.top 賦值(比較方便)行冰。理由如下:
- style.left:只能獲取行內(nèi)式,獲取的值可能為空伶丐,容易出現(xiàn)NaN悼做。
- offsetLeft:獲取值特別方便,而且是現(xiàn)成的number哗魂,方便計(jì)算肛走。它是只讀的,不能賦值录别。
動(dòng)畫的種類
- 閃現(xiàn)(基本不用)
- 勻速(本文重點(diǎn))
- 緩動(dòng)(后續(xù)重點(diǎn))
簡單舉例如下:(每間隔500ms朽色,向右移動(dòng)盒子100px)
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
div {
width: 100px;
height: 100px;
background-color: pink;
position: absolute;
}
</style>
</head>
<body>
<button>動(dòng)畫</button>
<div class="box" style="left: 0px"></div>
<script>
var btn = document.getElementsByTagName("button")[0];
var div = document.getElementsByTagName("div")[0];
//1、閃動(dòng)
// btn.onclick = function () {
// div.style.left = "500px";
// }
//2组题、勻速運(yùn)動(dòng)
btn.onclick = function () {
//定時(shí)器葫男,每隔一定的時(shí)間向右走一些
setInterval(function () {
console.log(parseInt(div.style.left));
//動(dòng)畫原理: 盒子未來的位置 = 盒子現(xiàn)在的位置 + 步長;
//用style.left賦值崔列,用offsetLeft獲取值梢褐。
div.style.left = div.offsetLeft + 100 + "px";
//div.style.left = parseInt(div.style.left)+10+"px"; //NaN不能用
}, 500);
}
</script>
</body>
</html>
效果如下:
勻速動(dòng)畫的封裝:每間隔30ms,移動(dòng)盒子10px【重要】
代碼如下:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
.box1 {
margin: 0;
padding: 5px;
height: 300px;
background-color: #ddd;
position: relative;
}
button {
margin: 5px;
}
.box2 {
width: 100px;
height: 100px;
background-color: red;
position: absolute;
left: 195px;
top: 40px;
}
.box3 {
width: 100px;
height: 100px;
background-color: yellow;
position: absolute;
left: 0;
top: 150px;
}
</style>
</head>
<body>
<div class="box1">
<button>運(yùn)動(dòng)到 left = 200px</button>
<button>運(yùn)動(dòng)到 left = 400px</button>
<div class="box2"></div>
<div class="box3"></div>
</div>
<script>
var btnArr = document.getElementsByTagName("button");
var box2 = document.getElementsByClassName("box2")[0];
var box3 = document.getElementsByClassName("box3")[0];
//綁定事件
btnArr[0].onclick = function () {
//如果有一天我們要傳遞另外一個(gè)盒子峻呕,那么我們的方法就不好用了
//所以我們要增加第二個(gè)參數(shù)利职,被移動(dòng)的盒子本身。
animate(box2, 200);
animate(box3, 200);
}
btnArr[1].onclick = function () {
animate(box2, 400);
animate(box3, 400);
}
//【重要】方法的封裝:每間隔30ms瘦癌,將盒子向右移動(dòng)10px
function animate(ele, target) {
//要用定時(shí)器猪贪,先清除定時(shí)器
//一個(gè)盒子只能有一個(gè)定時(shí)器,這樣的話讯私,不會(huì)和其他盒子出現(xiàn)定時(shí)器沖突
//我們可以把定時(shí)器本身热押,當(dāng)成為盒子的一個(gè)屬性
clearInterval(ele.timer);
//我們要求盒子既能向前又能向后西傀,那么我們的步長就得有正有負(fù)
//目標(biāo)值如果大于當(dāng)前值取正,目標(biāo)值如果小于當(dāng)前值取負(fù)
var speed = target > ele.offsetLeft ? 10 : -10; //speed指的是步長
ele.timer = setInterval(function () {
//在執(zhí)行之前就獲取當(dāng)前值和目標(biāo)值之差
var val = target - ele.offsetLeft;
ele.style.left = ele.offsetLeft + speed + "px";
//移動(dòng)的過程中桶癣,如果目標(biāo)值和當(dāng)前值之差如果小于步長拥褂,那么就不能在前進(jìn)了
//因?yàn)椴介L有正有負(fù),所有轉(zhuǎn)換成絕對(duì)值來比較
if (Math.abs(val) < Math.abs(speed)) {
ele.style.left = target + "px";
clearInterval(ele.timer);
}
}, 30)
}
</script>
</body>
</html>
實(shí)現(xiàn)的效果:
上方代碼中的方法封裝牙寞,可以作為一個(gè)模板步驟饺鹃,要記住。其實(shí)间雀,這個(gè)封裝的方法悔详,寫成下面這樣,會(huì)更嚴(yán)謹(jǐn)惹挟,更容易理解:(將if語句進(jìn)行了改進(jìn))
//【重要】方法的封裝:每間隔30ms茄螃,將盒子向右移動(dòng)10px
function animate(ele, target) {
//要用定時(shí)器,先清除定時(shí)器
//一個(gè)盒子只能有一個(gè)定時(shí)器连锯,這樣的話归苍,不會(huì)和其他盒子出現(xiàn)定時(shí)器沖突
//我們可以把定時(shí)器本身,當(dāng)成為盒子的一個(gè)屬性
clearInterval(ele.timer);
//我們要求盒子既能向前又能向后运怖,那么我們的步長就得有正有負(fù)
//目標(biāo)值如果大于當(dāng)前值取正拼弃,目標(biāo)值如果小于當(dāng)前值取負(fù)
var speed = target > ele.offsetLeft ? 10 : -10; //speed指的是步長
ele.timer = setInterval(function () {
//在執(zhí)行之前就獲取當(dāng)前值和目標(biāo)值之差
var val = target - ele.offsetLeft;
//移動(dòng)的過程中,如果目標(biāo)值和當(dāng)前值之差如果小于步長摇展,那么就不能在前進(jìn)了
//因?yàn)椴介L有正有負(fù)肴敛,所有轉(zhuǎn)換成絕對(duì)值來比較
if (Math.abs(val) < Math.abs(speed)) { //如果val小于步長,則直接到達(dá)目的地吗购;否則,每次移動(dòng)一個(gè)步長
ele.style.left = target + "px";
clearInterval(ele.timer);
} else {
ele.style.left = ele.offsetLeft + speed + "px";
}
}, 30)
}
scroll 相關(guān)屬性
window.onscroll() 方法
當(dāng)我們用鼠標(biāo)滾輪砸狞,滾動(dòng)網(wǎng)頁的時(shí)候捻勉,會(huì)觸發(fā) window.onscroll() 方法。效果如下:(注意看控制臺(tái)的打印結(jié)果)
如果你需要做滾動(dòng)監(jiān)聽刀森,可以使用這個(gè)方法踱启。
我們來看看和 scroll 相關(guān)的有哪些屬性。
1研底、ScrollWidth 和 scrollHeight
ScrollWidth
和 scrollHeight
:獲取元素整個(gè)滾動(dòng)區(qū)域的寬埠偿、高。包括 width 和 padding榜晦,不包括 border和margin冠蒋。
注意:
scrollHeight
的特點(diǎn)是:如果內(nèi)容超出了盒子,scrollHeight
為內(nèi)容的高(包括超出的內(nèi)容)乾胶;如果不超出抖剿,scrollHeight
為盒子本身的高度朽寞。ScrollWidth
同理。
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
div {
width: 100px;
height: 100px;
padding: 10px;
margin: 3px;
border: 8px solid red;
}
</style>
</head>
<body>
<div class="box">
靜斩郎,能寒窗苦守脑融;動(dòng),能點(diǎn)石成金缩宜。
靜肘迎,能寒窗苦守;動(dòng)锻煌,能點(diǎn)石成金妓布。
靜,能寒窗苦守炼幔;動(dòng)秋茫,能點(diǎn)石成金。
靜乃秀,能寒窗苦守肛著;動(dòng),能點(diǎn)石成金跺讯。
靜枢贿,能寒窗苦守;動(dòng)刀脏,能點(diǎn)石成金局荚。
靜,能寒窗苦守愈污;動(dòng)耀态,能點(diǎn)石成金。
</div>
<script>
var div = document.getElementsByTagName("div")[0];
// `scrollHeight` 的特點(diǎn)是:如果內(nèi)容超出了盒子暂雹,`scrollHeight`為內(nèi)容的高(包括超出的內(nèi)容)首装;如果不超出,`scrollHeight`為盒子本身的高度杭跪。
//IE8以下(不包括IE8)仙逻,為盒子本身內(nèi)容的高度。
console.log(div.scrollWidth);
console.log(div.scrollHeight);
</script>
</body>
</html>
打印結(jié)果:
2涧尿、scrollTop 和 scrollLeft
-
scrollLeft
:獲取水平滾動(dòng)條滾動(dòng)的距離系奉。 -
scrollTop
:獲取垂直滾動(dòng)條滾動(dòng)的距離。
實(shí)戰(zhàn)經(jīng)驗(yàn):
當(dāng)某個(gè)元素滿足scrollHeight - scrollTop == clientHeight
時(shí)姑廉,說明垂直滾動(dòng)條滾動(dòng)到底了缺亮。
當(dāng)某個(gè)元素滿足scrollWidth - scrollLeft == clientWidth
時(shí),說明水平滾動(dòng)條滾動(dòng)到底了庄蹋。
這個(gè)實(shí)戰(zhàn)經(jīng)驗(yàn)非常有用瞬内,可以用來判斷用戶是否已經(jīng)將內(nèi)容滑動(dòng)到底了迷雪。比如說,有些場景下虫蝶,希望用戶能夠看完“長長的活動(dòng)規(guī)則”章咧,才允許觸發(fā)接下來的表單操作。
scrollTop 的兼容性
如果要獲取頁面滾動(dòng)的距離能真,scrollTop 這個(gè)屬性的寫法要注意兼容性赁严,如下。
(1)如果文檔沒有 DTD 聲明粉铐,寫法為:
document.body.scrollTop
在沒有 DTD 聲明的情況下疼约,要求是這種寫法,chrome瀏覽器才能認(rèn)出來蝙泼。
(2)如果文檔有 DTD 聲明程剥,寫法為:
document.documentElement.scrollTop
在有 DTD 聲明的情況下,要求是這種寫法汤踏,IE6织鲸、7、8才能認(rèn)出來溪胶。
綜合上面這兩個(gè)搂擦,就誕生了一種兼容性的寫法:
document.body.scrollTop || document.documentElement.scrollTop //方式一
document.body.scrollTop + document.documentElement.scrollTop //方式二
另外還有一種兼容性的寫法:window.pageYOffset
和 window.pageXOffset
。這種寫法無視DTD的聲明哗脖。這種寫法支持的瀏覽器版本是:火狐/谷歌/ie9+瀑踢。
綜合上面的幾種寫法,為了兼容才避,不管有沒有DTD橱夭,最終版的兼容性寫法:
window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop;
判斷是否已經(jīng) DTD 聲明
方法如下:
document.compatMode === "CSS1Compat" // 已聲明
document.compatMode === "BackCompat" // 未聲明
將 scrollTop 和 scrollLeft 進(jìn)行封裝
這里,我們將 scrollTop 和 scrollLeft 封裝為一個(gè)方法桑逝,名叫scroll()徘钥,返回值為 一個(gè)對(duì)象。以后就直接調(diào)用scroll().top
和 scroll().left
就好肢娘。
代碼實(shí)現(xiàn):
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
body {
height: 6000px;
width: 5000px;
}
</style>
</head>
<body>
<script>
//需求:封裝一個(gè)兼容的scroll().返回的是對(duì)象,用scroll().top獲取scrollTop舆驶,用scroll().left獲取scrollLeft
window.onscroll = function () {
// var myScroll = scroll();
// myScroll.top;
console.log(scroll().top);
console.log(scroll().left);
}
//函數(shù)封裝(簡單封裝橱健,實(shí)際工作使用)
function scroll() {
return { //此函數(shù)的返回值是對(duì)象
top: window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop,
left: window.pageXOffset || document.body.scrollLeft || document.documentElement.scrollLeft
}
}
</script>
</body>
</html>
上方代碼中,函數(shù)定義的那部分就是要封裝的代碼沙廉。
另外還有一種比較麻煩的封裝方式:(僅供參考)
function scroll() { // 開始封裝自己的scrollTop
if(window.pageYOffset !== undefined) { // ie9+ 高版本瀏覽器
// 因?yàn)?window.pageYOffset 默認(rèn)的是 0 所以這里需要判斷
return {
left: window.pageXOffset,
top: window.pageYOffset
}
}
else if(document.compatMode === "CSS1Compat") { // 標(biāo)準(zhǔn)瀏覽器 來判斷有沒有聲明DTD
return {
left: document.documentElement.scrollLeft,
top: document.documentElement.scrollTop
}
}
return { // 未聲明 DTD
left: document.body.scrollLeft,
top: document.body.scrollTop
}
}
獲取 html 文檔的方法
獲取title拘荡、body、head撬陵、html標(biāo)簽的方法如下:
-
document.title
文檔標(biāo)題珊皿; -
document.head
文檔的頭標(biāo)簽 -
document.body
文檔的body標(biāo)簽网缝; -
document.documentElement
(這個(gè)很重要)。
document.documentElement
表示文檔的html標(biāo)簽蟋定。也就是說粉臊,基本結(jié)構(gòu)當(dāng)中的 html 標(biāo)簽
而是通過document.documentElement
訪問的,并不是通過 document.html 去訪問的驶兜。
scrollTop 舉例:固定導(dǎo)航欄
完整版代碼實(shí)現(xiàn):
(1)index.html:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
* {
margin: 0;
padding: 0
}
img {
vertical-align: top;
}
.main {
margin: 0 auto;
width: 1000px;
margin-top: 10px;
}
#Q-nav1 {
overflow: hidden;
}
.fixed {
position: fixed;
top: 0;
left: 0;
}
</style>
<!--引入工具js-->
<script src="tools.js"></script>
<script>
window.onload = function () {
//需求1:當(dāng)我們滾動(dòng)界面的時(shí)候扼仲,被卷曲的頭部如果超過第二個(gè)盒子距離頂部的位置,那么直接給第二個(gè)盒子加類名.fixed
//需求2:當(dāng)我們滾動(dòng)界面的時(shí)候抄淑,被卷曲的頭部如果小于第二個(gè)盒子距離頂部的位置屠凶,那么直接給第二個(gè)盒子取消類名.fixed
//1.老三步。
var topDiv = document.getElementById("top");
var height = topDiv.offsetHeight;
var middle = document.getElementById("Q-nav1");
var main = document.getElementById("main");
window.onscroll = function () {
//2.判斷 肆资,被卷曲的頭部的大小
if (scroll().top > height) {
//3.滿足條件添加類矗愧,否則刪除類
middle.className += " fixed";
//第二個(gè)盒子也要占位置,為了避免重疊郑原,我們給第三個(gè)盒子一個(gè)上padding的空間唉韭,把這個(gè)空間留給第二個(gè)盒子
main.style.paddingTop = middle.offsetHeight + "px";
} else {
middle.className = "";
//清零
main.style.paddingTop = 0;
}
}
}
</script>
</head>
<body>
<div class="top" id="top">
<img src="images/top.png" alt=""/>
</div>
<div id="Q-nav1">
<img src="images/nav.png" alt=""/>
</div>
<div class="main" id="main">
<img src="images/main.png" alt=""/>
</div>
</body>
</html>
上方代碼中,有一個(gè)技巧:
main.style.paddingTop = middle.offsetHeight + "px";
仔細(xì)看注釋就好颤专。
(2)tools.js:
/**
* Created by smyhvae on 2018/02/03.
*/
function scroll() { // 開始封裝自己的scrollTop
if (window.pageYOffset !== undefined) { // ie9+ 高版本瀏覽器
// 因?yàn)?window.pageYOffset 默認(rèn)的是 0 所以這里需要判斷
return {
left: window.pageXOffset,
top: window.pageYOffset
}
}
else if (document.compatMode === "CSS1Compat") { // 標(biāo)準(zhǔn)瀏覽器 來判斷有沒有聲明DTD
return {
left: document.documentElement.scrollLeft,
top: document.documentElement.scrollTop
}
}
return { // 未聲明 DTD
left: document.body.scrollLeft,
top: document.body.scrollTop
}
}
實(shí)現(xiàn)效果:
緩動(dòng)動(dòng)畫
三個(gè)函數(shù)
緩慢動(dòng)畫里纽哥,我們要用到三個(gè)函數(shù),這里先列出來:
- Math.ceil() 向上取整
- Math.floor() 向下取整
- Math.round(); 四舍五入
緩動(dòng)動(dòng)畫的原理
緩動(dòng)動(dòng)畫的原理就是:在移動(dòng)的過程中栖秕,步長越來越小春塌。
設(shè)置步長為:目標(biāo)位置和盒子當(dāng)前位置的十分之一。用公式表達(dá)簇捍,即:
盒子位置 = 盒子本身位置 + (目標(biāo)位置 - 盒子本身位置)/ 10只壳;
代碼舉例:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
div {
width: 100px;
height: 100px;
background-color: pink;
position: absolute;
}
</style>
</head>
<body>
<button>運(yùn)動(dòng)到left = 400px</button>
<div></div>
<script>
var btn = document.getElementsByTagName("button")[0];
var div = document.getElementsByTagName("div")[0];
btn.onclick = function () {
setInterval(function () {
//動(dòng)畫原理:盒子未來的位置 = 盒子當(dāng)前的位置+步長
div.style.left = div.offsetLeft + (400 - div.offsetLeft) / 10 + "px";
}, 30);
}
</script>
</body>
</html>
效果:
緩慢動(dòng)畫的封裝(解決四舍五入的問題)
我們發(fā)現(xiàn)一個(gè)問題,上圖中的盒子最終并沒有到達(dá)400px的位置暑塑,而是只到了396.04px就停住了:
原因是:JS在取整的運(yùn)算時(shí)吼句,進(jìn)行了四舍五入。
我們把打印396.04px這個(gè)left值打印出來看看:
我么發(fā)現(xiàn)事格,通過div.style.left
獲取的值是精確的惕艳,通過div.offsetLeft
獲取的left值會(huì)進(jìn)行四舍五入。
此時(shí)驹愚,我們就要用到取整的函數(shù)了远搪。
通過對(duì)緩動(dòng)動(dòng)畫進(jìn)行封裝,完整版的代碼實(shí)現(xiàn)如下:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
div {
width: 100px;
height: 100px;
background-color: pink;
position: absolute;
left: 0;
}
</style>
</head>
<body>
<button>運(yùn)動(dòng)到200</button>
<button>運(yùn)動(dòng)到400</button>
<div></div>
<script>
var btn = document.getElementsByTagName("button");
var div = document.getElementsByTagName("div")[0];
btn[0].onclick = function () {
animate(div, 200);
}
btn[1].onclick = function () {
animate(div, 400);
}
//緩動(dòng)動(dòng)畫封裝
function animate(ele, target) {
//要用定時(shí)器逢捺,先清定時(shí)器
//一個(gè)蘿卜一個(gè)坑兒谁鳍,一個(gè)元素對(duì)應(yīng)一個(gè)定時(shí)器
clearInterval(ele.timer);
//定義定時(shí)器
ele.timer = setInterval(function () {
//獲取步長
//步長應(yīng)該是越來越小的,緩動(dòng)的算法。
var step = (target - ele.offsetLeft) / 10;
//對(duì)步長進(jìn)行二次加工(大于0向上取整,小于0向下取整)
//達(dá)到的效果是:最后10像素的時(shí)候都是1像素1像素的向目標(biāo)位置移動(dòng)倘潜,就能夠到達(dá)指定位置绷柒。
step = step > 0 ? Math.ceil(step) : Math.floor(step);
//動(dòng)畫原理: 目標(biāo)位置 = 當(dāng)前位置 + 步長
ele.style.left = ele.offsetLeft + step + "px";
console.log(step);
//檢測緩動(dòng)動(dòng)畫有沒有停止
console.log("smyhvae");
if (Math.abs(target - ele.offsetLeft) <= Math.abs(step)) {
//處理小數(shù)賦值
ele.style.left = target + "px";
clearInterval(ele.timer);
}
}, 30);
}
</script>
</body>
</html>
實(shí)現(xiàn)效果:
client 家族的組成
clientWidth 和 clientHeight
元素調(diào)用時(shí):
- clientWidth:獲取元素的可見寬度(width + padding)。
- clientHeight:獲取元素的可見高度(height + padding)涮因。
body/html 調(diào)用時(shí):
- clientWidth:獲取網(wǎng)頁可視區(qū)域?qū)挾取?/li>
- clientHeight:獲取網(wǎng)頁可視區(qū)域高度废睦。
聲明:
-
clientWidth
和clientHeight
屬性是只讀的,不可修改蕊退。 -
clientWidth
和clientHeight
的值都是不帶 px 的郊楣,返回的都是一個(gè)數(shù)字,可以直接進(jìn)行計(jì)算瓤荔。
clientX 和 clientY
event調(diào)用:
- clientX:鼠標(biāo)距離可視區(qū)域左側(cè)距離净蚤。
- clientY:鼠標(biāo)距離可視區(qū)域上側(cè)距離。
clientTop 和 clientLeft
- clientTop:盒子的上border输硝。
- clientLeft:盒子的左border今瀑。
三大家族 offset/scroll/client 的區(qū)別
區(qū)別1:寬高
- offsetWidth = width + padding + border
- offsetHeight = height + padding + border
- scrollWidth = 內(nèi)容寬度(不包含border)
- scrollHeight = 內(nèi)容高度(不包含border)
- clientWidth = width + padding
- clientHeight = height + padding
區(qū)別2:上左
offsetTop/offsetLeft:
- 調(diào)用者:任意元素。(盒子為主)
- 作用:距離父系盒子中帶有定位的距離点把。
scrollTop/scrollLeft:
- 調(diào)用者:document.body.scrollTop(window調(diào)用)(盒子也可以調(diào)用橘荠,但必須有滾動(dòng)條)
- 作用:瀏覽器無法顯示的部分(被卷去的部分)。
clientY/clientX:
- 調(diào)用者:event
- 作用:鼠標(biāo)距離瀏覽器可視區(qū)域的距離(左郎逃、上)哥童。
函數(shù)封裝:獲取瀏覽器的寬高(可視區(qū)域)
函數(shù)封裝如下:
//函數(shù)封裝:獲取屏幕可視區(qū)域的寬高
function client() {
if (window.innerHeight !== undefined) {
//ie9及其以上的版本的寫法
return {
"width": window.innerWidth,
"height": window.innerHeight
}
} else if (document.compatMode === "CSS1Compat") {
//標(biāo)準(zhǔn)模式的寫法(有DTD時(shí))
return {
"width": document.documentElement.clientWidth,
"height": document.documentElement.clientHeight
}
} else {
//沒有DTD時(shí)的寫法
return {
"width": document.body.clientWidth,
"height": document.body.clientHeight
}
}
}
案例:根據(jù)瀏覽器的可視寬度,給定不同的背景的色褒翰。
PS:這個(gè)可以用來做響應(yīng)式贮懈。
代碼如下:(需要用到上面的封裝好的方法)
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script src="tools.js"></script>
<script>
//需求:瀏覽器每次更改大小,判斷是否符合某一標(biāo)準(zhǔn)然后給背景上色优训。
// // >960紅色朵你,大于640小于960藍(lán)色,小于640綠色揣非。
window.onresize = fn; //頁面大小發(fā)生變化時(shí)抡医,執(zhí)行該函數(shù)。
//頁面加載的時(shí)候直接執(zhí)行一次函數(shù)早敬,確定瀏覽器可視區(qū)域的寬忌傻,給背景上色
fn();
//封裝成函數(shù),然后指定的時(shí)候去調(diào)用和綁定函數(shù)名
function fn() {
if (client().width > 960) {
document.body.style.backgroundColor = "red";
} else if (client().width > 640) {
document.body.style.backgroundColor = "blue";
} else {
document.body.style.backgroundColor = "green";
}
}
</script>
</body>
</html>
上當(dāng)代碼中搞监,window.onresize
事件指的是:在窗口或框架被調(diào)整大小時(shí)發(fā)生芯勘。各個(gè)事件的解釋如下:
- window.onscroll 屏幕滑動(dòng)
- window.onresize 瀏覽器大小變化
- window.onload 頁面加載完畢
- div.onmousemove 鼠標(biāo)在盒子上移動(dòng)(注意:不是盒子移動(dòng))
獲取顯示器的分辨率
比如,我的電腦的顯示器分辨率是:1920*1080腺逛。
獲取顯示器的分辨率:
window.onresize = function () {
document.title = window.screen.width + " " + window.screen.height;
}
顯示效果:
上圖中,不管我如何改變?yōu)g覽器的窗口大小,title欄顯示的值永遠(yuǎn)都是我的顯示器分辨率:1920*1080棍矛。