插件封装|封装一个属于自己的轮播图插件——左右切换版


上一篇文章 案例|原生手写一个轮播图——渐隐渐显版 还有很多缺乏,这儿要十分感谢大佬 csdoker给出的宝贵意见和指导,所以笔者决定从头完善一下轮播图的案例,打算做一个简易版的左右轮U X ? 5播图插件的封装;

一、插件封装前言(封装的根底)

思维导图

插件封装|封装一个属于自己的轮播图插件——左右切换版

(一)、插件封装思想

1、敏捷化平台的构建思想

封装一款插件,首要榜首件工作一定是剖析,剖析最后完结的作用和) f ~能够支撑的装备项

2、依据:

  • => 经历积累
  • => 研究别人优秀的插件

3、意图:

写插件的意图是便利后期的开+ i [ % z P发,而且需求让更多人运用(开源)

4、要求:

  • -> 专业,+ [ C咱们写的插件功用要好(代码要好)
  • -> 易用,别人运用起来十分的c q p T 1 Z简便
  • -> 强大,尽可能在代码简洁的情况下,支撑更强大的作用
  • -> 灵活,尽可能依据原生JS编写,不要依赖其他的类库或者内容(拿来即用主义)
  • -> 扩展,可晋级,晋级的时候要考虑到低版别的向后兼容,而且不要和原始的版别距离太大
  • ……等等

(二)、左右轮播图插件封装思想

插件 组件 类[ p g ^ R | S库 等这些东西封装 根本上都要依据面向对象思想

  • Z ^ N l g向对象的思想能够确保每一个实例之间没有相关
  • 面向对象的最主要意图便是:插件组件封装
  • 咱们封装的插件是一个类
    • 依据插件每一次调用完结的轮t 2 f F播图 都是创立类) u 0的一个实例
  • 关于轮播图来说:
    • 1.根本中心信息应该都是私5 d b 4有的
    • 2.一些操作的办法应该是公用的

(三)、插件封L I b V装中的形参处理

办法一:设置为形参,一个个传递

  • 特色:
    • -> 传递实参的次序有必要和形参设置次序保持一致
    • -> 不好给形参设置默许值
    • -> 中间的一些项假如不传递,会把后面传递的项错位
  • 运用场景:
    • 一般这种情况只应用于参数特别少的情况下(一6 _ [般不超越两个)

办法二:依据对象键值对的办法处 b s _ 0 [ d O 1

  • 特色:
    • -&g, ? X qt; 能够传递,也能够] S Oj J m G u g o传递
    • -> 传递的次序也随意,由于都是依据特点名标记好的,只需特* g 8 C 7 0 点和值对应,次序是无所谓的
    • -> 便利扩展
    • -> 不传递的信息咱们给其设置默许值
  • 运用场景:] B F g $ j w ? g
    • 关于传递多个参数的情况下,咱们一般依据对象键值对的办法处理

二、轮播图封装——HTML

这一部分咱们能够写一点架子出来,用户运用时直接CV过来,更换自己的图片K : o,装备自己的一些细节内容即可;
库房地址

<!-- 轮播图整体容器 -->
<div class="xiaozhima-container">
<!-- 所有图X @ 2 * T R E p片容器 --&Z 1 g u -gt;
<div class="xiaozhima-wrapper">
<!-- 每个图片容器 -->
<K P s &;div class="xiaozhima-slide">
<!-- 刺进您的图片 -->
<img src=" " alt="">c T g k * C
</div>
<div class="xiaozhima-slide">
<imJ  Z Q = . P [ gg src=" " alt="">
</div>
<C @ B b } j a q;div class="xiaozhima-slide">
<img src=" " alt="">
</div>
<div class="xiaozhima-slide">
<img src=" " alt="">
</div>J ; a;
</div>
<!-- 分页器容器 -->
<d{ ( -iv class="xiaozhima-pad I A M * W : 7 }ginaF ? Ntio! Y ~ jn">&1 J ; 3 Ilt- @ q { N;/div>
<!-- 左右按钮容器 -->
<a href="javascript:;" class="xiaozhima-arrow-prev">( 2 { 4 F ` f m</a>
<a href="javascript:;" class="xiaozh1 l - ^ 5 S B 2ima-arrow-next"></a>
<7 S ; b/div>

三、轮播图封装——CSS

这一部分咱们也是写一点架子出来,把咱们需求完结的内容装备好,细节款式由用户自己指定即可

1、运用办法:

  • 引进4 . : ~ & A命名为b n Tbanner-plugin.css的款式表即s U 8 N B ; – ;可 ;库房地址
    (咱们也能够自己创立一个CSS文件,把代码直接张贴进去即可);

2、用户需求装备的内O [ 1 7 ( D容:

  • 轮播图整体容器的:
    • width
    • height
  • 刺进您的图片中的:(可不更改只传图片即可)
    • 1 M d q片及图片的款式

3、需求在JS中动态核算的款式

  • 所有图片容器的:

    • width :依据SLIDE的个数(含克隆的)*/ V ; k E 0 h s CONTAINER容器的宽度
    • transition:是在JS中设置的
    • left:初始展示哪一个SLIDE,LEFT值就应该是核算好的
  • 每个图片容器的:

    • width :需 K U 3 g $ X 求和用户传递的CONTAINE[ = Y A WR的宽度保持一致(JS中处理)
  • 左右按钮:(北京图片转为BASE64编码)

    • 插件中的d y u d c q 3 D款式资源最好不要运用图片(由于这样需求用户额定的导入,不利于插件的推行和运用) => 需求运用图片,咱们最好把图片设置为BASE Q +EE A + h H64编码

    • 一个把图片转为B$ l h d | ?ASE64编码的在线网站:tool.css-jd I $ ^ J (s.com/base64.html

4、详细的CSS代码

.xiaozhima-container {
/*
* 需求用户后期自己装备的款式
*   width
*   hF & 2 G Leight
*/
position: relative;
box-sizing: border-box;
width: 100%;
o: H F x 1 - & pverflow: hidden;
}
.xiaozhiB + 2 r yma-container .xiaozhima-wrapper {
/*
* 需求在JS中动态核算的款p % ) N i / ! 5 :式
*   width 依据SLIDE的个数(含克隆的)* CONTAINER容器的& j @ G {宽度
*   transition 是在JS中设置的
*   leftE R v Z 初始展示哪一个S( . I Z q X jLIDE,LEFT值就应该是核算好的
*/
display: flex;
box-sizing: border-box;
position: absolute;
top: 0;
height: 100%;
}
.xiaozhima-container .xiaozhima-wrapper .xiaozhima-slide {
/*
* 需求用户后期自己装备的款式
*   width 和CONTAINER的宽度保J & )  ~ $ p h持一致(JS中处理)
*/
box-sizing: border-box;
height: 100%;
overflo^ M p ! M 0 z gw: hidden;
}
.xiaozhima-conta: q W $ ^ 0  (iner .xiaozhima-wrapper .xiaozhima-slh 2 m h 0 ! Zide img {
display: block;
width: 100%;
height: 100%;
}
.xiaozhima-containI o d 5 2er .xiaozhima-pagination {
position: absolute;
bottom: 10px;
left: 50%;
z-index: 999;
transform: translateX(-50%);
padding: 3px 6p, z # [ }x;
backgroundr @ g 0 5 ^: rgba(255, 255,3 P [ 255, .3);
font-sizf Q & le: 0;
border-radius: 10px;
}
.xiaozhima-coT W [ Gntainer .xiaozB 9 - P i o y {hima-p)  6 5 7 O 1agination span {
displayk = : inline-block;
margin: 0 6px;
width: 10px;
height: 10px;
border-radius: 5? ? 1 g - : l a -0%;
background: lightblue;
cursor: pointer;
}
.xiaozhima-container .xiaozhima-pagina{ # I o (tion span.ac 6 ) 8 Active {
background:? u + 9 ) lightcoral;
}
.xiaozhima-arrow-prev,
.xiaozhima-arrow-next {
display: none;
position: absolute;
z-index: 999;
top: 50%;
margin-top: -22.5px;
width: 30px;
height: 45px;
/* 插件中的款式资源最好不要运用图片(由于这样需求用户额定的导入,不利于I s V B B | Q e插件的推行和运用) => 需求运用图片,咱们最好把图片设置为BASE64编码 */
background: url("data:imageG h ^ 3 U x/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF8a y o G / IAAAA1CAYAAAAnIzfJAAAACXBIWXMAAAsTAAALEwEAmpwY_ ) U o # 4AAAKTWlDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVN3WJP3Fj7f92UPVkLY8LGXbI7 5 x # 3EAIiOsCMgQWaIQkgBhhBASQMWFiApWFBURnEhVxILVCkidiOKgKLhnQYqIWotV M Q p B 7 p g DXDjuH9yD m 0 0 s A q $ ;ntX167+3t+9f7vOec5/zOec8PgBESJpHmomoAOVKFP- + ( VDrYH49PSMTJvYACFU; ( . S t R `jgBCAQ5svCZw: W S X c vXFAADwA3l4fnSwP/wBr28AAgBw1S4kEsfh/4O6UCZXACCRAOAiEucLAZBSAMguVMgUAMgYALBTs2QKAJQAAGx5fEIiAKoNAOz0ST4FANipk9wXANiiHKkIAI0BAJkoRyQCQLsAYFWBUiwCwMIAoKxAIi4EwK4BgFm2MkcCgL0FAHaOWJAPQGAAgJlCLMwAIDgCAEMeE80DIEwDoDDSv+CpX3CFuEgBAMDL8 X - w F } D 4 1lc# Y _ / d B m G 32XS9IzFLiV0Bp38vDg4iHiwmyxQmEXKRBmCeQinJebIxNI5wNMzgwAABr50cH+OD+Q5+bk4eZm52zv9MWi/mvwbyI+IfHf/ryMAgQAq & % NEE7P79pf5eXWA3DHAbB1v2upWwDaVgBo3/ldM9sJoFoK0Hr5i3k4/EAe} Q V : C z C a GnqFQyDwdHAoLC+0lYqG9MOOLPv8z4W/gi372/EAe/tt68ABxmkCZrcCjg/1xYW52rlKO58sEQjFu9+cj/seFf/2OKdHiNLFcLBWK8ViJuFAiTcd5G G { % N ] 0uVKRRCHJleIS6X8y8R+W/QmTdw0ArIZPwE62B7XLbMB+7gECiw5Y0nYAQH7zLYwaC5EAEGc0Mnn3AACTv/mPQCsBAM2XpOMAALzoGFyolBdMxggAAESggSqwQQcMwRSswA6cwR28wO W #BcCYQZEQAwkwDwQQgbkgBwKoRiWQRlUwDrYBLWwAxqgEZrhELTBMTgN5+ASXI# U i : . i 2 } 9HrcBcGYBiewhi8hgkEQcgIE2EhOogRYo7YIs4IF5mOBCJhSDSSgKQg6YgUC t } a !USLFB } [ S o G ^ .yHKkAqlCapFdSCPyLXIUOY1cQPqQ28ggMor8irxHR & w H T e e SMZSBslED1AJ1QLmoHxqKxqBz0XQ0D12AlqJr0Rq0Hj2AtqKn0UvodXW a 0 i 0 5 NQAfYqOY4DR} = _ eMQ5mjNlhXIyHRWCJWBomxxZj5Vg1Vo81Yx1YN3P [ K D t L  }YVG; L N u a / w _8CeYe8IJAKLgBPsCF6EEMJsgpCQR1hMWEOoJewjtBK6CFcJg4Qxwicr u / 4 K _ L #ik6hPtCV6- H Y - ] y T [EvnEeGI6. R gsZBYRqwm7iEeIZ4lXicOE1+TSCQOyZLkTgohJZAySQtJa0jbSC2kU6Q+0hBpnEwm6 D H J65Btyd7kCLKArCCXkbeQD5BPkvvJw+S3FDrFiOJMCaIkUqSUEko1ZT/lBKWfMkKZoKpRzame1AiqiDqfWkltoHZQL1OHqRM0dZolzZsWQ8ukLaPV0JppZ2n3aC/pdLoJ3YMep # e y 1 Q RZfQl9Jrl [ w p a d # t 6Afp5+mD9HcMDYYNg8dIYigZaxl7GacYtxkvmUyA , x ( DmBdOXmchUMNcyG5lnmA+Yb1VYKvYqfBWRyhKVOpVWlX6V56pUVXNVP9V5qgtUq1w 4 KUPq15WfaZGy 5 fVbNQ46kJ1Bar1akdVbupNq7Ok W h j 7UndSj1DPUV+jvl/9gvpjDbKGhUaghkijVGe ? M t y 9 G u 1O3xhmNIRbGMmXxWELWclYD6yxr} G *mE1iW7L57Ex2Bfsbdi97TFNDc6pmrGaR& A  _ f VZp3mcc0BDsax4PA52ZxKziHODc57LQt W g M 3MtPy2x1mqtZq1+rTfaetq+2mLtcG g q Uu0W7eva73VwnUCdLJ31Om0693UJuja6UbqFutt1z+o+02PreekJ9cr1Dund0Uf1bfSj9Rfq79bv0R83MDQINpAZbDE4Y/DMkGPoa5hpuNHwhOGoEctoupHEaKPRSaMnuCbuh2$ ? ` ` } RfjNXgXPmasbxxirDTeZdxrPGFiaTLbpMSkxeS+1  q ]Kc2Ud + f $ * w { @ da5pmutG003TMzMgs3KzYrMnsjjnVnGueYb7Za : = 2 8 kvNv8jYWlRZzFSos2i8eW2pZ8ywWWTZb3} A N 0 ) T e A %rJhWPlZ5VvVW16xJ1lzrLOtt1ldsUBtXmwybOpvLtqitm63EdpttV j : Y3xTiFI8p0in1U27aMez87ArsmuwG7Tn2YfYl9m32zx= x q |3MHBId1jt0O3xydHXMdmxwvOuk4TTDqcSpw+lXZxtnoXOd8zUXpkuQyxKXdpcXU22niqdun3rLleUa7rrStdP1o5u7m9yt2W3U3cw9xX2X = o V * H fr+00umxvJXcM970H08PdY4nHM452nm6fC85DnL152Xlle+70eT7OcJp7WMG3I28Rb4L3L~ - b e2A6Pj1l+s7pAz7GPgKfepo l U O E /+Hvqa+It89viN+1n6Zfgf8nvs7+sv9j/i/4XnyFvFOBWABwQHlAb2BGoGzA2sDHwSZBKUH? v r 4 y WNQWNBbsGLww+FUIMCQ1Zw B $ T Y cH3KTb#  3 h8AX8hv5YzPcZyya0RXKCJ0VWhv6MMwmTB7WEY6GzwjfEH5vpvlM6cy2CIjgR2yIuB9pGZkX+X0UKSoyqi7qUbRTdHFJ q * 1 W09yzWrORZ+2e9jvGPqYy5O9- * n W C @ t .tqP Q TtnJ2Z6xqbFJsY+ybuIC4qriBeIf4RfGXEnQTJAntieTE2MQ9ieNzAudsmjOc5JpUlnRjruXcorkX5unOy553PFk1WZB8OIWYEpeyP+WDIEJQLxhP5aduTR0T8oSbhU9FvqKNolGxt7hKPJLmnVaV9jjdO31D+miGT0Z1xjMJT1IreZEZkrkj801WRNberM/Zcdktf @ W ) g 6 y AOZSclJyj N n - OjUg1plrQr1zC3KLdPZisrkw3keeZtyhuTh8r35CP5c/PbFWyFF N r { 5TNGjtFKuUA4WTC+oK3hbGFt4uEi9SFrUM99m/ur5IwuCFny9kLBQuLCz` l Q $ P ! 2Lh4R T 1 _ mWfHgIr9FX 0 [  5 c p ~uxYji1MXdy4xXVK6ZHhp8NJ9y2jLspb9UOJYUlXyannc8o5Sg9KlpUMrglc0lamL k C L ) @ p w %UycturvRauWMVYZVkVe9qQ Q } F ql9VbVn8qF5VfrHCsqK74sEa45uJXTl/VfPV5bdra3kq3yu3rSOuk626s91m/r0q9akHV0IbwDa0b8Y3lG19tSt50oXpq9Y7NtM3KzQM1YTXtW8y2rNvyoTaj9nqdf13LVv2tq7e+2Sba1r/dd3vzDoMdFTve75TsvLUreFdrvUV99W7S7oLdjxpiG7q/5n7duEd3T8Wej3ulewf2Re/ranRvbNyvv7+yCW1SNo0eSDpwF m @ L5ZuAb9qb7Zp3tXBaKg7CQeXBJs W E ? n &9+mfHvjF e [ 4 ~ w uUOihzsPcw83fmX+39QjrSHkr0jq/dawto22gPaG97+iMo50dXh1Hvrf/0 a 4 : o { ? ;fu8x42N1xzWP& X O k ) s o NV56gnSg98fnkgpPjT 4 4 a U E + y Up2Snnp1OPz3Umdx590z8mWtdUV29Z0PPnj8XdO5Mt1/3yfPe549d8Lxw9CL3Ytslt0utPa49R3h d : W + $ 2 ;5w/eFIr1tvf ) b62X3y+1XPK509E3rO9Hv03/6I A | | S I |asDVc9f41y5dn3m978bsG7duJt0cuCW69@ d 6 _ + Jfh29u0XdwruTNxdeo94r/y+2v3qB/oP6n+0/rFlwG3g+GDA8 F a aYp L S Q YM/DWQ/vDgmHnv6U/9OH4dJHzEfVI0YjjY+dHx& S + ( ( o8C B , DbDRq98mTOk+GnsqcTz8p+Vv9563Or59/94vtLz1j82PAL+YvPv655qfNy76uprzrHI8cfvM55PfGm/K3O233vuO+638e9H5ko/ED+UPPR| K ( d 8 b+mPHp9BP9z7nfP78L/eE8/sl0p8zAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAEISURBVHja7NrLFYMwEENRUEtM/xW4J7PO0pgwsuepgBx8BcEfzuu6+vFhWmvnP343IpYbhw6SF, ; B x a `vDBB5+ADz4BH3wCPvgEfPB/0lqzH6zbNeqtQUWEPX54 O - EWBWgKvCOBagSvFsBqgbvVIAqwrsUoKrwDgWoMnx2AaoOn1mAgM8rQMDnM 5 ( t x 7 T TFSDHxzF7C+Krm02Oj2MF+KEX7u4FZPy9Dk01dy0g6702vMjarYDMCcWj7YVdCsieyT3eWFu9AIcp9NSW8qoFuKxdpg9TVivAadH4yjHiKgW4@ q h | v yrdZfO0Bf5QzXKXw6Aj74BHzwCfjgE/DBJ+CDTyZz9t5R4M4Hn4APPgEffAL+XrkBAAD//wMAxT+JY8GI0xgA) & ` p kAAAASUVORK5CYII=") no-repeat 0 0;
}
.xiaozhima-arrow-prev {
left: 0;
}
.xiaozhima-3 J u t U * `arrow-next {
right* : R V n c U 6: 0;
backgroundd | ~ 8 q-position: -50px 0;
}
.xiaozhima-container:hover .xiaozhima-arrow-L e 1 Tprev,
.xiaozhima-container:hover .xiaozhima-arrow-next {
displF r e ^ fay: block;
}

四、轮播图封装——JS(要点)

(( m E M c ,一)、榜首步——功用及装备项剖析

1、意图:

  • 封装一个bannerPlugin办法,能够让指M B U +定的容器完结出左右运动版的轮播图作用;

2、运用语法:

  • bannerPligin([{ b a # ` container],[options]) ;

3、参数阐明:

  • container:容3 * E 6器标签
  • options:需求装备项(这儿用户装备的参数较多,所以咱们采用( g 9 j P G –象数据类型

参数 options5 – a C i p J R{ M 9 9 k备项详解

插件封装|封装一个属于自己的轮播图插件——左右切换版

(二)、第二步—G g % P (—参数初始化

上面咱们说过了参数的处理办法有两种,咱. J b们这儿挑选依据对象健值对的办法处理;

这儿用到了咱们昨日衬托的深比较、循环迭代办法(深克隆 VS 浅克隆|深比较 VS 浅比较|回调函数),还有数据类型检测的: ? F / : ,办法,文章JS中数据类型检测四种办法的优_ r l缺点 的结尾提到过,我把他作为工具包先放在这儿

1、工具包

库房地址
咱们也能够直接CV

/* 工具包 */
(function () {
// 数据类型检测
let class2type = {};
["Boolean", "Number",Z y 0 D d "Strinb d v P % y 6g", "Function", "Array", "Date", "RegExp$ X d Z %", "Object", "Error", "Symbol"].forEach(item => {
class2type["[object 2 a )" + item + "]"] = item.toLowerCase();
});
function toType(obj) {
if (obj == null) return obj + "";
return typeof obj === "object" || typeof obj === "funcM J h R p t 3tion" ?
class2type[class2type.toString.call(obj)] || "object" :
typeof obj;
}
// 检测是否为函数
function isFunction(obj) {
return typeof obj === "funK e .ction" && typeof obj.nodeType !== "? q a bnumber";
}
// 检测window
function isWindow(obj) {
return obj != null && obj === obj.window;
}
// 数组/类数组
function isArrayLike(obj) {
var length = !!obj &L ] p X t 5 c&am_ H 2 f E # 2 Q Sp; "length" in obj && obj.l3 W : C q r V Hength,
type = toType(obj);
if (isFunction(t ? uobZ h d )j) || i= d i - 0 nsWindow(obj)) return false;
return type === "array" || length === 0 || typeof length === "number" &# / h Q |& length > 0 && (length - 1) in obj;
}
// 循环迭代
function _each(obj, callback, c9 6 c G ontext = window# R u B Z) {
if (/^(ARRAY|OBJECT)$/i.test(obL u  * 3 J l a ,j.consF W ptructor)) {
obj = _cloneDeep(obj);
}
if (isArrayLike(obj)) {
for (let i = 0;U B { ~ y ? E H / i < obj.length; i++) {
let res = callback && callback.call(context, obj[i], i);
if^ d = @ (rest J y === false) break;
if (rk Z Y `es !== undefined) obj[i] = res;
}
} else {
for (let key in obj) {
if (!obj.hasOwnPropertb g J d L ! ^y(keE 1 z S s |y)) break;
let res = callback && callback.ca) q +ll(context, obj[key], key)j . ! : H O G C;
if (res === false) bre2 } O ^ak;
if (res !== undefin9 B N red) obj[key] = res;
}
}
return obj;
}
// 深克隆
funN K ection _cl, X %oneDeep(obj) {
if (obj === null) return null;
if (typeof obj !== "object") return obj;
if (obj instanceof RegExQ Y M e jp) return new RegExp(obj);
if (obj instanceof Date) return new Date(obj);
let cloneObj = new obj.constructor;
for (let key in obj) {
if (!obj.hasOwnProperty(key)) break;
cloneObj[key] = _cloneDeep(obj[key]);
}
return cloneObj;
}
// 深比较
f~ 6  [unctionf $ 4 , H s p . _assignDeep(obj1, obj2) {
let obj = _cloneDeep(obj1A d Q k H 9 );
for (let key in obj2) {
if (!obj2.hasOwnProperty(key)) break;
let v2 = obj2[key],
v1 = obj[key];
if ((v1 !== null && typeof v1 === "object") && (v2 !== null && typeof v2 === "object")) {
obj[key] = _assignDe+ v Sep(v1, v2);
continue;
}
obj[key] = v2;
}
return obj;
}
['_each', '_cloneDeep', '_assignDeep', 'toType', 'isFuj p ] nnction',z # ~ ] / ? N 'isWG | /indow', 'isArrayLike'].forEach(item => {
window[item] = eval(item);
});
})();

2、参数初始化的意图

  • 装备默许的参数信息,当用户不传递对应参数时走默许信息
function bannerPlugin(container, optioe G k u 0 G A Tns =f ? y h L 9 6 o R {}) {v i 3 M j 8 + b
// 参数初始化:默许装备信息
let defaultParams = {
initialSl+ g Y + 1 c L :ide: 0,
autoplay: 3000,
speed: 300,
pagination: {
el: '.xiaozhima-pagination',
clickable: true
},
navigat* $ h h 6 pion: {
nextEl: ? t k'.xiaoO ? P 8 R T #zhima-arrow-next',
prevEl: '.Z c U ] Oxiaos 9 }zhima-arrow-prev'
},
on: {
init() {},
transitionSta_ a Xrt() {},
transX # E J } i )itionEnd() {}
}
};
// 使用深比较,把* U = { w :用户传递进来的参数和默许装备兼并(达到替换默许装备的作用)
options = _assignDeep(defaultParams, options);
// 判别用户传递进来的榜首个参数是否为元素容器,支撑| o r直接传递标签
typeof container === "string" ? contaj l u O hiner = document.querySelector(container) : null;
if (!container || container.nodeType !== 1) {
throw new TypeError~ c }('E 2 { F h ^ hcontainer must be an element: j S r d 4 -!');
}
return new Banner(container, optionl @ b # J ~s);
}

(三)、第三步——装备每个轮播图的私有特点

1、使用类与实例的办法完结K D f每个轮播图之间互不影响

  • 用户在运用时,每个装备信息肯定是当时轮播图私有的,所以咱们装备好的默许参数,应该是每一个实例的私有特点
class Banner3 M 2 S w T Z {
constructor(container, options) {
// 把传递进来的信息都挂载到当时类的实例上& ( ( ; E F b ?
// 1.信息都作为他的私有特点(这| I } O样每一个实例之间互不影响)
// 2.挂载到实例上,以后在当时类的其它办法中,只需确保THIS是实例,都能够依据THIS.X^ & : IXX获取和操作
_each(options, (item, key) => {
this[keyD 0 C 5 ^ ; b] = item;
});
this.container = container;
tY ] c ! @ # lhis.activeIndex = this.initialSlide;
}
}

(四)、第四步——装备公共办法(要点)

  • 上面咱们给每个轮播图实例都添加了私有特点,下面的公共办法才是要点内容

1、核算结构和款式函数 A F J g v o 5 #

  • 每一个轮播图的完结,必要的操作都是获取元素
computed() {
let {
container,
pagination,
na8 p l S # |vigation
} = this;
// 轮播图
this.wrapper = container.querySelector('.xiaozhima-wrapper');
this.slidesTrQ F ( bue = container.q$ g : 8 p yuerySelectorAll('.xiaozhima-slide');
// 克隆榜首张到容器的结尾
this.wrapper.appendChild(this.slidesTrue[0].cloneNode(true));
this.slides = containerw ( k H _ 3 1.querySelectorAll('.xiaozhima-sj F Y -lide');
// 分页器
this.paginatiB 2 f j q ? YonBox = null;
this.paginationList = null;
if (toTypef ; d 1 y L ](pagination) === "object") {
let el = pagination.el;
if (el) {
this.paginationBox = container.querySelector(el);
// 创立SPAN
let str = ``;
_each(this.slidesTrue, item => {
str += `<span></* F = v F v Q wspan>`;
});
this.paginationBox.innerHTML = str;
this.p3 h 8 ? 9 W X ]aginationList = this7 K 2 8 9 N k F t.paginationBox.querySelectorAll('span');
}
}
// 左右切换
this.af # vrrowPrev = null;F 3 Y
this.arrowNext = null;
if (toType(navigation) === "object") {
navigation.prevEl ? this.arrowPrev = container.querySelector(navigation.prevEl) : null;
navigation.nextEl ? this.arrowNext = container.querySelector(navigation.nextEl) : null;
}
// 操控元素的款式(包括初始展示哪一个)
this.chanM ~ 0 Y wgeWidth = parse4 6 %Float(getComputedStyle(container).width);q f x ; | 8 C
this.acl P E G ? d )tiveIndex = this.activeIndex < 0 ? 0 : (this.activeIndex > this.slides.length - 1 ? this.slides.li [ ! !ength - 1 : this.activeIndex);
this.wrapper.style.width = `${this.changeWidth*i r 3 e qthis.slides.length}px`;
this.wrapper L A ^ = A C y ).style.transition = `lZ :  _eft ${this.s@ # D V % t tpeed}ms`t } K u;
this.wrapper.style.left = `${-this.activeIndex*this.changeWidth}px`;
_eachy k K E m R k d c(this.slides, item => {
item.style.width = `${this.changeWidth}px`;
});
}

2、完结轮播图切换函数

// 完结轮播图切换
changeZ S V z(now = false) {
//now 传值是当即切换,不传是默许的有动画切换
let {
wrapper,
speed,
activeIns G  X K C ddex,
changeWidth,
on
} = this;
let isO = toType(on) === "object" ? true : false,
transitionStart = isO ? on.transitionStart : null,
transig 1 V E GtiI . | T ~ j # fonEnd = isO ? on.transitionEnd : null;
// 切换之前触发的钩子函数
!now && transitionStart ? transitionStart.call(this, this) : null;
// 假如传了now 当即切换,则不需求有动画
wrapper.style.transitionDur% $ i o cation = `5 n _ x - _ n + ${now?0:speed}ms: t ~ U v l C N h`;
wrapper.style.left = `${-activeIndex*changeWidth}px`;
if (now) {
// 假如当即切f 2 r换我需求让上面先烘托一次,使用读写分离;
wrapper.offsetWidth;
}
// 切换之后触发的钩子函数
let fn = () => {
!now && transitionEnd ? transitionEnd.call(this, this) : null;
// 每一次都会从头监听,所以监听完需求把上一次监听的移除掉
wrapper.removeEventListener('transitionend', fn);
};
wr4 e # t / ] % a |apper.addEventLis U 8 s b { w 3 ttener('transitionend', fn);
}

3、= R 主动轮播函数

// 主动轮播
autoMob n 7 ( s P = mve() {
if (this.activeIndex ==i s h ! . * : _= t: / Lhis.slides.leZ  F +ngth - 1) {
this.activeIndex = 0;
this.change(true);
}
this.activeIndex+$ M w o F ` +;
this.change();
}

4、焦点对齐函数

// 完结焦点对齐
autoFocus()U 7 q  % {
let {
paginationList,
activeIndex,
slides
} = this;
if (!paginationList) return;
acti2 C Q e 9 . U oveIndex === slides.length - 1 ? activeIndex = 0 : null;
_each(paginationList, (item, index) => {
if (index === activeIndex) {
item.className = 'active';
return;
}
item.className = '';
});
}

(五)Q 7 m . b ; n F Z、第五步——公共办法履行次序及条件(要点)

  • 现在完结一个轮播图功用的办法,咱们都已经封) S # n H ` j B装完结,但办法是死的,, W r g M a I 1 _只有履行才有价值,
  • 这个时候咱们就要考虑到,咱们虽然创立了这些办法,但是用户传递的参数中可能并不需求用到这些,所以咱们还需求判别用户是否需求,F U X i W # ; o假如用户需求,那咱们的履行次序又是什么;
init() {
// THIS:当时类的实例
// 入口,在这M ; 9 u M , E儿操控代码履行的逻辑次序
// 先依据它获取元素后,才能够获取实例上w X K 2 _ u 5 1 %的信息
this.computed();
let {
autoplay,
autoMove,
container,
pagination,
paginationList,
arrowNext,
arrowPrev
} = thise * :;
// 操控是否主动切换
if (autoplay) {
this.autoTimer = setInterval(autoMove.bind(this), autoplay);
// 箭头函数中的THIS是上下文中的,也便是实例
container.onmouseenter = () => clearInterval(this.au7 ? a :toTimer);
container.onmouseleave = () => this.autoTimer = setInterval(autoMove.bind(@ j fthis), autv t r j Yoplay);
}v w ,
// 操控@ z 7 5焦点切换
if (toTk s U p Y v [ype(paC g L W /gination) === "object" && pagination.clickable === true && paginationList) {
_each(paginationList, (item, indext 3 ,) => {
item.onclick = () => {
let {
activeIndex,
slides
} = this;
if ((index === activeIndex) || (index === 0 && activeIndex === slides.length - 1)) return;
this.activeIndex = in| u odex;
this.change();
};
});
}
// 操控左右按钮切换
arrowNext ? arrowNext.onclick = autoMove.bind(this) : nulH $ h s m b Z t Al;
arrowPrev ? arrowPrev.onclick = () => {
if (this.activeIndex =A H E Q 2 ? K ` .== 0) {
this.activeIndex = this.slides.le S ( E N Length - 1;
this.change(true);
}
this.activeQ I )Index--;
this.change();
} : null;
/$ i ; 2 J B a/ 初始化完结o ` % i ^ 9,触发INIT回调函数
if] q ^ { (toTypw 2 Y : I 0 De(this.on) === "object" && isFunction(this.on.init)) {
// 把回调函数履行u 2 f c b,让办法中的THI] % n D s y DS是实例,而且传递的榜首个参数也是实例
this? G w v.on.init.call(this, this);
}
}

(六)、第六步——整合优化(要点)

上面h _ 0 A G i n R 6JS代码汇总整理

  • 运用办法JS倒入即可;库房地址
    • 这儿笔者p c ~ ; `没有放地址,同样需求您创立一个banner-plugW L 1 Z ` u L ]in.js的JS文件,把代码直接张贴进去即可;
(func% R % F ? k btion () {
cS ^ #lass Banner {
constructor(container, options) {
// 把传递进来的信息都挂载到当时类的实例上
// 1.信息都作为他E - ^ y的私有特点(这样每一个实例之间互不影响)
// 2.挂载到实例上,P c u t ] z l a 以后在当时类的其它办法中,只需确保THIS+ / _ 7 ( S是实例,都能够依据THIS.XXX获取和操作
_each(options, (item, key) => {
t^ c K c H u } 0his[j b m D 4 Q  Ckey] = item;
});
this.container = container;
this.activeIndex = this.initialSlide;
this.init();
}
init() {
// THIS:当时类的实例
// 入口,在这儿操控代码履行的逻辑次序
// 先依据它获取元素后,才能够获取实例上的信息
this.computed/ = = 2();
let {
autF - k V . e Qoplay,
autoMov[ v 5 T y . L @e,
container,
pagination,
paginationList,
arrowG  4Next,8 9 v i s R 3 ( 3
arrowPrev
} = thV 8 : J ` } a %is;
/~ A E ! w/ 操控是否主动切换
if (autoplay) {
this.autoTimer = setInterval(autoMove.bind(this), autoplay);
// 箭头函数中的THIS是上下文中的,也便是实例
contl # U h F ? ) , Yainer.onmouseenter = () => clearInterval(this.autoTimer);
container.onmouseleave = () => this.autoTimer = setInterval(autoMove.bind(this), autoplay);
}
// 操控焦点切换
if (toType(pagination) === "object" && pagination.clickable === ( C true && paginationList) {
_e& E 5 hach(paginationL[ j & Oist, (item, index) =>/ ` | $ { f w {
item.onclick =* r e 9 () => {
let {
activeIndex,
slides
} = this;
if ((2 h ] C 0 D *index === activeIndex) || (index === 0 && activeIndex === slides.leB A f *ngth - 1)) return;
this.activeIndex = index;
this.change();
};
});
}
// 操控左右按钮切换
arrowNext ? arrowNext.onclick = autoMove.bind(t# A H ?his) : null;
arrowPrev ? arrowPrev.onclick = () => {
ix _ +f (this.activeIndex === 0) {
this.activeIndex = this.sl/ c e T =ides.length - 1;
this.chy o h Y 7 4ange(true);
}
this.activeIndex--;2 f ! P [ n S
this.change();
} : null;
// 初始化完结,触发3 9 Z O | m ] t &INIT回调函数
if (toType(this.on) === "object" &&x ! P isFunction(thiA ~ * M A Js.on.init)) {
// 把回调函数履行,让办法中的THIS是实例,而且J h = ^ a传递的榜首个, ^ V @ ^参数也是实例
this.on.init.call(this, this);
}
}
// 核算结构和款式
comput3 g ( h & ( q z Ped() {
let {
container,
pagination,
navigation
} = this;
// 轮播图
this.wrapper = conta2 k / Zine_ V - [r.querySelector('.xiaozhima-wrap( # D + k Oper');
this.slidesTrue = container.queryo & R . X U - OSeN s N @ r dlectorAll('.xiaoI U h O ? a O l Bzhima-slide');
// 克隆榜首张到容器的结尾
this.wrapper.appendChild(this.slidesTrue[0].cloneNode(true));
this.slides = container.querySelectorAlU & J Ml('.xiaozhima-slide');
// 分页器
this.paginn  y g n # * nationBox = null;
this.paginationList = null;
if (toType(pagination) === "object") {
let el =) o Q 8 - M * pagination.el;
if (el) {
this.paginationBox = container.querySelecto} M m x m E r qr(el);
// 创立SPAN
let str = ``;
_each(this.slidesTrue, item => {r z i ?
str += `<span></span>`;
});
this.paginati2 0 ; 3 { z = ionBox.innerHTML = str;
this.paginationListm $ K & e m P O == r d 4 O [ this.paginationBox.querySelectorAll('sp6 L .an');
}
}
// 左右切换
this.arrowPrev = null;
this.arrowNext = null;
if (toType(navigation) === "object") {
navigation.prevEl ?d N J this.arrowPrev = container.querySelecw W k $ BtorM L 5 i e(navigation.prevEl) : null;
navigation.nextEl ? this.arrowNext = container.querySelector(navigation.nextEl) :c V A W k @ null;
}
// 操控元素的款式4 d @ j q(包括初始展示哪一t w I S个)
this.changeWidth = parseFloat(getComputedStyle(container).width);
th_ 5 q l / `is.activeIndex = this.activeIndex < 0 ? 0 :( : j  ) /  (this.acti2 1 * v $ l ! zveIndex > this.slides.length - 1)  6 ? this.sliw M t S zdes.length - 1 : this.activeIndH z ; a 6 Z ^ $ex);
this.wrapper.style.width = `${this.changeWidth * this.slides.length}px`) W i;
this.wrapper.style.transition = `left ${thip y + Z C !s.speed}ms`;
this.wrapper.style.left = `${-this.activeIndex * this.changeWidth}px`;
_each(this.slides, item => {
item.style.width = `${this.changeWidth}pn d Mx`_ j B G;
});
this.autoFocus();
}
// 主动轮播
autoMove() {
iu Y & U Sf (this.activeIndex === this.slides.length - 1) {
this.activeIndex = 0;
this.change(true);
}
this.activeIndex++;
this.change();
}
// 完结轮播图切换
change(now = false) {
//now 传值是当即切换,不传是有动画切换
let {
wrapper,
speed,
a@ L w I @ D @ @ctiveIndex,
changeWidth,z o  ^ G Q ` S T
on
} = this;
let isO = toType(on) === "obje e D Fect" ? true : false,
transitionStart = isO ? on.transitionStart :W = w # [ r = e M null,
transitionEnd = isO ? on.transitionET ~ v N m + nnd : null;
// 切换之前触发的钩子函数
!now && F C; transitionStart ? tran: $ I . I J # X `sitionO h ,Start.call(this, this) : null;
// 假如传了nowH K 2 6 x N 5 ) 当即切换,则不需求有动画
wrapper.style.transitionDuratk g 9 ( jion = `${now ? 0 : speed}ms`;
wrapper.style.left = `${-activeIndex * changeWidth}px`;
if (now) {
// 假如:  / u s X O m当即切换我需求让上面先烘托一次,使用读写分离;
wrapper.offsetWidth;
} else {
this.autoFocus();
}
// 切换之后触E d i d D发的钩子函数
let fn = () => {
!now && transitionEnd ? transitionEnd.call? X - ( n & 8 @(this, this) : nu/ 0 ? . 7 | v y [ll;
// 每一次都会从头监听,所以监听完需求把上一次监听的移除掉
wrapper.remo , RveEventListener('transitionenda 6 ,', fn);
};
wrappeM G 8 f ,r.addEventListener('transit 6 ~ionend', fn);
}
// 完结焦点T S ~ % 2 O wn ) p 1 s
autoFocus() {
let {
pD % s & d } 4 x vaginationList,
activeIndex,
slidej @ ) _s
} = this;
if (!paginationList) return;
activW Y =  meIndex === slides.V p E t Q Vlength - 1 ? activeIndex = 0 : null;
_each(paginatio& s KnList,. C p 0 ? Y L Z (item, index) => {
if (index === activeIndex) {
item.~ 9 % k # * RclassR = % | _ ^ Z eNW k c ` $ f iame = 'active';
ret0 r Furn;
}
item.className = '';
});
}
}
f z x n J 1 T 2 #unction banner7 J C UPlugin(container, options = {}) {
let defaultParams = {
i. f G 5 m ( $ S QnitialSlide: 0,
autoplay: 3000,
speed: 300,
pagination: {
el: '.xiaozhima-pagination',
clickable: true
},
navigation: {
nextEl: '` K c ?  V o ,.xiaozhima-arrow-next',
prevEl: '.xiaozhima-arrow-prev'
},
on: {
init() { }C ` u,
transitionStart() { },
transitionEnd() { }
}
};
options = _assignDeep(defaultParams, optioZ s C b s Ens);
typeof container === "string" ? container =L -  / U 6 document.querySele? q lctor(container) : null;
if (!cont8 s Sainer || container.nodeType !== 1) {
throw new TypeError('container must be an elemenK + i O u & q b !t!');
}
return new Banner(container, options);
}
window.bannerPlugin = bannerPlugin;
})();

五、运用须知

  • 有必要设置的款式
    • 大容器的宽高
    • 您自己的图片
  • JS的运用语法
    • bannerPlugin(大容器,用户需求的参数信息)
      • container:容器标签
      • optiJ 4 Zons:需求装备项
        • 7 Z A , d E 4 S数信息详见 参数信息阐明
插件封装|封装一个属于自己的轮播图插件——左右切换版

笔者也在S w t & I S前端这条路上不断的学习和测验,文中内容有不对的地= B 2方,还请赐教,不胜感激e h % + N J ]

笔者想在掘金不断成长,现阶段方针升到3级,还望咱们满足,不胜感激;

发表评论

提供最优质的资源集合

立即查看 了解详情