2012年10月4日 星期四

Note:寫自己的jQuery plugin

重複的功能一直重複寫也不是辦法。jQuery的外掛功能提供你將自己的程式碼打包起來,成為jquery的外掛,降低程式碼的重複性。
對了,下面說明文字:plugin =插件 = 外掛=jquery的外掛程式。

擴展jQuery的plugin跟method是非常強大的,可以減省很多開發時間。
一個網站如果小小的可能沒差,但是管理大站的jQuery可以好好考慮往plugin的方向學習。我看了官方的文件寫了下面的筆記,可以說是翻譯過來,建議可以看官方文件就看官方文件,網址: http://docs.jquery.com/Plugins/Authoring
說實在的可能要真的用到才會懂吧><,而且要寫的機率很低...,所以想說寫之前,先看看別人怎麼寫。
在尋找jquery的範例時就馬上吃了閉門羹,http://plugins.jquery.com/ ,這個網頁還在開發中,好吧,沒關係,像fancybox就是一種jquery的外掛。

外掛程式的命名

(這段可以參考:jQuery網頁設計範例教學/德瑞工作室 松崗出版),因為官方網站沒看到這段,但書裡有介紹到,如果想多了解就看書。

有用過jquery的外掛應該可以想像下載下來就是一個壓縮檔之類的,然後打開之後有css,有js,有html檔,其js除了有jquery的檔案之外,還有外掛程式的.js檔。有用過fancybox嗎?
它的外掛檔如圖:

通常寫plugin會將plugin額外取出另存成一個.js檔,再將js引入到頁面中。
外掛程式的命名如下 :
1) 使用"jquery"作為前置詞,後面接一個"."`,再接你的外掛名稱,在接".",然後加上附檔名,
     如 jquery.你的外掛名稱.js  (ex: jquery.winwingo.js)
2) 附檔名會是js
3) 可以選擇要不要加入版本名稱。如 : jquery.winwingo-1.0.js


開始寫一個jQuery的plugin

jQuery的plugin會先接著一個新的function,另外你也要先想好你的plugin的名稱,範例如下:
jQuery.fn.myPlugin = function(){
        //Do your awesome stuff here 
}:

myPlugin是你的plugin命名,隨意取名(恩…也不是很隨意,就是也要符合命名的規則啦),像是:photoHover,showBackground..等等
//Do your awesome stuff here ,簡單來說這個fn要做的事情都寫在這裡面。
像這樣:
jQuery.fn.sayhello = function(){
        //Do your awesome stuff here
 };


但是,還記得jQuery可以用$替換嗎?
所以剛剛的範例可以改成這樣 :

jQuery.fn.myPlugin = function(){ 
$.fn.myPlugin = function(){
         //Do your awesome stuff here
};


為了確保你的plugin 不會與其他library有碰撞的情況(函數衝突),建議你把你的plugin打包起來。(簡單來說就是把你的程式碼包起來,以防與其他code有相衝或汙染的情況=>官方比較建議您使用這種做法)
因此,我們可以這樣寫:

(function($){ $.fn.myPlugin = function(){
           //Do your awesome stuff here };
})(jQuery);


寫在Plugin的this跟你想得不一樣…. 

前面講得是,怎麼產出一個plugin的方法,但裡面要做些什麼呢?.....官方文件先從包在plugin裡面的this講起….
我第一次看官方文件的時候,實在搞不懂這邊再講什麼,先看一下官方網站所列出來的例子:
這個範例是建立一個myPlugin的plugin,這個plugin會指向一個function(),會使該物件執行fadeIn的事件,這個範例還不夠具體,但只是要表達在$.fn.plugin的function()內的this已經是DOM了。
在這個myPlugin裡面呢,jQuery會接收一個callback(回傳),而這個callback本身就指到DOM,所以直接使用this等於$(this)。

(function( $ ){
$.fn.myPlugin = function() {
           //在這裡,不需要再用$(this),因為”this”已經是jQuery的物件了
           // there's no need to do $(this) because
           // "this" is already a jquery object
           // $(this) would be the same as $($('#element'));
              this.fadeIn('normal', function(){
             //這裡的this是一個HTML元素
               });
};
})( jQuery );

而使用這個myPlugin時這樣寫:
$('#emelent').myPlugin();

比方說我選取一個div,執行myPlugin的plugin,可以這樣寫:
$(‘div’).myplugin();


讓我們寫一個plugin來真正做些事情!

這是ㄧ個簡單的plugin,利用.height() 回傳頁面中最高的div的高度值。
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>The Basic</title>
<style type="text/css">
div{border:1px solid #CCC}
</style>
</head>
<body>
<div style="height:100px">1</div>
<div style="height:50px">2</div>
<div style="height:80px">3</div>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script type="text/javascript">
(function($){
    $.fn.maxHeight = function(){
      var max = 0;
      this.each(function(){
      //這裡不用$(this) 因為這裡的this已經是$('this')
      //利用each跑遍要被執行的元素
        max = Math.max(max,$(this).height());
      });
      return max;
      console.log(max);
    };
  })(jQuery);

  var tallest = $('div').maxHeight();
  //變數tallest 的值為$(‘div’).maxHeight
  //maxHeight是我們自己寫出來的Plugin
  console.log(tallest);
  //log出頁面最高的div高度
  //如果不會用console.log可以改用 alert (把註解拿掉)
  //alert(tallest);
</script>
</body>



Maintaining Chainability
(這大標我不知道怎麼用中文講)
在前面的例子,我們回傳了一個整數的值,該值是頁面中最高的div的高度值,但某些時候,一個plugin以某種方式簡單的修改該集合的元素,和傳遞鏈(chain)給下一個method,這就是jQuery的設計之美,也是jQuery受歡迎的原因之一。
因此要保持一個plugin的鏈(chain),你必須return this。


參數的傳遞,Default預設值跟option可選值

對於更複雜以及提供很多選項的plugin來說,使用$.extend來延伸一些默認的參數是很好用的。
利用$.extend()將許多物件合併成一個物件。

<script type="text/javascript">
  (function($){
  $.fn.tooltip = function(options){
  //建立一些預設值
  var settings = $.extend({
    'location'        : 'top',
    'background-color': 'blue',
  },options);
  return this.each(function(){
     //Tooltop plugin code here
        });
  }
  })(jQuery);
 
  $('div').tooltip({'location':'left'});

</script>

在上面的範例中,當我們呼叫tooltip時附帶著我們自選的選項(‘location’:’left’),則預設的location將會被覆蓋為left,然而背景色(background-color)因為沒有特別的指定,因此維持預設值(default)一樣是藍色,所以這個物件最後的設定會長這樣:
{
‘location’  :’left’,
        ‘background’ : ‘blue’,
}
這是ㄧ個可任意配置選項的plugin,不需要開發人員自己去定義所有的選項。


Namespcing 命名空間

正確的使用命名空間是開發plugin很重要的一部分,正確的命名,可以降低你的plugin在同一個頁面中被其他plugin或是程式碼覆蓋。
This is a discouraged because it clutters up the $.fn namespace. To remedy this, you should collect all of your plugin's methods in an object literal and call them by passing the string name of the method to the plugin. (-難翻..)

這裡有一個範例:
(function( $ ){

  $.fn.tooltip = function( options ) {
    // THIS
  };
  $.fn.tooltipShow = function( ) {
    // IS
  };
  $.fn.tooltipHide = function( ) {
    // BAD
  };
  $.fn.tooltipUpdate = function( content ) {
    // !!! 
  };

})( jQuery );

以上的範例是比較洩氣的方式,(我的解讀是…)因為以上的程式碼是將所有的明明是很類似的功能都個別分出一個Plugin。為了糾正這個寫法,你可以看看糾正後的樣子:


(function( $ ){

  var methods = {
    init : function( options ) {
      // THIS
    },
    show : function( ) {
      // IS
    },
    hide : function( ) {
      // GOOD
    },
    update : function( content ) {
      // !!!
    }
  };

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

})( jQuery );

// calls the init method
$('div').tooltip();

// calls the init method
$('div').tooltip({
  foo : 'bar'
});


這種封裝方法跟結構在jquery的plugin中是很標準的寫法,適用於無數的Plugin,包含jQueryUI也是。


Continue…………….

沒有留言:

張貼留言

若你看的文章,時間太久遠的問題就別問了,因為我應該也忘了... XD

Vue multiselect set autofocus and tinymce set autofocus

要在畫面一進來 focus multiselect 的方式: 參考: https://jsfiddle.net/shentao/mnphdt2g/ 主要就是在 multiselect 的 tag 加上 ref (例如: my_multiselect), 另外在 mounted...