TWEEN動畫、JQUERY、ES6 — 3、 輪播圖-左右運動版本

weixin_33686714發表於2018-11-05

封裝banner外掛(完整版)

左右運動版輪播圖

  • 自動切換並且實現無縫斜街

  • 點選焦點切換

  • 點選左右切換

  • 封裝輪播圖外掛

  • ...

    window.onload=function(){}容易被覆蓋掉的解決方案

    什麼時候執行延遲載入:當頁面載入成功才執行延遲載入。

    window.onload=function(){};但是window.onload在當前頁面只能執行一次,所以容易被覆蓋掉,最好不用

    所以可以用window.addEventListener('load');但是不相容

    所以這裡用定時器setTimeout();當整個js同步都執行完後(頁面都載入完後)才會執行這個非同步

    所以很多時候都用定時器setTimeout()來代替window.onload

    目錄

思路

banner.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
    <!--<link rel="stylesheet/less" href="css/banner.less">
    <script src="js/less-2.5.3.min.js"></script>-->
    <link rel="stylesheet" href="css/banner.min.css">
</head>
<body>
<!--BANNER-->
<div class="container" id="container">
    <!--WRAPPER-->
    <ul class="wrapper clearfix">
        <!--<li class="slide">
            <a href="#">
                <img src="img/banner1.jpg" alt="">
            </a>
        </li>-->
    </ul>
    <!--FOCUS-BOX-->
    <ul class="focusBox clearfix">
        <!--<li class="select"></li>
        <li></li>-->
    </ul>
    <!--ARROW-->
    <a href="javascript:;" class="arrow arrowLeft"></a>
    <a href="javascript:;" class="arrow arrowRight"></a>
</div>

<div class="container" id="container2">
    <!--WRAPPER-->
    <ul class="wrapper clearfix">
    </ul>
    <!--FOCUS-BOX-->
    <ul class="focusBox clearfix">
        <!--<li class="select"></li>
        <li></li>-->
    </ul>
</div>

<!--IMPORT JS-->
<script src="js/utils.min.js"></script>
<script src="js/animate.min.js"></script>
<script src="js/banner.js"></script>
</body>
</html>
複製程式碼

banner.less

@import "reset";

.container {
  @W: 1000px;
  @H: 300px;

  position: relative;
  margin: 20px auto;
  width: @W;
  height: @H;
  text-align: center;
  overflow: hidden;
  background: url("../img/default.gif") no-repeat center center #EEE;

  .wrapper {
    position: absolute;
    top: 0;
    left: 0;
    width: unit(unit(@W,px)*10, px); //=>需要在JS中根據獲取的資料動態設定寬度
    height: @H;

    .slide {
      float: left;
      width: @W;
      height: @H;

      a {
        display: block;
        width: @W;
        height: @H;

        img {
          display: none;
          width: @W;
          height: @H;
          opacity: 0;
          filter: alpha(opacity=0);
        }
      }
    }
  }

  .focusBox {
    display: inline-block;
    position: relative;
    top: unit(unit(@H,px)-30, px);
    z-index: 999;
    padding: 4px;
    background: #999;
    background: rgba(0, 0, 0, .5);
    border-radius: 20px;

    li {
      float: left;
      margin: 0 4px;
      width: 12px;
      height: 12px;
      background: #FFF;
      border-radius: 50%;
      cursor: pointer;

      &.select {
        background: #E01D20;
      }
    }
  }

  .arrow {
    display: none;
    position: absolute;
    top: 50%;
    margin-top: -22.5px;
    width: 28px;
    height: 45px;
    background: url("../img/pre.png") no-repeat;
    opacity: 0.5;
    filter: alpha(opacity=50);

    &.arrowLeft {
      left: 0;
    }

    &.arrowRight {
      right: 0;
      background-position: -50px 0;
    }

    &:hover {
      opacity: 1;
      filter: alpha(opacity=100);
    }
  }

}
複製程式碼

reset.less

body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, dl, dt, dd, ul, ol, li, button, input, textarea, th, td {
  margin: 0;
  padding: 0
}

body {
  font-size: 12px;
  font-style: normal;
  font-family: "\5FAE\8F6F\96C5\9ED1", Helvetica, sans-serif
}

small {
  font-size: 12px
}

h1 {
  font-size: 18px
}

h2 {
  font-size: 16px
}

h3 {
  font-size: 14px
}

h4, h5, h6 {
  font-size: 100%
}

ul, ol {
  list-style: none
}

a {
  text-decoration: none;
  background-color: transparent
}

a:hover, a:active {
  outline-width: 0;
  text-decoration: none
}

table {
  border-collapse: collapse;
  border-spacing: 0
}

hr {
  border: 0;
  height: 1px
}

img {
  border-style: none
}

img:not([src]) {
  display: none
}

svg:not(:root) {
  overflow: hidden
}

html {
  -webkit-touch-callout: none;
  -webkit-text-size-adjust: 100%
}

input, textarea, button, a {
  -webkit-tap-highlight-color: rgba(0, 0, 0, 0)
}

article, aside, details, figcaption, figure, footer, header, main, menu, nav, section, summary {
  display: block
}

audio, canvas, progress, video {
  display: inline-block
}

audio:not([controls]), video:not([controls]) {
  display: none;
  height: 0
}

progress {
  vertical-align: baseline
}

mark {
  background-color: #ff0;
  color: #000
}

sub, sup {
  position: relative;
  font-size: 75%;
  line-height: 0;
  vertical-align: baseline
}

sub {
  bottom: -0.25em
}

sup {
  top: -0.5em
}

button, input, select, textarea {
  font-size: 100%;
  outline: 0
}

button, input {
  overflow: visible
}

button, select {
  text-transform: none
}

textarea {
  overflow: auto
}

button, html [type="button"], [type="reset"], [type="submit"] {
  -webkit-appearance: button
}

button::-moz-focus-inner, [type="button"]::-moz-focus-inner, [type="reset"]::-moz-focus-inner, [type="submit"]::-moz-focus-inner {
  border-style: none;
  padding: 0
}

button:-moz-focusring, [type="button"]:-moz-focusring, [type="reset"]:-moz-focusring, [type="submit"]:-moz-focusring {
  outline: 1px dotted ButtonText
}

[type="checkbox"], [type="radio"] {
  box-sizing: border-box;
  padding: 0
}

[type="number"]::-webkit-inner-spin-button, [type="number"]::-webkit-outer-spin-button {
  height: auto
}

[type="search"] {
  -webkit-appearance: textfield;
  outline-offset: -2px
}

[type="search"]::-webkit-search-cancel-button, [type="search"]::-webkit-search-decoration {
  -webkit-appearance: none
}

::-webkit-input-placeholder {
  color: inherit;
  opacity: .54
}

::-webkit-file-upload-button {
  -webkit-appearance: button;
  font: inherit
}

.clearfix:after {
  display: block;
  height: 0;
  content: "";
  clear: both
}
複製程式碼

banner.js

~function (options) {
    var container = document.getElementById('container'),
        containerChild = utils.children(container),
        wrapper = containerChild[0],
        focusBox = containerChild[1],
        arrowLeft = containerChild[2],
        arrowRight = containerChild[3];
    var slideList = null,
        imgList = null,
        focusList = null,
        bannerData = null,
        containerWidth = container.clientWidth;

    //=>INIT PARAMETERS 預設設定
    var _default = {
        initIndex: 0,
        autoInterval: 2000
    };
    //遍歷options替換預設設定
    for (var key in options) {
        if (options.hasOwnProperty(key)) {
            _default[key] = options[key];
        }
    }
    var initIndex = _default.initIndex,
        autoInterval = _default.autoInterval;

    //=>GET DATA & BIND DATA 
    ~function () {
        //->AJAX GET DATA 獲取資料
        var xhr = new XMLHttpRequest();
        xhr.open('GET', 'json/banner.json', false);
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4 && xhr.status === 200) {
                bannerData = utils.toJSON(xhr.responseText);
            }
        };
        xhr.send(null);

        //->BIND DATA 繫結資料
        var str = ``,
            strFocus = ``;
        for (var i = 0; i < bannerData.length; i++) {
            var item = bannerData[i];
            str += `<li class="slide">
                <a href="${item.link}">
                    <img src="" data-img="${item.img}" alt="${item.desc}">
                </a>
            </li>`;

            strFocus += `<li></li>`;
        }
        wrapper.innerHTML = str;
        focusBox.innerHTML = strFocus;

        //->GET ELEMENT LIST
        slideList = wrapper.getElementsByTagName('li');
        imgList = wrapper.getElementsByTagName('img');
        focusList = focusBox.getElementsByTagName('li');

        //=>CLONE  克隆第一張到末尾  cloneNode(true)深度克隆
        wrapper.appendChild(slideList[0].cloneNode(true));

        //->COMPUTED WRAPPER WIDTH 
        utils.css(wrapper, 'width', (bannerData.length + 1) * containerWidth);
    }();

    //=>INIT SHOW & LAZY IMG
    ~function () {
        //->FOCUS DEFAULT SHOW
        for (var i = 0; i < focusList.length; i++) {
            focusList[i].className = i === initIndex ? 'select' : null;
        }

        //->WRAPPER DEFAULT SHOW
        utils.css(wrapper, 'left', -containerWidth * initIndex);

        //->LAZY IMG 懶載入
        // 什麼時候執行延遲載入:當頁面載入成功才執行延遲載入
        // window.onload=function(){};但是window.onload在當前頁面只能執行一次,所以容易被覆蓋掉,最好不用。
        // 所以可以用window.addEventListener('load');但是不相容
        // 所以這裡用定時器setTimeout();當整個js同步都執行完後(頁面都載入完後)才會執行這個非同步,所以這裡500ms可以寫成0ms也行
        // 所以很多時候都用定時器setTimeout()來代替window.onload

        var timer = setTimeout(function () {
            for (var k = 0; k < imgList.length; k++) {
                lazyImg(imgList[k]);
            }
            clearTimeout(timer);
        }, 500);

        function lazyImg(curImg) {
            var tempImg = new Image;
            tempImg.onload = function () {
                curImg.src = this.src;
                curImg.style.display = 'block';
                animate({
                    curEle: curImg,
                    target: {opacity: 1},
                    duration: 200
                });
                tempImg = null;
            };
            tempImg.src = curImg.getAttribute('data-img');
        }
    }();

    //=>AUTO CHANGE 自動切換 當運動到最後一張,讓wrapper瞬移到第一張,並且讓initIndex = 1,再執行動畫就從第二張開始
    var autoTimer = null;
    autoTimer = setInterval(autoMove, autoInterval);
    function autoMove() {
        initIndex++;
        if (initIndex === bannerData.length + 1) {
            utils.css(wrapper, 'left', 0);
            initIndex = 1;
        }
        change();
    }

    //=>MOUSE EVENT 
    
    container.onmouseenter = function () {
        clearInterval(autoTimer);
        arrowLeft.style.display = arrowRight.style.display = 'block';
    };
    container.onmouseleave = function () {
        autoTimer = setInterval(autoMove, autoInterval);
        arrowLeft.style.display = arrowRight.style.display = 'none';
    };

    //=>BIND FOCUS EVENT
    ~function () {
        for (var i = 0; i < focusList.length; i++) {
            focusList[i].myIndex = i;
            focusList[i].onclick = function () {
                initIndex = this.myIndex;
                change();
            }
        }
    }();

    //=>BIND ARROW EVENT
    ~function () {
        arrowRight.onclick = autoMove;
        arrowLeft.onclick = function () {
            initIndex--;
            if (initIndex === -1) {
                //->RUN TO CLONE ELEMENT
                utils.css(wrapper, 'left', -bannerData.length * containerWidth);
                initIndex = bannerData.length - 1;
            }
            change();
        }
    }();

    //=>CHANGE
    function change() {
        animate({
            curEle: wrapper,
            target: {left: -initIndex * containerWidth},
            duration: 300
        });

        //->CHANGE FOCUS
        var tempIndex = initIndex;
        tempIndex === bannerData.length ? tempIndex = 0 : null;
        for (var i = 0; i < focusList.length; i++) {
            focusList[i].className = i === tempIndex ? 'select' : null;
        }
    }
}();
複製程式碼
banner.json
複製程式碼
[
  {
    "id": 1,
    "img": "img/banner1.jpg",
    "desc": "推薦機會",
    "link": "http://www.baidu.com/"
  },
  {
    "id": 2,
    "img": "img/banner2.jpg",
    "desc": "夢想起飛",
    "link": "http://www.baidu.com/"
  },
  {
    "id": 3,
    "img": "img/banner3.jpg",
    "desc": "把握未來",
    "link": "http://www.baidu.com/"
  },
  {
    "id": 4,
    "img": "img/banner4.jpg",
    "desc": "先學習",
    "link": "http://www.baidu.com/"
  }
]
複製程式碼

封裝banner外掛(封裝外掛的基本思路)

外掛思想:功能越強大越好

首先理解jq中最難理解的部分:

如何讓一個函式執行,建立一個屬於自己函式和這個類的例項

~function () {
    function BannerPlugin(options) {//建構函式建立一個類  options配置引數
        return new BannerPlugin.fn.init(options);
    }

    BannerPlugin.fn = BannerPlugin.prototype = {};

    var init = BannerPlugin.fn.init = function (options) {

    };

    init.prototype = BannerPlugin.prototype;

}();

//--------------------------以上可以簡寫成以下-----------------------------------------
// 封裝外掛直接用建構函式模式 先寫一個自執行函式~function (){},
// 在裡面建立一個類BannerPlugin(),
// 執行BannerPlugin()會配置很多引數,很多引數用options來配置
~function () {

    function BannerPlugin(options) { 
        // 執行BannerPlugin這個方法建立的是init對應函式的例項,
        // 但是會用到BannerPlugin.prototype原型上的方法,所以 
        // BannerPlugin.prototype.init.prototype = BannerPlugin.prototype;
        return new BannerPlugin.prototype.init(options);
    }
    
    BannerPlugin.prototype = {
        //為了保證完建構函式完整性,constructor:BannerPlugin 
        //見JS中的閉包及物件導向程式設計 — 2、物件導向程式設計詳解 19-2重新構造原型(最常用))
        constructor:BannerPlugin,
        init:function (options) { // 建立的是init時有個形參options,這裡需要通過options接收
            // 這裡的this也可以呼叫BannerPlugin原型上的方法  看到20:20
        }
    };
    // 讓INIT的原型指向BANNER-PLUGIN的原型,目的:當執行BANNER-PLUGIN方法的時候建立出來的依然是BANNER-PLUGIN類的例項
    BannerPlugin.prototype.init.prototype = BannerPlugin.prototype;

    console.dir(BannerPlugin({}));//直接執行BannerPlugin()先建立init例項,由init例項再變成BannerPlugin例項,不用再通過newBannerPlugin()去建立BannerPlugin例項

    window.$banner = window.BannerPlugin = BannerPlugin;//暴露BannerPlugin
}();

BannerPlugin({});
$banner({});

複製程式碼

圖解:

首先一個類BannerPlugin(),有屬性prototype;

BannerPlugin.prototype開闢一個新堆記憶體;(自己開闢的新堆記憶體沒有constructor, 為了保證完建構函式完整性,constructor:BannerPlugin 見JS中的閉包及物件導向程式設計 — 2、物件導向程式設計詳解 19-2重新構造原型(最常用));

原型prototype的_proto_都指向Object的原型

BannerPlugin.prototype裡面有個init方法,方法又是一個堆記憶體BannerPlugin.prototype.init (BannerPlugin.prototype.init又是一個函式資料型別,有屬性prototype)

BannerPlugin.prototype.init.prototype = BannerPlugin.prototype:讓init的原型指向BannerPlugin的原型, 目的:當執行BannerPlugin方法的時候會通過return new BannerPlugin.prototype.init(options)建立init這個方法 的例項(init的例項),init的例項有_proto_指向所屬類的原型,最終還是指向了BannerPlugin的原型,所以創 建的init依然是BannerPlugin類的例項

為什麼要這麼做呢,為什麼不直接建立BannerPlugin這個類的例項呢?

這麼做有個好處=>直接執行BannerPlugin({})返回的例項就是BannerPlugin()這個類的例項,不再需要通過new BannerPlugin()去建立這個類的例項, 而是通過先建立init例項,由init例項再變成BannerPlugin例項(通過console.dir(BannerPlugin({}))列印出來看是個死迴圈巢狀, 在原型裡面是沒有這個概念的,因為constructor建構函式雖然指向BannerPlugin,但是和普通類還是有所區別,並不會形成死迴圈)如圖:

這個怎麼去找上級?

init例項裡面沒有通過_proto_找到BannerPlugin.prototype,BannerPlugin.prototype沒有再通過BannerPlugin.prototype.proto 找到Object.prototype。(這裡上級查詢不會去找BannerPlugin.prototype裡的constructor,這個不會形成死迴圈)

封裝外掛

看懂了jq最難理解的部分,接下來一步步寫外掛

plugin-banner.js參照banner.js封裝成外掛的,對應banner.js看(方法裡面的程式碼都是複製貼上,改變引數,涉及utils的用原生,this...),注意this,並且把很多屬性方法寫在私有屬性上就可以了。

plugin-banner.js

/*
 * 分析我們需要支援的部分:
 * [基礎]
 *   資料動態繫結的地址是不同的 (url)
 *   切換速度 (speed:300)
 *   預設展示第幾張 (initIndex:0)
 *   延遲多久進行圖片懶載入 (lazyImgTime:500)
 *
 * [自動切換]
 *   是否支援自動切換 (needAutoChange:true)
 *   自動切換的間隔時間 (autoInterval:2000)
 *
 * [焦點]
 *   是否顯示焦點 (isFocusShow:true)
 *   是否需要通過焦點切換 (needFocusChange:true)
 *   什麼樣的事件控制焦點切換 (focusEvent:click)
 *
 * [左右切換]
 *   是否支援左右切換 (isArrowShow:true)
 */
~function () {
    function BannerPlugin(options) { 
        return new BannerPlugin.prototype.init(options);
    }

    BannerPlugin.prototype = {
        constructor: BannerPlugin,
        //=>1、宣告可擴充引數的預設值,並且讓傳遞引數的值OPTIONS替換原有的預設值(把需要用的引數擴充套件到例項的私有屬性上)
        initDefault: function (options) {
            var _default = {
                container: null,
                url: null,
                initIndex: 0,
                speed: 300,
                lazyImgTime: 500,
                needAutoChange: true,
                autoInterval: 2000,
                isFocusShow: true,
                needFocusChange: true,
                focusEvent: 'click',
                isArrowShow: true
            };
            //=>迴圈options替換預設值
            for (var key in options) {
                if (options.hasOwnProperty(key)) {
                    _default[key] = options[key];
                }
            }
            //=>把_DEFAULT中的每一項遍歷到THIS例項上(寫到私有屬性上)後銷燬_default
            for (key in _default) {
                if (_default.hasOwnProperty(key)) {
                    this[key] = _default[key];
                }
            }
            _default = null;
        },

        //=>3、AJAX資料繫結(複製banner.js中的程式碼邏輯,修改url,把bannerData擴充到例項上,獲取元素和克隆)
        // 這裡ajax用的同步程式設計,專案中用非同步(需要用到promise),(所以這個封裝是個入門的外掛,不建議專案中使用,同步會有問題)
        queryData: function () {
            var xhr = new XMLHttpRequest(),
                bannerData = null;
            xhr.open('GET', this.url, false);
            xhr.onreadystatechange = function () {
                if (xhr.readyState === 4 && xhr.status === 200) {
                    bannerData = JSON.parse(xhr.responseText);
                }
            };
            xhr.send(null);

            //=>擴充到例項上,方便以後再其它方法中使用
            this.bannerData = bannerData;
        },
        bindData: function () {
            var str = ``,
                strFocus = ``;
            for (var i = 0; i < this.bannerData.length; i++) {
                var item = this.bannerData[i];
                str += `<li class="slide">
                <a href="${item.link}">
                    <img src="" data-img="${item.img}" alt="${item.desc}">
                </a>
            </li>`;

                strFocus += `<li data-index="${i}"></li>`;
            }
            this.wrapper.innerHTML = str;
            this.isFocusShow ? this.focusBox.innerHTML = strFocus : null;

            //=>其它事情
            this.slideList = this.wrapper.getElementsByTagName('li');
            this.imgList = this.wrapper.getElementsByTagName('img');
            this.isFocusShow ? this.focusList = this.focusBox.getElementsByTagName('li') : null;

            //=>克隆第一張到末尾
            this.wrapper.appendChild(this.slideList[0].cloneNode(true));
            this.wrapper.style.width = (this.bannerData.length + 1) * this.containerWidth;
        },

        //=>6、圖片延遲載入
        lazyImg: function () {
            var _this = this;
            var timer = setTimeout(function () {//setTimeout中的this是window
                [].forEach.call(_this.imgList, function (curImg) {
                    var tempImg = new Image;
                    tempImg.onload = function () {
                        curImg.src = this.src;
                        curImg.style.display = 'block';
                        animate({
                            curEle: curImg,
                            target: {opacity: 1},
                            duration: 200
                        });
                        tempImg = null;
                    };
                    tempImg.src = curImg.getAttribute('data-img');
                });
                clearTimeout(timer);
            }, this.lazyImgTime);
        },

        //=>8、預設展示
        showInit: function () {
            var _this = this;
            if (_this.isFocusShow) {
                [].forEach.call(_this.focusList, function (item, index) {
                    item.className = index === _this.initIndex ? 'select' : null;
                });
            }
            _this.wrapper.style.left = -_this.containerWidth * _this.initIndex + 'px';
        },

        //=>10、自動切換
        change: function () {
            animate({
                curEle: this.wrapper,
                target: {left: -this.initIndex * this.containerWidth},
                duration: this.speed
            });

            //->CHANGE FOCUS
            if (this.isFocusShow) {
                var tempIndex = this.initIndex;
                tempIndex === this.bannerData.length ? tempIndex = 0 : null;
                [].forEach.call(this.focusList, function (item, index) {
                    item.className = index === tempIndex ? 'select' : null;
                });
            }
        },
        autoMove: function () {
            this.initIndex++;
            if (this.initIndex === this.bannerData.length + 1) {
                this.wrapper.style.left = 0;
                this.initIndex = 1;
            }
            this.change();
        },

        //=>12、其它切換方式
        mouseEvent: function () {
            var _this = this;
            _this.container.onmouseenter = function () {
                _this.needAutoChange ? clearInterval(_this.autoTimer) : null;
                _this.isArrowShow ? _this.arrowLeft.style.display = _this.arrowRight.style.display = 'block' : null;
            };

            _this.container.onmouseleave = function () {
                _this.needAutoChange ? _this.autoTimer = setInterval(_this.autoMove.bind(_this), _this.autoInterval) : null;
                _this.isArrowShow ? _this.arrowLeft.style.display = _this.arrowRight.style.display = 'none' : null;
            };
        },
        arrowEvent: function () {
            var _this = this;
            if (!_this.isArrowShow) return;
            _this.arrowRight.onclick = _this.autoMove.bind(_this);//保證_this.autoMove方法中的this是例項
            _this.arrowLeft.onclick = function () {
                _this.initIndex--;
                if (_this.initIndex === -1) {
                    _this.wrapper.style.left = -_this.bannerData.length * _this.containerWidth + 'px';
                    _this.initIndex = _this.bannerData.length - 1;
                }
                _this.change();
            }
        },
        eventFocus: function () {
            var _this = this;
            if (!_this.isFocusShow) return;
            if (!_this.needFocusChange) return;
            [].forEach.call(_this.focusList, function (item, index) {
                item['on' + _this.focusEvent] = function () {
                    _this.initIndex = index;
                    _this.change();
                }
            });
        },
        delegateEvent: function () {
            var _this = this;
            _this.container.onclick = function (e) {
                e = e || window.event;
                var target = e.target || e.srcElement,
                    targetParent = target.parentNode;

                //=>焦點事件源
                if (/(^| +)focusBox( +|$)/i.test(targetParent.className)) {
                    _this.initIndex = parseFloat(target.getAttribute('data-index'));
                    _this.change();
                    return;
                }

                //=>左右切換事件源
                if (/(^| +)arrow( +|$)/i.test(target.className)) {
                    if (target.className.indexOf('arrowRight') > -1) {
                        _this.autoMove();
                        return;
                    }
                    _this.initIndex--;
                    if (_this.initIndex === -1) {
                        _this.wrapper.style.left = -_this.bannerData.length * _this.containerWidth + 'px';
                        _this.initIndex = _this.bannerData.length - 1;
                    }
                    _this.change();
                }
            };
        },
        init: function (options) {
            //=>2、引數初始化
            this.initDefault(options);

            //=>4、獲取需要使用的到的元素

            // var container = document.getElementById('container'),
            //     containerChild = utils.children(container),
            //     wrapper = containerChild[0],
            //     focusBox = containerChild[1],
            //     arrowLeft = containerChild[2],
            //     arrowRight = containerChild[3];
            // var slideList = null,
            //     imgList = null,
            //     focusList = null,
            //     bannerData = null,
            //     containerWidth = container.clientWidth;

            // 以上可以寫成
           
            // this.wrapper = this.container.querySelector('.wrapper');
            // this.focusBox = this.container.querySelector('.focusBox');
            // this.arrowLeft = this.container.querySelector('.arrowLeft');
            // this.arrowRight = this.container.querySelector('.arrowRight');
            // this.containerWidth = this.container.clientWidth;
            // var slideList = null,
            //     imgList = null,
            //     focusList = null;

            // 以上可以寫成

            var _this = this;
            ['wrapper', 'focusBox', 'arrowLeft', 'arrowRight'].forEach(function (item, index) {
                _this[item] = _this.container.querySelector('.' + item);
            });
            this.containerWidth = this.container.clientWidth;

            //=>5、資料繫結
            this.queryData();
            this.bindData();

            //=>7、圖片延遲載入
            this.lazyImg();

            //=>9、預設展示
            this.showInit();

            //=>11、自動切換

            // this.autoTimer = setInterval(function(){
            //     _this.autoMove();
            // },this.autoInterval);
            // 或者這樣寫
            // this.autoTimer = setInterval(this.autoMove.bind(this),this.autoInterval);
            if (this.needAutoChange) {
                this.autoTimer = setInterval(this.autoMove.bind(this), this.autoInterval);
            }

            //=>13、其它方式切換
            this.mouseEvent();
            // this.arrowEvent();
            // this.eventFocus();
            this.delegateEvent();
        }
    };

    // 14、深度擴充套件(類似jq一樣,支援extend自己擴充套件方法,別人可以自己擴充套件方法,)
    BannerPlugin.extend = function (obj, deep) {
        typeof deep === 'undefined' ? deep = false : null;
        for (var key in obj) {
            //迴圈obj,替換外掛原有方法,如果傳遞的obj中的方法在原外掛中有,就continue不執行BannerPlugin.prototype[key] = obj[key];
            // 如果傳遞的obj中的方法在原外掛中有,並且deep是true的時候,替換到原型上方法執行BannerPlugin.prototype[key] = obj[key];
            if (obj.hasOwnProperty(key)) {
                if (BannerPlugin.prototype.hasOwnProperty(key)) {
                    if (deep) {
                        BannerPlugin.prototype[key] = obj[key];
                    }
                    continue;
                }
                BannerPlugin.prototype[key] = obj[key];
            }
        }
    };

    //=>讓INIT的原型指向BANNER-PLUGIN的原型,目的:當執行BANNER-PLUGIN方法的時候建立出來的依然是BANNER-PLUGIN類的例項
    BannerPlugin.prototype.init.prototype = BannerPlugin.prototype;
    window.$banner = window.BannerPlugin = BannerPlugin;
}();


$banner({
    container: document.getElementById('container'),
    url: 'json/banner.json',
    autoInterval: 3000,
    initIndex: 2
});

var bannerExample = $banner({
    container: document.getElementById('container2'),
    url: 'json/banner2.json',
    needFocusChange: false,
    isArrowShow: false,
    speed: 100,
    lazyImgTime: 2000
});

// true深度擴充套件,把外掛原有方法替換掉
// $banner.extend({
//     aa: function () {

//     }
// }, true);
// bannerExample.aa();//別人可以通過自己擴充套件aa()這個方法做一些其他的功能

//替換原型上的change方法
$banner.extend({
    change: function () {
        animate({
            curEle: this.wrapper,
            target: {left: -this.initIndex * this.containerWidth},
            duration: this.speed,
            effect: animateEffect.Bounce.easeOut
        });

        //->CHANGE FOCUS
        if (this.isFocusShow) {
            var tempIndex = this.initIndex;
            tempIndex === this.bannerData.length ? tempIndex = 0 : null;
            [].forEach.call(this.focusList, function (item, index) {
                item.className = index === tempIndex ? 'select' : null;
            });
        }
    }
}, true);
bannerExample.speed = 500;

複製程式碼

banner.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
    <!--<link rel="stylesheet/less" href="css/banner.less">
    <script src="js/less-2.5.3.min.js"></script>-->
    <link rel="stylesheet" href="css/banner.min.css">
</head>
<body>
<!--BANNER-->
<div class="container" id="container">
    <!--WRAPPER-->
    <ul class="wrapper clearfix">
        <!--<li class="slide">
            <a href="#">
                <img src="img/banner1.jpg" alt="">
            </a>
        </li>-->
    </ul>
    <!--FOCUS-BOX-->
    <ul class="focusBox clearfix">
        <!--<li class="select"></li>
        <li></li>-->
    </ul>
    <!--ARROW-->
    <a href="javascript:;" class="arrow arrowLeft"></a>
    <a href="javascript:;" class="arrow arrowRight"></a>
</div>

<div class="container" id="container2">
    <!--WRAPPER-->
    <ul class="wrapper clearfix">
    </ul>
    <!--FOCUS-BOX-->
    <ul class="focusBox clearfix">
        <!--<li class="select"></li>
        <li></li>-->
    </ul>
</div>

<!--IMPORT JS-->
<script src="js/utils.min.js"></script>
<script src="js/animate.min.js"></script>
<script src="js/plugin-banner.js"></script>
</body>
</html>
複製程式碼

banner2.json

[
  {
    "id": 1,
    "img": "img/banner1.jpg",
    "desc": "推薦機會",
    "link": "http://www.baidu.com/"
  },
  {
    "id": 2,
    "img": "img/banner2.jpg",
    "desc": "夢想起飛",
    "link": "http://www.baidu.com/"
  },
  {
    "id": 3,
    "img": "img/banner3.jpg",
    "desc": "把握未來",
    "link": "http://www.baidu.com/"
  }
]
複製程式碼

相關文章