zoukankan      html  css  js  c++  java
  • 第四十三课:jQuery插件化

    我们先来看一个最简单的例子:

    (function($){

      $.fn.extend({     //把此插件添加到jQuery的原型上

        pluginName:function(){   //插件的名字

          return this.each(function(){     //遍历匹配元素的集合

            //插件要实现的功能

          });

        }

      });

    })(jQuery);   //传入jQuery对象

    由于jQuery是集化操作($("div")会选择多个div元素进行操作),而我们的插件编写应该一个元素对应一个配置对象,我们可以使用$.extend({},defaults,options)来为每个元素分配独立的配置对象。其中,defaults为默认配置对象,以防我们什么都没传时,插件也能正常运作。如果传入的配置对象options比较复杂,也就是说options的属性也是一个对象,那么我们可以使用深拷贝,$.extend(true,{},defaults,options)。

    当然,你可以在上面例子中的each中做一个元素对应一个配置对象的操作,但是如果操作很多,那么在each中就会有很多代码,维护不方便。

    因此,我们需要使用面向对象的写法。请看例子:

    (function($){

      var Plugin = function(element, options){

      };

      Plugin.defaults = {    //默认配置

      };

      Plugin.prototype = {};

      $.fn.extend({     //把此插件添加到jQuery的原型上

        pluginName:function(options){   //插件的名字

          return this.each(function(){     //遍历匹配元素的集合

            var ui = $._data(this, "pluginname");    //看此元素在jQuey缓存系统中是否存有pluginname属性,它的值是一个Plugin实例对象

            if(!ui){

              var opts = $.extend(true,{}, Plugin.defaults , options);    //这里的默认配置对象一般写在Plugin实例构造中使用

              ui = new Plugin(this,opts);

              $._data(this,"pluginname", ui);    //一个元素对应一个Plugin实例对象,插件的功能,全部在Plugin对象中,因此,我们只需要改写Plugin构造函数以及它的原型,就能实现此插件的功能。

            }       

          });

        }

      });

    })(jQuery);   //传入jQuery对象

    Bootstrap在上面的基础上,进行了三大改造,第一:插件的无冲突处理。第二:将内部的对象构造器(类)放到了$.fn.pluginName.Constructor上,方便我们来扩展这个内部类。第三:利用事件代理自动初始化实例,目的是让用户只需要引入此插件,并按照规定写HTML,就能让此HTML实现插件的功能。举个例子:

    (function($){

    //------------------------------------------------------------------------内部的对象构造器(内部类)

      var Dropdown= function(element, options){

        $(element).on("click",this.toggle);    //当$("div").dropdowm({....})时,就会给div绑定一个click事件,如果点击了div,就会触发toggle方法。

      };

      Dropdown.defaults = {    //默认配置

      };

      Dropdown.prototype = {

        constructor:Dropdown,

        toggle:function(){

          ......

        }

      };

    //--------------------------------------------------------------

      var old = $.fn.dropdown;    //因为需要重写此方法名,因此先把原始的保存在old变量中,当调用$.fn.dropdown.noConflict(),就会把它还原。

      $.fn.extend({     //把此插件添加到jQuery的原型上

        dropdown :function(options){   //插件的名字

          var args = [].slice.call(arguments,1);

          return this.each(function(){     //遍历匹配元素的集合

            var ui = $._data(this, "dropdown");    //看此元素在jQuey缓存系统中是否存有dropdown属性,它的值是一个Dropdown实例对象

            if(!ui){

              var opts = $.extend(true,{}, Dropdown.defaults , options);   //这里的默认配置对象,一般在Dropdown实例对象构造中使用。

              ui = new Dropdown(this,opts);

              $._data(this,"dropdown", ui);    //一个元素对应一个Dropdown实例对象,插件的功能,全部在Dropdown对象中,因此,我们只需要改写Dropdown构造函数以及它的原型,就能实现此插件的功能。

            }    

            if (typeof options == 'string' && typeof ui[options] == 'function') {  //这里添加的这段代码,是针对jQuery插件的,当我们实例化此插件后,比如:$("div").dropdown({....})后,如果想调用此插件的方法,那么,可以用$("div").dropdown(方法名, arg1,arg2....)
              ui[options].apply(ui, args);
            }    

          });

        }

      });

      $.fn.dropdown.Constructor = Dropdown;   //把内部类暴露出来,我们可以通过$.fn.dropdown.Constructor来访问,并且扩展它

      $.fn.dropdown.noConflict = function(){

        $.fn.dropdown = old;

        return this;

      }

      $(document).on("click", ".dropdown",Dropdown.prototype.toggle);    //加载完此插件后,在HTML的元素中只要有class = dropdowm,那么点击此元素,就会执行toggle方法。 

    })(jQuery);   //传入jQuery对象

     如果想做jQuery插件,此思想一定要掌握,面试会问,一次看不懂,多看几次就懂了,或者去看下公司里面其他人写的插件,就很容易懂了。如果大家没有很好的例子,那可以看一下我写的那个日历插件:http://www.cnblogs.com/chaojidan/p/4140725.html。在这个插件中,我是直接使用了全局变量来定义了CCalendar,这样会污染我们的全局环境,因此,我们只需要在整个代码的外面,添加一个立即执行的匿名函数,同时包装到jQuery中就行了。

    (function($){    

    //------------------------------------------------------------------------内部的对象构造器(内部类)

      // 日历插件代码  

    //-------------------------------------------------------------- 

      $.fn.ccalendar = function (options) {
        return this.each(function () {
          var $this = $(this),
          data = $this.data('CCalendar'),      //这个就相当于$._data(this, "CCalendar")
          if (!data) {

            data = new CCalendar(this, options);
            $this.data('CCalendar', data );  //这个就相当于$._data(this,"CCalendar“, data);
          }
        });
      };
      $.fn.ccalendar.Constructor = CCalendar;

     })(jQuery)

    这样一包装之后,插件代码中的方法和变量,都变成局部的了,就不会污染全局环境了,但是在使用这个日历插件时,你就需要这样调用了:

    $("input").ccalendar({   .....   });

    如果大家使用的是sea.js这种模块化开发的模式:

    那么只需要:

    define(function(require, exports, module){

      var $ = require("./jQuery.js");

      //然后再把上面的立即执行函数中的代码放到这里。

      module.exports=CCalendar;

    })

    这时,你既可以用jQuery的调用方式:$("input").ccalendar({   .....   });

    也可以使用sea.js的调用方式:var callendar = require("./ccalendar.js");   var date = new callendar(element, { ..... }) 

    加油!

  • 相关阅读:
    LeetCode_167. Two Sum II
    LeetCode_160. Intersection of Two Linked Lists
    LeetCode_155. Min Stack
    LeetCode_141. Linked List Cycle
    LeetCode_136. Single Number
    LeetCode_125. Valid Palindrome
    HTML解析类 ,让你不使用正则也能轻松获取HTML相关元素 -C# .NET
    .net 根据匿名类生成实体类,根据datatable生成实体类,根据sql生成实体类
    将form表单元素转为实体对象 或集合 -ASP.NET C#
    ASP.NET 图片上传工具类 upload image简单好用功能齐全
  • 原文地址:https://www.cnblogs.com/chaojidan/p/4213942.html
Copyright © 2011-2022 走看看