一、如何使用
第1步:導入類庫
Unslider是基於jQuery,自然要先將Jquery庫導入
- <script src="http://code.jquery.com/jquery-latest.min.js"></script>
- <script src="http://unslider.com/unslider.js"></script>
第2步:寫HTML結構,即幻燈片列表
- <div class="banner">
- <ul>
- <li style="background:url(1.jpg)">first slide.</li>
- <li style="background:url(2.jpg)">second slide.</li>
- <li style="background:url(3.jpg)">third slide.</li>
- </ul>
- </div>
第3步:添加樣式,這里先不管漂亮,只放官網上說必須有的骨架
- .banner { position: relative; overflow: auto; }
- .banner li { list-style: none; }
- .banner ul li { float: left; }
第4步:調用unslider()方法讓幻燈片列表滾動起來,參數就先默認吧
- $(function() {
- $('.banner').unslider();
- });
好了,到這里幻燈片就如預期滾動起來了。但是不美觀,為了更加靈活定制自己想要的效果,我要潛入源代碼瞧一瞧。
二、源碼分析
- /**
- * Unslider by @idiot and @damirfoy
- * Contributors:
- * - @ShamoX
- *
- */
- (function($, f) {
- var Unslider = function() {
- // 克隆對象
- var _ = this;
- // 設置一些默認參數
- _.o = {
- speed: 500, // 動畫過渡的速度(毫秒),如果不需要過渡效果就設置為false
- delay: 3000, // 每張幻燈片的間隔時間(毫秒), 如果不是自動播放就設置為false
- init: 0, // 初始化延遲時間(毫秒),如果不需要延遲就設置為false
- pause: !f, // 當鼠標指針浮動在當前區域內時是否暫停自動播放
- loop: !f, // 是否無盡循環播放
- keys: f, // 是否開啟鍵盤導航
- dots: f, // 是否顯示導航點
- arrows: f, // 是否顯示向前和向后的箭頭
- prev: '←', // 向前按鈕中的顯示文字(或html片段)
- next: '→', // 向后......
- fluid: f, // 是否寬度自適應
- starting: f, // 在每個動畫前調用的函數
- complete: f, // 在每個動畫之后調用的函數
- items: '>ul', // 幻燈片的容器選擇器
- item: '>li', // 需要滾動的選擇器
- easing: 'swing',// 動畫的緩動函數(easing function)
- autoplay: true // 是否允許自動播放
- };
- _.init = function(el, o) {
- // 將我們在外部調用時設置的參數覆蓋掉默認參數
- _.o = $.extend(_.o, o);
- _.el = el;
- _.ul = el.find(_.o.items);//返回ul元素集合
- _.max = [el.outerWidth() | 0, el.outerHeight() | 0];//保存一下幻燈片div容器的寬和高
- _.li = _.ul.find(_.o.item).each(function(index) {
- var me = $(this),
- width = me.outerWidth(),
- height = me.outerHeight();
- // 記錄最大幻燈片的寬高
- if (width > _.max[0]) _.max[0] = width;
- if (height > _.max[1]) _.max[1] = height;
- });
- // 申請一些臨時變量
- var o = _.o,
- ul = _.ul,
- li = _.li,
- len = li.length;//li元素個數
- // 當前索引,或者叫頁碼更容易理解吧,源代碼中寫了“Current indeed”,應該是“index”吧
- _.i = 0;
- // 設置幻燈片div容器的樣式,高度初始化為第一個li的高度
- el.css({width: _.max[0], height: li.first().outerHeight(), overflow: 'hidden'});
- // 設置ul元素的位置和寬度,寬度的公式是(li元素的個數乘以100)%,我的例子中就是300%
- ul.css({position: 'relative', left: 0, width: (len * 100) + '%'});
- if(o.fluid) {
- li.css({'float': 'left', width: (100 / len) + '%'});//自適應寬度時,li元素的寬度就是把ul的寬度平均分成len份
- } else {
- li.css({'float': 'left', width: (_.max[0]) + 'px'});//不是自適應時,li元素的寬度是最大的幻燈片的寬度
- }
- // 在init毫秒后開啟自動播放
- o.autoplay && setTimeout(function() {
- if (o.delay | 0) {
- _.play();
- if (o.pause) {
- el.on('mouseover mouseout', function(e) {
- _.stop();//鼠標經過時暫停
- e.type == 'mouseout' && _.play();//鼠標離開時播放
- });
- };
- };
- }, o.init | 0);
- // 鍵盤事件處理
- if (o.keys) {
- $(document).keydown(function(e) {
- var key = e.which;
- if (key == 37)
- _.prev(); // 左箭頭按鍵
- else if (key == 39)
- _.next(); // 右箭頭按鍵
- else if (key == 27)
- _.stop(); // Esc
- });
- };
- // 顯示導航點
- o.dots && nav('dot');
- // 顯示箭頭
- o.arrows && nav('arrow');
- // 使幻燈片div容器寬度自適應
- if (o.fluid) {
- $(window).resize(function() {
- _.r && clearTimeout(_.r);
- _.r = setTimeout(function() {
- var styl = {height: li.eq(_.i).outerHeight()},
- width = el.outerWidth();
- ul.css(styl);
- //這一串真是繞,其實就是計算div占父窗口的寬度原始比例,然后記錄到styl中
- styl['width'] = Math.min(Math.round((width / el.parent().width()) * 100), 100) + '%';
- el.css(styl);//重新設置幻燈片div容器的寬度為比例而不是像素值,這樣就能達到自適應的目的了
- li.css({ width: width + 'px' });//設置li的絕對寬度,以防因div被自適應了而擠壓或拉伸了li造成內容扭曲(如有誤請大神指教)
- }, 50);//每次父窗口改變大小時,幻燈片div容器延遲50毫秒后再跟着自適應大小,請大神告訴我這樣做的目的僅僅是為了效果更自然么
- }).resize();//強制執行resize事件,使得自適應特性在最開始時就被設置好了
- };
- // 自定義move事件,這一段不太懂,求大神指點
- if ($.event.special['move'] || $.Event('move')) {
- // 為幻燈片div元素綁定movestart、move、moveend事件
- el.on('movestart', function(e) {
- if ((e.distX > e.distY && e.distX < -e.distY) || (e.distX < e.distY && e.distX > -e.distY)) {
- e.preventDefault();//鼠標位置不在當前區域時取消事件的默認動作(我猜的,關鍵是不知道distX這幾個的准確含義)
- }else{
- el.data("left", _.ul.offset().left / el.width() * 100);
- }
- }).on('move', function(e) {
- var left = 100 * e.distX / el.width();
- var leftDelta = 100 * e.deltaX / el.width();
- _.ul[0].style.left = parseInt(_.ul[0].style.left.replace("%", ""))+leftDelta+"%";
- _.ul.data("left", left);
- }).on('moveend', function(e) {
- var left = _.ul.data("left");//
- if (Math.abs(left) > 30){
- var i = left > 0 ? _.i-1 : _.i+1;
- if (i < 0 || i >= len) i = _.i;
- _.to(i);
- }else{
- _.to(_.i);
- }
- });
- };
- return _;
- };
- // 播放指定索引的幻燈片
- _.to = function(index, callback) {
- if (_.t) {
- _.stop();
- _.play();
- }
- var o = _.o,
- el = _.el,
- ul = _.ul,
- li = _.li,
- current = _.i,
- target = li.eq(index);
- //在動畫之前執行的函數,我的例子里都沒有,可以忽略它們
- $.isFunction(o.starting) && !callback && o.starting(el, li.eq(current));
- // 如果(一張幻燈片也沒有或者索引無效),並且不是循環播放,就啥也不做,我覺得這樣不好,因為to這個函數就只能在循環播放狀態下工作了
- if ((!target.length || index < 0) && o.loop == f) return;
- // 檢查索引是否有效,超出時設置為0,即第一張幻燈片
- if (!target.length) index = 0;
- if (index < 0) index = li.length - 1;//索引負數時設置為最后一張幻燈片
- target = li.eq(index);//獲取目標元素
- var speed = callback ? 5 : o.speed | 0,//執行回調函數后返回的是真則speed設為5,如果沒有回調函數或返回假則設置為o.speed
- easing = o.easing,
- obj = {height: target.outerHeight()};
- if (!ul.queue('fx').length) {//確保沒有為ul元素添加函數隊列,應該是為了防止上一次動作還沒有完成吧
- // 設置對應導航點的高亮
- el.find('.dot').eq(index).addClass('active').siblings().removeClass('active');
- // 改變幻燈片div容器的高度為目標元素的高度,並把ul的位置向左移動(index*100%),使目標元素正好在幻燈片div容器區域
- el.animate(obj, speed, easing) && ul.animate($.extend({left: '-' + index + '00%'}, obj), speed, easing, function(data) {
- _.i = index;//移動結束之后更新一下當前索引
- //動畫結束之后執行的函數,我的例子中也沒有,忽略它們
- $.isFunction(o.complete) && !callback && o.complete(el, target);
- });
- };
- };
- // 每隔delay毫秒自動播放
- _.play = function() {
- _.t = setInterval(function() {
- _.to(_.i + 1);//這里就加了1個索引號,具體的處理都封裝在了to方法中
- }, _.o.delay | 0);
- };
- // 停止自動播放
- _.stop = function() {
- _.t = clearInterval(_.t);
- return _;
- };
- // 向后翻一張
- _.next = function() {
- return _.stop().to(_.i + 1);
- };
- // 向前翻一張
- _.prev = function() {
- return _.stop().to(_.i - 1);
- };
- // 創建導航點和箭頭
- function nav(name, html) {
- if (name == 'dot') {
- html = '<ol class="dots">';
- $.each(_.li, function(index) {
- html += '<li class="' + (index == _.i ? name + ' active' : name) + '">' + ++index + '</li>';
- });
- html += '</ol>';
- /*整理一下,在我的例子中就是這副摸樣
- <ol class="dots">
- <li class="dot active">0</li>
- <li class="dot">1</li>
- <li class="dot">2</li>
- </ol>
- */
- } else {
- html = '<div class="';
- html = html + name + 's">' + html + name + ' prev">' + _.o.prev + '</div>' + html + name + ' next">' + _.o.next + '</div></div>';
- /*也整理一下
- <div class="arrows">
- <div class="arrow prev">←</div>
- <div class="arrow next">→</div>
- </div>
- */
- };
- //先給幻燈片div容器元素加上has-dots或arrows的class,再把上面組織好的元素追加為子元素,並給該子元素添加click事件處理函數
- _.el.addClass('has-' + name + 's').append(html).find('.' + name).click(function() {
- var me = $(this);
- me.hasClass('dot') ? _.stop().to(me.index()) : me.hasClass('prev') ? _.prev() : _.next();
- });
- };
- };
- // 將unslider方法擴展到jQuery對象,使任意jQuery對象都能夠直接訪問該方法,就像上面那樣:$('.banner').unslider();
- $.fn.unslider = function(o) {
- var len = this.length;
- // 遍歷li元素集
- return this.each(function(index) {
- var me = $(this),
- key = 'unslider' + (len > 1 ? '-' + ++index : ''),
- instance = (new Unslider).init(me, o);
- // 給div元素添加數據
- me.data(key, instance).data('key', key);
- });
- };
- Unslider.version = "1.0.0";
- })(jQuery, false);
三、定制自己需要的幻燈片
終於看完大部分了。好了,通過源碼至少我知道了該怎樣去控制外觀,現在我要動手啦,心里有點小激動呢~
我選擇Unslider是因為它是如此純粹,正如我想要的那樣,啥也可以不要,只要能自動循環播放、用導航點控制翻頁就滿足我的要求了。
因為默認就是自動循環播放的,所以我只要設置一個顯示導航點的參數即可,然后錦上添花也支持一下響應式吧:
- $(function() {
- $('.banner').unslider({
- dots: true, // 顯示導航點
- fluid: true // 支持響應式設計
- });
- });
通過源碼我們知道unslider為我們寫好了導航點的文檔結構、並取好了類名,但並沒有設置樣式,所以只是傳個參數是木有用滴,要自己寫樣式才能看見那些可愛的點點:
- *{margin: 0;padding: 0;}
- .banner { position: relative; top:0;overflow: auto; }
- .banner li { list-style: none; }
- .banner ul li { float: left; }
- .dots{width:66px;position:absolute;bottom:10px;left:50%;margin-left:-27px;}
- .dot{
- display:inline-block;
- width: 10px;
- height: 10px;
- font-size: 0px;
- line-height: 0px;
- margin-right: 12px;
- cursor: pointer;
- background-color: #ffffff;
- border-radius: 8px;
- }
- .dot.active{background-color: #cce8cf;}
大功告成!
四、總結
對jquery的事件機制還不熟悉,遇到自定義事件啥的就犯暈了,這塊知識還要多加學習。