我們可能已經(jīng)用過很多JS插件,比如著名的輪播圖插件Swiper.js,滾動條插件iScroll.js等等臀蛛,用起來非常方便尿扯,大大提高了我們的工作效率求晶。那么它們基本實現(xiàn)原理是怎樣的呢?我們又該如何DIY一個可以復(fù)用的JS插件呢衷笋?
接下來芳杏,我將以圖片無縫循環(huán)輪播為例,手把手教你封裝一個方便復(fù)用的原生JS插件辟宗。
開始之前爵赵,我們先看看實現(xiàn)后的具體效果吧 → 圖片無縫循環(huán)輪播 。
一泊脐、面向過程編程實現(xiàn)
1. 實現(xiàn)原理
如上圖所示空幻,后三個 li 元素為復(fù)制元素,container 保持不動容客,ul 向左移動秕铛,當(dāng)狀態(tài)到達(dá)②時瞬間切回①狀態(tài)则剃,這樣整個過程看起來就像一直向左移動一樣。
2. 實現(xiàn)代碼
/*CSS*/
html{ background-color: #00b0e4;}
body,ul,li{ margin: 0; padding: 0;}
ul li{ list-style: none;}
.container{ height: 300px; margin: 100px auto; padding: 60px 0; overflow: hidden;}
.container ul{ display: -webkit-flex; display: flex; height: 100%;}
.container ul li{ -webkit-flex-shrink: 0; flex-shrink: 0; position: relative; z-index: 0; width: 400px; height: 100%;
padding: 5px; box-sizing: border-box; -webkit-transition: all .6s; transition: all .6s;}
.container ul li:hover{ z-index: 1; -webkit-transform: scale(1.2); transform: scale(1.2); }
.container ul li img{ width: 100%; height: 100%; object-fit: cover; box-sizing: border-box;
border: 10px solid #fff; box-shadow: 0 0 5px #333;}
布局方式我使用的是flexbox布局如捅,可以輕松實現(xiàn)圖片橫排棍现,更多相關(guān)內(nèi)容請戳 → 快速理解Flexbox布局。
圖片樣式中我用到了object-fit: cover
镜遣,這個屬性可以使不同比例的圖片在寬高固定的情況下不被壓縮變形己肮,更多相關(guān)內(nèi)容請戳 → 圖片在固定寬高盒子中的顯示問題
<!--HTML-->
<div class="container">
<ul class="wrapper">
<li class="slide"><img src="./imgs/1.jpg" alt=""></li>
<li class="slide"><img src="./imgs/2.jpg" alt=""></li>
<li class="slide"><img src="./imgs/3.jpg" alt=""></li>
<li class="slide"><img src="./imgs/4.jpg" alt=""></li>
</ul>
</div>
// Javascript
window.onload = function () {
var oContainer = document.querySelector('.container'),
oWrapper = oContainer.querySelector('ul'),
oSlide = oWrapper.querySelectorAll('li');
var wrapperW = oSlide[0].offsetWidth * oSlide.length;
oWrapper.style.width = wrapperW * 2 + 'px';
// 復(fù)制所有圖片以實現(xiàn)圖片無縫銜接
oWrapper.innerHTML += oWrapper.innerHTML;
/*此處是為了防止所有圖片總寬度小于最外層盒子的寬度,
這時需要將最外層盒子寬度設(shè)置為圖片總寬度*/
if(wrapperW < oContainer.offsetWidth){
oContainer.style.width = wrapperW + 'px';
}
var x = 0, timer = null;
// 圖片自動輪播函數(shù)
var slideMove = function(){
timer = setInterval(function () {
x++;
if(x > wrapperW){
x = 0;
}
// 圖片左移
oWrapper.style.transform = 'translate('+ (-x) +'px)';
},10);
};
// 圖片自動無限輪播
slideMove();
// 鼠標(biāo)移入時清除定時器悲关,圖片停止輪播
oContainer.addEventListener('mouseover',function () {
clearInterval(timer);
});
// 鼠標(biāo)移出時圖片繼續(xù)輪播
oContainer.addEventListener('mouseout',function () {
slideMove();
});
};
二谎僻、面向?qū)ο缶幊虒崿F(xiàn)
1. 基本改造步驟
如何將面向過程改造成面向?qū)ο?/strong>呢?
一般有以下幾個基本步驟:
① 創(chuàng)建一個構(gòu)造函數(shù)
② 變量改為屬性
③ 函數(shù)改為原型方法(有些實現(xiàn)某塊具體功能的代碼也可抽離成原型方法)
④ 更正某些不正確的this指向
2. 實現(xiàn)代碼
// Javascript
/* 創(chuàng)建一個構(gòu)造函數(shù) */
function FreeSlider(selector,speed) {
/* 變量改為屬性 */
this.oContainer = document.querySelector(selector);
this.oWrapper = this.oContainer.querySelector('ul');
this.oSlide = this.oWrapper.querySelectorAll('li');
/* 當(dāng)不傳入輪播速度時寓辱,速度默認(rèn)為100 */
this.speed = speed || 100;
this.containerW = this.oContainer.offsetWidth;
this.wrapperW = this.oSlide[0].offsetWidth * this.oSlide.length;
this.x = 0;
this.timer = null;
this.init();
}
/* 構(gòu)造函數(shù)的原型對象 */
FreeSlider.prototype = {
constructor: FreeSlider,
/* 功能抽離艘绍,此處實現(xiàn)初始化 */
init: function(){
this.oWrapper.style.width = this.wrapperW * 2 + 'px';
this.oWrapper.innerHTML += this.oWrapper.innerHTML;
if(this.wrapperW < this.containerW){
this.oContainer.style.width = this.wrapperW + 'px';
}
this.slideMove();
},
/* 圖片自動無限輪播 */
slideMove: function(){
/* 此處需要注意this的指向,
在setInterval回調(diào)函數(shù)中的this指向為window */
var that = this;
this.timer = setInterval(function () {
that.x++;
if(that.x > that.wrapperW){
that.x = 0;
}
that.oWrapper.style.transform = 'translate('+ (-that.x) +'px)';
},this.containerW / this.speed); // 將速度轉(zhuǎn)化成定時器時間
},
/* 圖片停止輪播 */
stopSlideMove: function () {
clearInterval(this.timer);
}
};
window.onload = function(){
var oContainer = document.querySelector('.container');
// 新建圖片輪播對象
var mySlider = new FreeSlider('.container',300);
// 鼠標(biāo)移入時清除定時器秫筏,圖片停止輪播
oContainer.addEventListener('mouseover',function () {
mySlider.stopSlideMove();
});
// 鼠標(biāo)移出時圖片繼續(xù)輪播
oContainer.addEventListener('mouseout',function () {
mySlider.slideMove();
});
}
本文重點總結(jié)
① JS插件其實沒有你想象的那么難诱鞠,基本原理就是面向?qū)ο?br> ② 將需要可靈活配置的部分作為構(gòu)造函數(shù)的參數(shù)傳入,插件中的各個功能可作為原型方法提供給外部調(diào)用