DOM影片效果
- 讓一個元素從左至右進行運動
<div id="box"></div>
var box = document.getElementById("box");
var t = null;
t = setInterval(function(){
})
運動的終止條件
t = setInterval(function(){終止條件})
// 元素的屬性值 === 目標點
if(dom.attr === target){
clearInterval(t);
}
運動的三要素
- 起始點
一個運動的起始點其實就是當前元素的位置,我們通過API獲取當前元素的位置,讓這個位置作為運動的起始,
-
目標
-
速度
運動的底層原理
- 讓元素通過定時器在很短的間隔內進行CSS屬性值的改變
- 這樣連續的運動在用戶看來就是影片效果
DOM影片效果封裝
封裝的主要作用就是讓元素可以在短時間間隔內不斷改變屬性實作影片效果
單屬性運動框架:
<button id="btn">開始運動</button>
<div id="box"></div>
<div id="line"></div>
<script>
var box = document.getElementById("box");
var btn = document.getElementById("btn");
var target = 500;
// 速度可以根據 起始點和目標點進行判斷,從而決定正負;
var speed = 17;
// - 方向;
btn.onclick = function(){
// 1. 獲取元素初始位置;
var _left = box.offsetLeft;
speed = target - _left >= 0 ? speed : -speed ;
var interval = setInterval( function(){
// 4. 判定運動的終止條件;
if(Math.abs(target - _left) <= Math.abs(speed) ){
// 因為終止時有可能沒有到達目標點,因此我們把元素賦值到目標點位置;
box.style.left = target + "px";
clearInterval( interval );
}else{
// 2. 元素根據初始位置進行改變;
_left += speed;
// 3. DOM操作,根據已有資料讓元素屬性發生改變;
box.style.left = _left + "px";
}
} , 30)
}
</script>
- 勻速運動封裝
<script>
// - 提取屬性名作為引數;
btn.onclick = function(){
animate( "left", 500 )
}
function animate( attr , target , speed = 10 ){
// 1. 獲取元素初始樣式
var _style = getComputedStyle( box );
// 2. 根據屬性要求取出當前的屬性的屬性值;
var _css_style = parseInt(_style[attr]);
speed = target - _css_style >= 0 ? speed : -speed ;
var interval = setInterval( function(){
// 4. 判定運動的終止條件;
if(Math.abs(target - _css_style) <= Math.abs(speed) ){
// 因為終止時有可能沒有到達目標點,因此我們把元素賦值到目標點位置;
box.style[attr] = target + "px";
clearInterval( interval );
}else{
// 2. 元素根據初始位置進行改變;
_css_style += speed;
// 3. DOM操作,根據已有資料讓元素屬性發生改變;
box.style[attr] = _css_style + "px";
}
} , 30)
}
</script>
- 兼容透明度
<script>
function animate( dom , attr , target , speed = 10 ){
// 1. 獲取元素初始樣式
var _style = getComputedStyle( dom );
// 2. 根據屬性要求取出當前的屬性的屬性值;
if( attr === "opacity"){
var _css_style = parseInt(_style[attr] * 100 );
target *= 100;
}else{
var _css_style = parseInt(_style[attr]);
}
speed = target - _css_style >= 0 ? speed : -speed ;
var interval = setInterval( function(){
// 4. 判定運動的終止條件;
if(Math.abs(target - _css_style) <= Math.abs(speed) ){
// 因為終止時有可能沒有到達目標點,因此我們把元素賦值到目標點位置;
if( attr === "opacity"){
dom.style[attr] = target / 100;
}else{
dom.style[attr] = target + "px";
}
clearInterval( interval );
}else{
// 2. 元素根據初始位置進行改變;
_css_style += speed;
// 3. DOM操作,根據已有資料讓元素屬性發生改變;
if( attr === "opacity"){
dom.style[attr] = _css_style / 100 ;
}else{
dom.style[attr] = _css_style + "px";
}
}
} , 30)
}
</script>
- 緩沖運動
- 緩沖運動是一種運動方式
- 這種運動方式是速度在運動程序中會有改變的運動
- 距離越小 速度越小
<button id="btn">開始運動</button>
<div id="box"></div>
<script>
var box = document.getElementById("box");
var btn = document.getElementById("btn");
btn.onclick = function(){
animate( box , "left" , 500 )
}
function animate( dom , attr , target , transition = "buffer", speed = 10 ){
var _style = getComputedStyle( dom );
if( attr === "opacity"){
var _css_style = parseInt(_style[attr] * 100 );
target *= 100;
}else{
var _css_style = parseInt(_style[attr]);
}
if( transition === "liner"){
speed = target - _css_style >= 0 ? speed : -speed ;
}
var interval = setInterval( function(){
if( transition === "buffer"){
// 計算速度;
speed = (target - _css_style) / 10;
//速度不取整在小數部分會做很多無意義的計算;
speed = speed > 0 ? Math.ceil(speed) :Math.floor( speed )
}
if(Math.abs(target - _css_style) <= Math.abs(speed) ){
// 因為終止時有可能沒有到達目標點,因此我們把元素賦值到目標點位置;
if( attr === "opacity"){
dom.style[attr] = target / 100;
}else{
dom.style[attr] = target + "px";
}
clearInterval( interval );
}else{
// 2. 元素根據初始位置進行改變;
_css_style += speed;
// 3. DOM操作,根據已有資料讓元素屬性發生改變;
if( attr === "opacity"){
dom.style[attr] = _css_style / 100 ;
}else{
dom.style[attr] = _css_style + "px";
}
}
} , 30)
}
</script>
//只需要改變里面transition的值就可以調整運動模式
//buffer為緩沖運動
//liner為勻速運動
多屬性運動框架 (拓展)
- 多屬性運動框架
- 我們在多次呼叫animate的時候會開啟多個定時器
- 因為定時器之中的資料都一樣,我們看不出在效果上的差異
- 但是多次開啟定時器會極其嚴重的消耗計算機性能
- 開啟當前定時器之前關閉上一個定時器
<script>
// 在一個定時器之中,用for回圈同時執行多次dom樣式操作;
// 1. 需要優化的部分:引數,要把樣式部分的引數優化成一個物件;
function animate( dom , attrs , transition = "buffer", speed = 10 ){
var _style = getComputedStyle( dom );
// 獲取元素當前的屬性 :
for(var attr in attrs ){
// attr ? 要過渡的css屬性名;
// attrs[attr] ? 要過渡的當前屬性;
attrs[attr] = {
target : attrs[attr],
// 元素當前的屬性放入到這個物件之中;
now : parseInt(_style[attr])
}
}
// 因為直接關閉interval是沒有作用的,此時的inteval是一個區域變數,每次animate被呼叫的時候都會直接重置;
// 我們應該吧定時器的id放在當前正在執行過渡效果的dom物件上;
clearInterval(dom.interval);
dom.interval = setInterval( function(){
for(var attr in attrs){
// 取出 attrs 之中的目標點和當前值;
speed = (attrs[attr].target - attrs[attr].now) / 10 ;
// 根據速度正負,進行速度取整;
speed = speed > 0 ? Math.ceil( speed ) : Math.floor( speed );
// 判定終止條件;
if( attrs[attr].target === attrs[attr].now){
// 洗掉已經到達目標點的屬性;
delete attrs[attr]
// 判定attrs里面已經沒有屬性了;
for(var a in attrs){
return false;
}
clearInterval(dom.interval);
}else{
attrs[attr].now += speed;
dom.style[ attr ] = attrs[attr].now + "px";
}
}
} , 30)
}
// 優化引數之后,key值是等待運動的css屬性,value值是元素的目標;
btn.onclick = function(){
animate( box , { width : 500 , height : 400 } )
}
</script>
輪播圖功能實作
<style>
*{
margin: 0;
padding: 0;
}
.container{
width: 1130px;
height: 286px;
margin: 0 auto;
position: relative;
overflow: hidden;
}
.wrapper{
width: 6780px;
position: absolute;
left: 0;
}
.slide{
float: left;
}
.slide , .slide img{
width: 1130px;
height: 286px;
}
.button-prev{
left: 0;
background-position: 30px center;
background-image: url(https://static.zcool.cn/git_z/z/widget/slider/images/svg/left_arrow.svg?v=2);
top: 0;
width: 13px;
height: 100%;
padding: 0 80px;
border-radius: 2px;
position: absolute;
background-repeat: no-repeat;
}
.button-prev:hover{
background-image: url(https://static.zcool.cn/git_z/z/widget/slider/images/svg/left_arrowhover.svg?v=2);
}
.button-next{
right: 0;
background-position: 91px center;
background-image: url(https://static.zcool.cn/git_z/z/widget/slider/images/svg/right_arrow.svg?v=2);
top: 0;
width: 13px;
height: 100%;
padding: 0 80px;
border-radius: 2px;
position: absolute;
background-repeat: no-repeat;
}
.button-next:hover{
background-image: url(https://static.zcool.cn/git_z/z/widget/slider/images/svg/right_arrowhover.svg?v=2);
}
.pagination{
position: absolute;
bottom: 10%;
width: 100%;
height: 10px;
left: 30px;
}
.pagination span{
display: inline-block;
width: 10px;
height: 10px;
margin-left: 10px;
border-radius: 50%;
background-color: cornflowerblue;
border: 2px solid transparent;
background-clip: content-box;
}
.pagination span.active{
border: 2px solid skyblue;
box-shadow: 0 0 5px skyblue;
background-color: #fff;
}
</style>
<!-- 類名請使用和我一樣的類名 -->
<div class="container">
<div class="wrapper">
<!-- 第0張圖片 -->
<div class="slide">
<img src="https://img.zcool.cn/ad_manager/location/f35d611484931101c43350bbdbd5.jpg" alt="">
</div>
<div class="slide">
<img src="https://img.zcool.cn/ad_manager/location/3dcb6113a3471101c433505bbd72.jpg" alt="">
</div>
<div class="slide">
<img src="https://img.zcool.cn/ad_manager/location/65f36113a3341101c4335014b174.jpg" alt="">
</div>
<div class="slide">
<img src="https://img.zcool.cn/ad_manager/location/7f97611481181101c43350225b33.jpg" alt="">
</div>
<div class="slide">
<img src="https://img.zcool.cn/ad_manager/location/afcf6114801e1101c433507f9e28.jpg" alt="">
</div>
<!-- 最后一張圖片 -->
<!-- 把第0張圖片放在整個圖片結構的最后 -->
<div class="slide">
<img src="https://img.zcool.cn/ad_manager/location/f35d611484931101c43350bbdbd5.jpg" alt="">
</div>
</div>
<div class="button-next"></div>
<div class="button-prev"></div>
<div class="pagination">
<span class="active"></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
</div>
<script src="./utils.js"></script>
<script>
// 輪播圖的核心就是左右切換按鈕,實作顯示元素下標的改變;
var index = 0 ;
var prev = 0;
var next_btn = document.querySelector(".button-next");
var prev_btn = document.querySelector(".button-prev");
var slides = document.querySelectorAll(".slide");
var wrapper = document.querySelector(".wrapper");
// 自動播放的阻止功能是在滑鼠移入container容器之中就觸發的;
var container = document.querySelector(".container");
var bullets = document.querySelectorAll(".pagination span");
// 系結事件
// - 輪播圖改變下標功能必須設定邊界;
function bindEvent(){
next_btn.onclick = function(){
add();
bannerAnimate();
}
prev_btn.onclick = function(){
reduce()
bannerAnimate();
}
container.onmouseover = function(){
stop();
}
container.onmouseout = function(){
autoPlay();
}
bullets.forEach( function( ele , i ){
ele.onmouseover = function(){
prev = index;
// 防止穿幫邏輯;
// - 如果在假的第0張圖片上(在最后一張圖片上)
// - 我們先讓真偽圖片呼喊然后在進行元素的影片效果;
if( index === 5 ){
wrapper.style.left = 0;
}
index = i;
bannerAnimate();
}
})
}
// 下標增加;
function add(){
prev = index;
if( index === slides.length - 1 ){
// 這個邏輯會在最后一張圖片進行切換時進入;
// 我們讓wrapper直接位移到開頭,改變元素位置的同時讓用戶無法感知;
wrapper.style.left = 0;
// 我們需要從第0個圖片切換到第一個圖片;
// -因為我們最后一張圖片的顯示和開頭圖片的顯示是一樣的
index = 1;
}else{
index ++;
}
}
// 下標減少;
function reduce(){
prev = index;
if( index === 0 ){
wrapper.style.left = -(slides.length - 1) * 1130 + "px";
index = slides.length - 2;
}else{
index --;
}
}
// 根據我們的演算法去實作影片效果;
function bannerAnimate(){
animate( wrapper , { left : - index * 1130 });
// 給對應的分頁器按鈕添加active;
// 先去清空所有的類名;
bullets.forEach( function( ele ){
ele.classList.remove("active")
})
// 下標需要進行特殊處理,在顯示最后一張圖片的時候,給第0個按鈕添加active;
bullets[ index === 5 ? 0 : index ].classList.add("active");
}
bindEvent();
var interval = null;
function autoPlay(){
// 間隔3s,讓js點擊一下下一頁按鈕;
interval = setInterval( function(){
// 虛擬點擊 :
next_btn.dispatchEvent( new Event("click"));
} , 3000 )
}
function stop(){
clearInterval( interval )
}
autoPlay();
</script>
原創不易,轉載請注明出處,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/293982.html
標籤:其他
