前言
DOM&BOM基礎(chǔ)是很重要前端知識(shí),在這里我準(zhǔn)備了所有相關(guān)知識(shí)的概念描述以及示例Demo,連載7篇,和大家一起溫故而知新,覆蓋每一個(gè)知識(shí)點(diǎn),相信在以后的開(kāi)發(fā)和面試中你總會(huì)用到它。
自定義 animate.js 動(dòng)畫函數(shù)
function animate(obj, target, callback) {
// console.log(callback); callback = function() {} 調(diào)用的時(shí)候 callback()
// 先清除以前的定時(shí)器,只保留當(dāng)前的一個(gè)定時(shí)器執(zhí)行
clearInterval(obj.timer);
obj.timer = setInterval(function() {
// 步長(zhǎng)值寫到定時(shí)器的里面
// 把我們步長(zhǎng)值改為整數(shù) 不要出現(xiàn)小數(shù)的問(wèn)題
// var step = Math.ceil((target - obj.offsetLeft) / 10);
var step = (target - obj.offsetLeft) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
if (obj.offsetLeft == target) {
// 停止動(dòng)畫 本質(zhì)是停止定時(shí)器
clearInterval(obj.timer);
// 回調(diào)函數(shù)寫到定時(shí)器結(jié)束里面
// if (callback) {
// // 調(diào)用函數(shù)
// callback();
// }
callback && callback();
}
// 把每次加1 這個(gè)步長(zhǎng)值改為一個(gè)慢慢變小的值 步長(zhǎng)公式:(目標(biāo)值 - 現(xiàn)在的位置) / 10
obj.style.left = obj.offsetLeft + step + 'px';
}, 15);
}
自定義 flexible.js 函數(shù)
(function flexible(window, document) {
var docEl = document.documentElement
var dpr = window.devicePixelRatio || 1
// adjust body font size
function setBodyFontSize() {
if (document.body) {
document.body.style.fontSize = (12 * dpr) + 'px'
} else {
document.addEventListener('DOMContentLoaded', setBodyFontSize)
}
}
setBodyFontSize();
// set 1rem = viewWidth / 10
function setRemUnit() {
var rem = docEl.clientWidth / 10
docEl.style.fontSize = rem + 'px'
}
setRemUnit()
// reset rem unit on page resize
window.addEventListener('resize', setRemUnit)
window.addEventListener('pageshow', function(e) {
if (e.persisted) {
setRemUnit()
}
})
// detect 0.5px supports
if (dpr >= 2) {
var fakeBody = document.createElement('body')
var testElement = document.createElement('div')
testElement.style.border = '.5px solid transparent'
fakeBody.appendChild(testElement)
docEl.appendChild(fakeBody)
if (testElement.offsetHeight === 1) {
docEl.classList.add('hairlines')
}
docEl.removeChild(fakeBody)
}
}(window, document))
動(dòng)畫原理
<head>
<style>
div {
position: absolute;
left: 0;
width: 100px;
height: 100px;
background-color: pink;
}
</style>
</head>
<body>
<div></div>
<script>
// 動(dòng)畫原理
// 1. 獲得盒子當(dāng)前位置
// 2. 讓盒子在當(dāng)前位置加上1個(gè)移動(dòng)距離
// 3. 利用定時(shí)器不斷重復(fù)這個(gè)操作
// 4. 加一個(gè)結(jié)束定時(shí)器的條件
// 5. 注意此元素需要添加定位, 才能使用element.style.left
var div = document.querySelector('div');
var timer = setInterval(function() {
if (div.offsetLeft >= 400) {
// 停止動(dòng)畫 本質(zhì)是停止定時(shí)器
clearInterval(timer);
}
div.style.left = div.offsetLeft + 1 + 'px';
}, 30);
</script>
</body>
</html>
簡(jiǎn)單動(dòng)畫函數(shù)封裝
<head>
<style>
div {
position: absolute;
left: 0;
width: 100px;
height: 100px;
background-color: pink;
}
span {
position: absolute;
left: 0;
top: 200px;
display: block;
width: 150px;
height: 150px;
background-color: purple;
}
</style>
</head>
<body>
<div></div>
<span>夏雨荷</span>
<script>
// 簡(jiǎn)單動(dòng)畫函數(shù)封裝obj目標(biāo)對(duì)象 target 目標(biāo)位置
function animate(obj, target) {
var timer = setInterval(function() {
if (obj.offsetLeft >= target) {
// 停止動(dòng)畫 本質(zhì)是停止定時(shí)器
clearInterval(timer);
}
obj.style.left = obj.offsetLeft + 1 + 'px';
}, 30);
}
var div = document.querySelector('div');
var span = document.querySelector('span');
// 調(diào)用函數(shù)
animate(div, 300);
animate(span, 200);
</script>
</body>
</html>
給不同對(duì)象添加不同定時(shí)器
<head>
<style>
div {
position: absolute;
left: 0;
width: 100px;
height: 100px;
background-color: pink;
}
span {
position: absolute;
left: 0;
top: 200px;
display: block;
width: 150px;
height: 150px;
background-color: purple;
}
</style>
</head>
<body>
<button>點(diǎn)擊夏雨荷才走</button>
<div></div>
<span>夏雨荷</span>
<script>
// var obj = {};
// obj.name = 'andy';
// 簡(jiǎn)單動(dòng)畫函數(shù)封裝obj目標(biāo)對(duì)象 target 目標(biāo)位置
// 給不同的元素指定了不同的定時(shí)器
function animate(obj, target) {
// 當(dāng)我們不斷的點(diǎn)擊按鈕,這個(gè)元素的速度會(huì)越來(lái)越快,因?yàn)殚_(kāi)啟了太多的定時(shí)器
// 解決方案就是 讓我們?cè)刂挥幸粋€(gè)定時(shí)器執(zhí)行
// 先清除以前的定時(shí)器,只保留當(dāng)前的一個(gè)定時(shí)器執(zhí)行
clearInterval(obj.timer);
obj.timer = setInterval(function() {
if (obj.offsetLeft >= target) {
// 停止動(dòng)畫 本質(zhì)是停止定時(shí)器
clearInterval(obj.timer);
}
obj.style.left = obj.offsetLeft + 1 + 'px';
}, 30);
}
var div = document.querySelector('div');
var span = document.querySelector('span');
var btn = document.querySelector('button');
// 調(diào)用函數(shù)
animate(div, 300);
btn.addEventListener('click', function() {
animate(span, 200);
})
</script>
</body>
</html>
緩動(dòng)動(dòng)畫原理
<html lang="en">
<head>
<style>
div {
position: absolute;
left: 0;
width: 100px;
height: 100px;
background-color: pink;
}
span {
position: absolute;
left: 0;
top: 200px;
display: block;
width: 150px;
height: 150px;
background-color: purple;
}
</style>
</head>
<body>
<button>點(diǎn)擊夏雨荷才走</button>
<span>夏雨荷</span>
<script>
// 緩動(dòng)動(dòng)畫函數(shù)封裝obj目標(biāo)對(duì)象 target 目標(biāo)位置
// 思路:
// 1. 讓盒子每次移動(dòng)的距離慢慢變小, 速度就會(huì)慢慢落下來(lái)。
// 2. 核心算法:(目標(biāo)值 - 現(xiàn)在的位置) / 10 做為每次移動(dòng)的距離 步長(zhǎng)
// 3. 停止的條件是: 讓當(dāng)前盒子位置等于目標(biāo)位置就停止定時(shí)器
function animate(obj, target) {
// 先清除以前的定時(shí)器,只保留當(dāng)前的一個(gè)定時(shí)器執(zhí)行
clearInterval(obj.timer);
obj.timer = setInterval(function() {
// 步長(zhǎng)值寫到定時(shí)器的里面
var step = (target - obj.offsetLeft) / 10;
if (obj.offsetLeft == target) {
// 停止動(dòng)畫 本質(zhì)是停止定時(shí)器
clearInterval(obj.timer);
}
// 把每次加1 這個(gè)步長(zhǎng)值改為一個(gè)慢慢變小的值 步長(zhǎng)公式:(目標(biāo)值 - 現(xiàn)在的位置) / 10
obj.style.left = obj.offsetLeft + step + 'px';
}, 15);
}
var span = document.querySelector('span');
var btn = document.querySelector('button');
btn.addEventListener('click', function() {
// 調(diào)用函數(shù)
animate(span, 500);
})
// 勻速動(dòng)畫 就是 盒子是當(dāng)前的位置 + 固定的值 10
// 緩動(dòng)動(dòng)畫就是 盒子當(dāng)前的位置 + 變化的值(目標(biāo)值 - 現(xiàn)在的位置) / 10)
</script>
</body>
</html>
緩動(dòng)動(dòng)畫多個(gè)目標(biāo)值之間移動(dòng)
<body>
<button class="btn500">點(diǎn)擊夏雨荷到500</button>
<button class="btn800">點(diǎn)擊夏雨荷到800</button>
<span>夏雨荷</span>
<script>
// 緩動(dòng)動(dòng)畫函數(shù)封裝obj目標(biāo)對(duì)象 target 目標(biāo)位置
// 思路:
// 1. 讓盒子每次移動(dòng)的距離慢慢變小, 速度就會(huì)慢慢落下來(lái)。
// 2. 核心算法:(目標(biāo)值 - 現(xiàn)在的位置) / 10 做為每次移動(dòng)的距離 步長(zhǎng)
// 3. 停止的條件是: 讓當(dāng)前盒子位置等于目標(biāo)位置就停止定時(shí)器
function animate(obj, target) {
// 先清除以前的定時(shí)器,只保留當(dāng)前的一個(gè)定時(shí)器執(zhí)行
clearInterval(obj.timer);
obj.timer = setInterval(function() {
// 步長(zhǎng)值寫到定時(shí)器的里面
// 把我們步長(zhǎng)值改為整數(shù) 不要出現(xiàn)小數(shù)的問(wèn)題
// var step = Math.ceil((target - obj.offsetLeft) / 10);
var step = (target - obj.offsetLeft) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
if (obj.offsetLeft == target) {
// 停止動(dòng)畫 本質(zhì)是停止定時(shí)器
clearInterval(obj.timer);
}
// 把每次加1 這個(gè)步長(zhǎng)值改為一個(gè)慢慢變小的值 步長(zhǎng)公式:(目標(biāo)值 - 現(xiàn)在的位置) / 10
obj.style.left = obj.offsetLeft + step + 'px';
}, 15);
}
var span = document.querySelector('span');
var btn500 = document.querySelector('.btn500');
var btn800 = document.querySelector('.btn800');
btn500.addEventListener('click', function() {
// 調(diào)用函數(shù)
animate(span, 500);
})
btn800.addEventListener('click', function() {
// 調(diào)用函數(shù)
animate(span, 800);
})
// 勻速動(dòng)畫 就是 盒子是當(dāng)前的位置 + 固定的值 10
// 緩動(dòng)動(dòng)畫就是 盒子當(dāng)前的位置 + 變化的值(目標(biāo)值 - 現(xiàn)在的位置) / 10)
</script>
</body>
緩動(dòng)動(dòng)畫添加回調(diào)函數(shù)
<body>
<button class="btn500">點(diǎn)擊夏雨荷到500</button>
<button class="btn800">點(diǎn)擊夏雨荷到800</button>
<span>夏雨荷</span>
<script>
// 緩動(dòng)動(dòng)畫函數(shù)封裝obj目標(biāo)對(duì)象 target 目標(biāo)位置
// 思路:
// 1. 讓盒子每次移動(dòng)的距離慢慢變小, 速度就會(huì)慢慢落下來(lái)。
// 2. 核心算法:(目標(biāo)值 - 現(xiàn)在的位置) / 10 做為每次移動(dòng)的距離 步長(zhǎng)
// 3. 停止的條件是: 讓當(dāng)前盒子位置等于目標(biāo)位置就停止定時(shí)器
function animate(obj, target, callback) {
// console.log(callback); callback = function() {} 調(diào)用的時(shí)候 callback()
// 先清除以前的定時(shí)器,只保留當(dāng)前的一個(gè)定時(shí)器執(zhí)行
clearInterval(obj.timer);
obj.timer = setInterval(function() {
// 步長(zhǎng)值寫到定時(shí)器的里面
// 把我們步長(zhǎng)值改為整數(shù) 不要出現(xiàn)小數(shù)的問(wèn)題
// var step = Math.ceil((target - obj.offsetLeft) / 10);
var step = (target - obj.offsetLeft) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
if (obj.offsetLeft == target) {
// 停止動(dòng)畫 本質(zhì)是停止定時(shí)器
clearInterval(obj.timer);
// 回調(diào)函數(shù)寫到定時(shí)器結(jié)束里面
if (callback) {
// 調(diào)用函數(shù)
callback();
}
}
// 把每次加1 這個(gè)步長(zhǎng)值改為一個(gè)慢慢變小的值 步長(zhǎng)公式:(目標(biāo)值 - 現(xiàn)在的位置) / 10
obj.style.left = obj.offsetLeft + step + 'px';
}, 15);
}
var span = document.querySelector('span');
var btn500 = document.querySelector('.btn500');
var btn800 = document.querySelector('.btn800');
btn500.addEventListener('click', function() {
// 調(diào)用函數(shù)
animate(span, 500);
})
btn800.addEventListener('click', function() {
// 調(diào)用函數(shù)
animate(span, 800, function() {
// alert('你好嗎');
span.style.backgroundColor = 'red';
});
})
// 勻速動(dòng)畫 就是 盒子是當(dāng)前的位置 + 固定的值 10
// 緩動(dòng)動(dòng)畫就是 盒子當(dāng)前的位置 + 變化的值(目標(biāo)值 - 現(xiàn)在的位置) / 10)
</script>
</body>
引用animate動(dòng)畫函數(shù)
<head>
<style>
.sliderbar {
position: fixed;
right: 0;
bottom: 100px;
width: 40px;
height: 40px;
text-align: center;
line-height: 40px;
cursor: pointer;
color: #fff;
}
.con {
position: absolute;
left: 0;
top: 0;
width: 200px;
height: 40px;
background-color: purple;
z-index: -1;
}
</style>
<script src="animate.js"></script>
</head>
<body>
<div class="sliderbar">
<span>←</span>
<div class="con">問(wèn)題反饋</div>
</div>
<script>
// 1. 獲取元素
var sliderbar = document.querySelector('.sliderbar');
var con = document.querySelector('.con');
// 當(dāng)我們鼠標(biāo)經(jīng)過(guò) sliderbar 就會(huì)讓 con這個(gè)盒子滑動(dòng)到左側(cè)
// 當(dāng)我們鼠標(biāo)離開(kāi) sliderbar 就會(huì)讓 con這個(gè)盒子滑動(dòng)到右側(cè)
sliderbar.addEventListener('mouseenter', function() {
// animate(obj, target, callback);
animate(con, -160, function() {
// 當(dāng)我們動(dòng)畫執(zhí)行完畢,就把 ← 改為 →
sliderbar.children[0].innerHTML = '→';
});
})
sliderbar.addEventListener('mouseleave', function() {
// animate(obj, target, callback);
animate(con, 0, function() {
sliderbar.children[0].innerHTML = '←';
});
})
</script>
</body>
</html>
仿淘寶返回頂部
<head>
<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">頭部區(qū)域</div>
<div class="banner w">banner區(qū)域</div>
<div class="main w">主體部分</div>
<script>
//1. 獲取元素
var sliderbar = document.querySelector('.slider-bar');
var banner = document.querySelector('.banner');
// banner.offestTop 就是被卷去頭部的大小 一定要寫到滾動(dòng)的外面
var bannerTop = banner.offsetTop
// 當(dāng)我們側(cè)邊欄固定定位之后應(yīng)該變化的數(shù)值
var sliderbarTop = sliderbar.offsetTop - bannerTop;
// 獲取main 主體元素
var main = document.querySelector('.main');
var goBack = document.querySelector('.goBack');
var mainTop = main.offsetTop;
// 2. 頁(yè)面滾動(dòng)事件 scroll
document.addEventListener('scroll', function() {
// console.log(11);
// window.pageYOffset 頁(yè)面被卷去的頭部
// console.log(window.pageYOffset);
// 3 .當(dāng)我們頁(yè)面被卷去的頭部大于等于了 172 此時(shí) 側(cè)邊欄就要改為固定定位
if (window.pageYOffset >= bannerTop) {
sliderbar.style.position = 'fixed';
sliderbar.style.top = sliderbarTop + 'px';
} else {
sliderbar.style.position = 'absolute';
sliderbar.style.top = '300px';
}
// 4. 當(dāng)我們頁(yè)面滾動(dòng)到main盒子,就顯示 goback模塊
if (window.pageYOffset >= mainTop) {
goBack.style.display = 'block';
} else {
goBack.style.display = 'none';
}
})
// 3. 當(dāng)我們點(diǎn)擊了返回頂部模塊,就讓窗口滾動(dòng)的頁(yè)面的最上方
goBack.addEventListener('click', function() {
// 里面的x和y 不跟單位的 直接寫數(shù)字即可
// window.scroll(0, 0);
// 因?yàn)槭谴翱跐L動(dòng) 所以對(duì)象是window
animate(window, 0);
});
// 動(dòng)畫函數(shù)
function animate(obj, target, callback) {
// console.log(callback); callback = function() {} 調(diào)用的時(shí)候 callback()
// 先清除以前的定時(shí)器,只保留當(dāng)前的一個(gè)定時(shí)器執(zhí)行
clearInterval(obj.timer);
obj.timer = setInterval(function() {
// 步長(zhǎng)值寫到定時(shí)器的里面
// 把我們步長(zhǎng)值改為整數(shù) 不要出現(xiàn)小數(shù)的問(wèn)題
// var step = Math.ceil((target - obj.offsetLeft) / 10);
var step = (target - window.pageYOffset) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
if (window.pageYOffset == target) {
// 停止動(dòng)畫 本質(zhì)是停止定時(shí)器
clearInterval(obj.timer);
// 回調(diào)函數(shù)寫到定時(shí)器結(jié)束里面
// if (callback) {
// // 調(diào)用函數(shù)
// callback();
// }
callback && callback();
}
// 把每次加1 這個(gè)步長(zhǎng)值改為一個(gè)慢慢變小的值 步長(zhǎng)公式:(目標(biāo)值 - 現(xiàn)在的位置) / 10
// obj.style.left = window.pageYOffset + step + 'px';
window.scroll(0, window.pageYOffset + step);
}, 15);
}
</script>
</body>
</html>
touch觸摸事件
<body>
<div></div>
<script>
// 1. 獲取元素
// 2. 手指觸摸DOM元素事件
var div = document.querySelector('div');
div.addEventListener('touchstart', function() {
console.log('我摸了你');
});
// 3. 手指在DOM元素身上移動(dòng)事件
div.addEventListener('touchmove', function() {
console.log('我繼續(xù)摸');
});
// 4. 手指離開(kāi)DOM元素事件
div.addEventListener('touchend', function() {
console.log('輕輕的我走了');
});
</script>
</body>
觸摸事件對(duì)象touchEvent
<body>
<div></div>
<script>
// 觸摸事件對(duì)象
// 1. 獲取元素
// 2. 手指觸摸DOM元素事件
var div = document.querySelector('div');
div.addEventListener('touchstart', function(e) {
// console.log(e);
// touches 正在觸摸屏幕的所有手指的列表
// targetTouches 正在觸摸當(dāng)前DOM元素的手指列表
// 如果偵聽(tīng)的是一個(gè)DOM元素,他們兩個(gè)是一樣的
// changedTouches 手指狀態(tài)發(fā)生了改變的列表 從無(wú)到有 或者 從有到無(wú)
// 因?yàn)槲覀円话愣际怯|摸元素 所以最經(jīng)常使用的是 targetTouches
console.log(e.targetTouches[0]);
// targetTouches[0] 就可以得到正在觸摸dom元素的第一個(gè)手指的相關(guān)信息比如 手指的坐標(biāo)等等
});
// 3. 手指在DOM元素身上移動(dòng)事件
div.addEventListener('touchmove', function() {
});
// 4. 手指離開(kāi)DOM元素事件
div.addEventListener('touchend', function(e) {
// console.log(e);
// 當(dāng)我們手指離開(kāi)屏幕的時(shí)候,就沒(méi)有了 touches 和 targetTouches 列表
// 但是會(huì)有 changedTouches
});
</script>
</body>
移動(dòng)端拖動(dòng)元素
<head>
<style>
div {
position: absolute;
left: 0;
width: 100px;
height: 100px;
background-color: pink;
}
</style>
</head>
<body>
<div></div>
<script>
// (1) 觸摸元素 touchstart: 獲取手指初始坐標(biāo),同時(shí)獲得盒子原來(lái)的位置
// (2) 移動(dòng)手指 touchmove: 計(jì)算手指的滑動(dòng)距離,并且移動(dòng)盒子
// (3) 離開(kāi)手指 touchend:
var div = document.querySelector('div');
var startX = 0; //獲取手指初始坐標(biāo)
var startY = 0;
var x = 0; //獲得盒子原來(lái)的位置
var y = 0;
div.addEventListener('touchstart', function(e) {
// 獲取手指初始坐標(biāo)
startX = e.targetTouches[0].pageX;
startY = e.targetTouches[0].pageY;
x = this.offsetLeft;
y = this.offsetTop;
});
div.addEventListener('touchmove', function(e) {
// 計(jì)算手指的移動(dòng)距離: 手指移動(dòng)之后的坐標(biāo)減去手指初始的坐標(biāo)
var moveX = e.targetTouches[0].pageX - startX;
var moveY = e.targetTouches[0].pageY - startY;
// 移動(dòng)我們的盒子 盒子原來(lái)的位置 + 手指移動(dòng)的距離
this.style.left = x + moveX + 'px';
this.style.top = y + moveY + 'px';
e.preventDefault(); // 阻止屏幕滾動(dòng)的默認(rèn)行為
});
</script>
</body>
</html>
上一篇:DOM&BOM基礎(chǔ)第5篇 - 簡(jiǎn)書(shū) (jianshu.com)
下一篇:DOM&BOM基礎(chǔ)第7篇 - 簡(jiǎn)書(shū) (jianshu.com)
點(diǎn)贊加關(guān)注,永遠(yuǎn)不迷路