zoukankan      html  css  js  c++  java
  • 如何写一个jQuery插件

    jQuery 插件开发模式

    jQuery 的插件开发模式主要有三种:

    • 通过$.extend()来扩展jQuery
    • 通过$.fn向jQuery添加新的方法
    • 通过$.widget()应用jQuery UI 的部件工厂方式创建

    这里我们选用第二种:

    $.fn.myplugin = functin() {
    	// plugin code
    }
    

    因为这种方法是加在jQuery对象上,可以在jQuery选择器选择元素后直接调用:

    	$('body').myplugin();
    

    若对其他两种方法有兴趣,请自行查看jQuery 官方文档

    一个非常简单的例子

    改变元素的背景颜色插件:

    $.fn.tinyPlugin = function(){
    	this.css('background-color','#fff'); // 这里的this是jQuery对象,而不是原生的js对象
    }
    

    这样写的话,颜色不能使用时定义,修改一下:

    $.fn.tinyPlugin = function(bg){
    	this.css('background-color',bg);
    }
    

    以上是一个jQuery插件的基本结构。但编写更复杂的jQuery插件,借助面向对象的思想可以使插件具有更好的扩展性、可维护性。

    面向对象开发插件

    大体思路如下:

    1.创建myplugin构造函数

    2.定义myplugin的方法

    3.添加到jQuery对象中

    基本结构

    首先将代码放到一个自执行的匿名函数中,防止全局对象污染:
    根据上面的步骤,基本结构大致如下:

    // 定义构造函数
    function myplugin($element,options){
    	// ...
    }
    
    // 添加方法
    myplugin.prototype = {
    	method1: function(){
    		// ...
    	},
    	method2: function(){
    		// ...
    	}
    };
    
    // 添加到jQuery对象中
    $.fn.myplugin = function(options){
    	new myplugin(this,options);
    }
    

    后面将在这个结构上进行完善:

    放到立即执行的匿名函数内部

    放到匿名函数内部的主要作用是隔离作用域,避免变量污染,而自执行可以返回需要的函数或对象,而不需要每次通过条件判断为处理,只需要在首次加载的时候赋值给某个变量。更详细的信息参见知乎上的 这个问题

    ;(function($){
        // ...
    })(jQuery);
    

    留意到上面,函数前还加了分号,这是由于自执行函数前省略分号的表达式时,某些情况下会报错,可以看 这里

    在匿名函数里面还传入了jQuery对象,这样做的好处是美元符号 $ 在内部是一个私有变量,仅代表jQuery,可以防止和其他使用 $ 的库冲突。

    有的自执行函数还将window对象、undefined对象传入,具体作用可以看 这里

    默认参数

    options是提供给使用者定义的参数。一个好的插件,应该提供必要的参数给使用者,并且提供好默认的参数,因为很多情况下不是每个参数都需要自定义。之前在项目中写了一个加载更多 LoadMore 插件,就以这个插件为例:

    function LoadMore($element,options){
        this.$element = $element;
    
        this._defaults = {
            loadingSelector: ".zc_loading",  //加载中的提示
            overSelector: ".zc_loaded",  // 加载完毕的加载
        }
        this.options = $.extend({},this._defaults,options||{});  // 合并参数
    }
    

    初始化方法

    一般插件都会有一个 init() 方法,调用插件时做一些初始化操作:

    function myplugin($element,options){
        this.init();
    }
    
    // 添加方法
    myplugin.prototype = {
        init: function(){
            // ...
        }
    };
    

    防止多次初始化

    为了防止用户多次在同一个元素上调用插件,有必要加一些已初始化的判断。通过在该元素上用 data() 方法缓存插件的实例对象,每次实例化时判断该缓存对象即可。

    $.fn.myplugin = function(options){
        if (!$.data(this, 'myplugin')) {
            $.data(this, 'myplugin', new myplugin(this, options));
        }
    }
    

    遍历所有元素

    $ 选择器返回的有可能是多个元素,因此需要返回的所有元素添加插件,直接使用jQuery自带的 each() 方法:

    $.fn.myplugin = function(options){
        this.each(function(){
            if (!$.data(this, 'myplugin')) {
                $.data(this, 'myplugin', new myplugin(this, options));
            }
        });
    }
    

    注意这里的this 是jQuery对象,而不是原生JS对象。所以可以直接使用this.each()

    保持链式操作

    由于jQuery有个链式操作的特性,在每个方法调用后都会返回该对象,因此只需要 return 该对象即可保持链式操作:

    $.fn.myplugin = function(options){
        return this.each(function(){
            // ...
        });
    }
    

    给插件添加方法

    插件不仅有可配置的参数,很多时候还需要调用方法。比如说“加载更多”插件,可能需要知道现在加载到第几页,或者是否已经全部加载完毕。此时就需要调用方法来获得结果。

    在前面我们知道是在 prototype 定义方法:

    LoadMore.prototype = {
            init: function(){},
            // 重新加载
            reload: function(){},
            // 开始加载
            startLoad: function(){},
            // 本次加载完成
            loadOver: function(){},
            // 全部加载完毕
            allLoadOver: function(){},
            // 插入内容
            insert: function(content){}
        }
    

    方法名可以通过options参数传入,只需在内部做字符串判断:

    $.fn.LoadMore = function(options,para){
            var instance;
            instance = $.data(this,'LoadMore');
            if(!instance){
                instance = new LoadMore(this,options);
                $.data(this,'LoadMore',instance);
            }
    
            // 如果是字符串则调用方法
            if($.type(options) === 'string') {
                return instance[options](para);
            }
            return this;  // 保持链式
    }
    

    因此我们调用方法可以像下面这样:

    $('#list').LoadMore('startLoad');
    

    但是,当调用的方法需要传参怎么办?很简单,那就再加一个参数 para

    $.fn.LoadMore = function(options,para){
            // ...
            // 如果是字符串则调用方法
            if($.type(options) === 'string') {
                return instance[options](para);
            }
            return this;  // 保持链式
    }
    

    调用带参数的方法:

    $('#list').LoadMore('insert','这是待插入的内容');
    

    这里如果要使用回调函数,和上面也是一样的道理,只需在内部加个函数判断。不详述。若有更多的参数,请使用对象 {}

    配置参数中添加事件

    在写 LoadMore 插件的过程中,还发现需要使用事件,比如说滚动到某个位置时,执行某些操作。也很简单,事件我们可以直接写在配置参数 options 中:

    this._defaults = {
        onScroll: null,  // scroll中
        onScrollBottom: null  // scroll到底部
    }
    

    然后在内部 init() 函数中调用前判断:

    init: function(){
        var that = this,
            $win = $(window),
            $doc = $(document);
        $win.on('scroll',function(){
            (typeof that.options['onScroll'] == 'function') && that.options['onScroll']();
            if($win.scrollTop() + $win.height() >= $doc.height()-10){
                (typeof that.options['onScrollBottom'] == 'function') && that.options['onScrollBottom']();
            }
        });
    }
    

    兼容AMD规范

    现在流行模块化开发,AMD是require.js在推广过程中的规范化产出,AMD说明见 这里
    下面的代码可以使你的插件兼容AMD规范,可以在require.js中直接调用,当然,没有使用require.js直接 <script> 引入也是可以的。

    // amd support
    (function(factory){
        // amd support
        if(typeof define === 'function' && define.amd){
            define(['jquery'],factory);
        }else {
            factory(jQuery);
        }
    }(function($){
        var exports = {};
        // 这里写插件代码
        return exports;
    }));
    

    上面的前一段是判断是否有define函数,有则调用define方法定义一个模块,否则直接执行。后一段的 exports 对象是模块的返回对象,模块对外的接口。关于AMD规范的具体信息,可参考阮一峰的 这篇文章

    结语

    上面所写的就是写一个插件的大致流程,由于能力有限,还有很多要完善的地方。想要了解更多,这里推荐一篇文章 深入理解jQuery插件开发。另外,这里提供一个gitHub上面的某位大神写的插件 SlipHover供参考。

  • 相关阅读:
    Docker界面化管理
    搭建MQTT服务器(Docker版)
    VS Code Markdown文件实时预览
    Nginx直接处理接口请求,返回相应内容(带html标签)
    Docker(九): 安装MySQL主从复制
    feign的一个注解居然隐藏这么多知识!
    使用Magisk指令修改 ro.debuggable(不刷机)
    【钓鱼可用】文件名反转字符串
    android高级UI之贝塞尔曲线<下>--贝塞尔曲线运用:QQ消息气泡
    英文阅读技巧操练---Article 1:The Product-Minded Software Engineer《一》
  • 原文地址:https://www.cnblogs.com/yoomin/p/5391423.html
Copyright © 2011-2022 走看看