jQuery插件寫法小結之重寫輪播圖功能

最近在維護老網站的時候,發現一些jQuery庫的使用有些臃腫,而且大部分自定義的js文件很容易污染全局變量,因此想着重寫下,雖然jQuery的輝煌時代已通過去了,可是他的思想,依舊燦爛(滾去維護去)css

先舉個栗子

;(function($) {
  var methods = {
    init: function(options) {
      // 可自定義擴展項
      options = $.extend(
        true,
        {}, 
        $.fn.myPlugin.defaults,
        options
      );
      console.log('options', options, this)
  
      return this;
    },
    getName: function() {
      console.log('Name is ', $.fn.myPlugin.defaults.name, '.')
    },
    getAge: function() {
      console.log('Age is ', $.fn.myPlugin.defaults.age, '.')
    },
    show: function(){
      return this.each(function(){
        this.style.display == "none" && (this.style.display = '')
        if (getComputedStyle(this, '').getPropertyValue("display") == "none")
          this.style.display = defaultDisplay(this.nodeName)
      })
    },
    hide: function() {
      return this.css("display", "none")
    }
  };

  // 命名空間最好只有一個
  $.fn.myPlugin = function(method) {

    // 方法調用,可知足三種狀況:1. method, 2. init, 3. error
    if(methods[method]) {
      return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));  //將具備length屬性的對象轉成數組
    } else if(typeof method === 'object' || !method) {
      // 若是沒有參數或者參數
      return methods.init.apply(this, arguments);
    } else {
      $.error('Method' + method + 'does not exist on jQuery.myPlugin.');
    }
  }

  $.fn.myPlugin.defaults =  {
    'name': 'zhangsan',
    'age': '20'
  };
})(jQuery)

/* --- 測試 --- */

// 初始化init
$('#testPara').myPlugin()

// 修改參數
$('#testPara').myPlugin({
    'name': 'wuwang',
    'age': '27'
})

// 調取方法
$('#testPara').myPlugin('hide')
$('#testPara').myPlugin('show')

複製代碼

簡單易懂,可是五臟俱全,接下來簡單說明:node

搞定複雜參數列表

首先,咱們通常傳參以下:數組

function foo(a1, a2, a3, a4) { }

foo(1, 2, 3, 4)
複製代碼

那若是不傳參吶?瀏覽器

foo(1, null, 3, 4)
複製代碼

就須要如上使用 null 來站位,參數多了,保證你暈。app

因此,咱們使用 可選哈希參數(options hash),如:ide

foo(1, null, null, 4)
// 改爲
foo(1, {
    a4: 4
})
複製代碼

接着,咱們使用 jQuery 的 $.extend() 工具函數合併可選參數,並設置默認值:函數

function foo (a1, options) {
    var settings = $.extend({
        a2: value2,
        a3: value3,
        a4: value4
    }, options || {} );
}
複製代碼

最後,就有了栗子中形態:工具

var settings = $.extend(
    true,  // 是否爲深拷貝
    {},    // 使用源元素屬性來擴展目標對象
    $.fn.myPlugin.defaults,  // 默認的一個對象,將屬性添加到 target(即{}) 目標對象中
    options  // 多個源後會覆蓋前面同名的屬性
);
複製代碼

這樣,就不再會糾結參數的不傳或者多個佔位傳參,挺好。測試

實際操做下:先看一個多個參數的:網站

$('#btn').myPlugin({
  'mynewname': 'lisi',
  'mynewage': 22
})
// 打印settings: {name: "zhangsan", age: "20", mynewname: "lisi", mynewage: 22}
複製代碼

再看一個:

$('#btn').myPlugin({
  'name': 'lisi',
  'mynewage': 22
})

// {name: "lisi", age: "20", mynewage: 22}
複製代碼

一看就懂,有則覆蓋,無則添加,完美。

統一命名空間

因爲是jQuery插件,都掛載在 jQuery 對象下,因此恰當命名空間的插件儘量不與其餘插件衝突,甚至是 jQuery 的核心庫方法。

好比:

(function($) {
    var defaults = {}  // 定義默認項
    var methods = {}  // 定義方法
    $.fn.myPlugin = function(method) {}  // 定義 myPlugin 命名空間並賦值一個匿名函數
}(jQuery)
複製代碼

容許公開訪問默認設置

爲了更加的定製化,咱們須要暴露默認的設置,這樣咱們就能夠修改設置了。

首先修改 defaults 變量,爲了暴露給外部世界,須要把它賦值給 $.fn 屬性。而且爲了統一命名空間原則,須要把它做爲 myPlugin 的屬性,如:

$.fn.myPlugin.defaults =  {
    'name': 'zhangsan',
    'age': '20'
};
複製代碼

接着,當使用默認值來合併參數選項時,在項目中只出現一次,即在 init() 方法裏,如:

var methods = {
    init: function(options) {
      // 可自定義擴展項
      options = $.extend(
        true,
        {}, 
        $.fn.myPlugin.defaults,
        options
      );
    }
}
複製代碼

這樣,當咱們在瀏覽器裏直接測試:

// 獲取
$.fn.myPlugin.defaults.name   // zhangsan

// 修改
$.fn.myPlugin.defaults.name = 'wangwu'
// "wangwu"
複製代碼

維護鏈式調用性

使用 return this ,能夠維護鏈式調用性。

Array.prototype.slice.call()

Array.prototype.slice.call(arguments)能將具備length屬性的對象轉成數組 (arguments.toArray().slice()

var a={length:2,0:'first',1:'second'};
Array.prototype.slice.call(a);   //Array [ "first", "second" ]
複製代碼

再舉個栗子

項目中常常使用輪播圖,咱們就在前人的基礎上,模仿一下吧(你就說是抄的不就好了麼):

;
(function ($) {
    function showPhoto(options, index) {
        var $photoElement = $(options.photoElement);
        if (!$photoElement.is(':animated')) {
          $photoElement.animate({
            opacity: 0.5
          }, 0).attr(
            'src',
            options.transformer(options.$thumbnails[index].src)
          ).animate({
            opacity: 1
          }, 800);
          options.current = index;
        }
    }
   var methods = {
      init: function (options) {
         options = $.extend(
            true, {},
            $.fn.slidePhoto.defaults,
            options, {
               current: 0, // 初始值爲0
               $thumbnails: this.filter('img'), //選出全部的圖片
               delay: options.delay >= 1000 ? options.delay : 1000,
            }
         );

         // 點擊圖片,切換對應大圖
         options.$thumbnails.click(function () {
            showPhoto(options, options.$thumbnails.index(this));
         });

         // 顯示下一張
         $(options.nextControl + ', ' + options.photoElement).click(function () {
            var index = (options.current + 1) % options.$thumbnails.length; // 取模

            showPhoto(options, index);
         });

         // 顯示上一張
         $(options.previousControl).click(function () {
            var index = options.current === 0 ? options.$thumbnails.length - 1 : options.current - 1;

            showPhoto(options, index);
         });

         // 顯示第一張
         $(options.firstControl).click(function () {
            showPhoto(options, 0);
         }).triggerHandler('click'); // 主要是初始時觸發,觸發被選元素上指定的事件,返回事件處理函數的返回值

         // 顯示最後一張
         $(options.lastControl).click(function () {
            showPhoto(options, options.$thumbnails.length - 1);
         })

         // 自動播放
         var tick;

         function autoPlay() {
            tick = window.setInterval(
               function () {
                  $(options.nextControl).triggerHandler('click')
               }, options.delay);
         }
         // 鼠標移入移出狀態
         function mouserStatus(obj) {
            $(obj).mouseenter(function () {
               if (tick) {
                  window.clearInterval(tick);
               }
            }).mouseleave(autoPlay);
         }

         if (options.autoPlayControl) {
            autoPlay();
         }

         // 鼠標滑動暫停、播放
         mouserStatus(options.photoElement);
         mouserStatus(options.$thumbnails);

         return this;
      }
   };

   $.fn.slidePhoto = function (method) {
      if (methods[method]) {
         return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
      } else if ($.type(method) === 'object') {
         return methods.init.apply(this, arguments);
      } else {
         $.error('Method ' + method + ' does not exist on jQuery.slidePhoto');
      }
   };

   $.fn.slidePhoto.defaults = {
      photoElement: 'img.photomatic-photo', // 大圖顯示
      transformer: function (name) {
         return name.replace('thumbnail', 'photo'); // 將'thumbnail' 替換爲 'photo',即最終返回大圖的src屬性值
      },
      nextControl: null, // 下一張
      previousControl: null, // 前一張
      firstControl: null, // 第一張
      lastControl: null, // 最後一張
      autoPlayControl: false,
      delay: 3000 // 延時
   };

})(jQuery)

複製代碼

用法:

$('#thumbnails-pane img').slidePhoto({
    photoElement: '#photo-display',
    previousControl: '#previous-button',
    nextControl: '#next-button',
    firstControl: '#first-button',
    lastControl: '#last-button',
    autoPlayControl: true,
    delay: 3000
 });
複製代碼

參考:

  • 《jQuery實戰 第三版》
相關文章
相關標籤/搜索