`

jQuery插件开发的模式和结构

 
阅读更多

jQuery插件开发的模式和结构

 

jQuery插件开发

一般来说,jQuery插件的开发分为两种:一种是挂在jQuery命名空间下的全局函数,也可称为静态方法;另一种是jQuery对象级别的方法,即挂在jQuery原型下的方法,这样通过选择器获取的jQuery对象实例也能共享该方法。

一、在讲解jQuery插件基本结构和模式前,先介绍下两个重要的方法,还有不知啥原因,代码无法折叠,导致整体篇幅稍微有点长,阅读时请加点耐心:

1、$.extend(target, [object1], [objectN])

该方法主要用于合并两个或更多对象的内容(属性)到第一个对象,并返回合并后的第一对象。如果该方法只有一个参数target,则该参数将扩展jQuery的命名空间,即作为静态方法挂在jQuery全局对象下,如jQuery里的$.ajax、$.getJSON全局函数等:

// 将hello方法挂在jquery全局对象下,作为静态方法
$.extend({ 
    hello: function() {alert("hello");} 
});

又如,在jQuery全局对象中扩展一个hcy命名空间:

$.extend({ hcy: { } });

并将hello方法扩展到之前扩展的JQuery的hcy命名空间中去:

$.extend($.hcy, {
    hello: function() {alert("hello");}
});

在开发插件时,也可以将方法扩展到jQuery的原型中去,如:

$.extend($.fn, {
    hello: function() {alert("hello");}
});

值得注意的是:多个对象参数合并时,会破坏第一个对象的结构,所以可传递一个空对象作为第一个参数,如:$.extend({}, object1, object2);

另外,对于深度拷贝,即如果对象中也嵌套子对象,则会拷贝并覆盖子对象(如果有同名属性)全部的属性,需要设置第一个参数deep为true值,如:$.extend(true, target, object1, [objectN])。

2、$.fn.extend(target)

在jQuery中,$.fn本质上是等于jQuery的原型,即$.fn = $.prototype, 所以该方法实际上是为jQuery原型添加方法,即把target对象的方法添加到jQuery原型中去,这样jQuery对象实例就可以访问添加的方法了,这也是jQuery插件开发常用的方法,特别是添加多个接口时。如:

// 将hello、hello2方法添加到jquery原型中
$.fn.extend({ 
    hello: function() {alert("hello!");},
    hello2: function() {alert("hello again!);}
});

如果添加单个方法到jQuery原型中,可使用$.fn.pluginName方法添加,如:

// 将hello方法添加到jquery原型中
$.fn.hello = function() {
    // ...            
};

 

 

二、在开发过一些 jQuery 插件后,慢慢的探索出了一套开发jQuery插件的基本结构和模式。这样在面对复杂多变的需要方案时,只要专注最主要的逻辑代码就行了。另外,使用相同的设计模式和架构也让修复bug或者二次开发更容易。

在这里分享一些平时遇到和总结的经验:

1、把全部代码放在闭包(一个即时执行函数)里

此时闭包相当于一个私有作用域,外部无法访问到内部的信息,并且不会存在全局变量的污染情况。官方创建开发规范的解释是:a) 避免全局依赖;b) 避免第三方破坏;c) 兼容jQuery操作符'$'和'jQuery '。如下所示:

(function($) {
    // 局部作用域中使用$来引用jQuery
    // ...
})(jQuery);

这段代码在被解析时可理解成以下代码:

var jQ = function($) {
  // code goes here
}; 
jQ(jQuery);

2、提供插件的默认参数选项

一个扩展性良好的插件应该是可以让使用者根据需求自定义参数选项,并控制插件的行为,所以提供恢复默认选项是很有必要的。你可以通过jQuery的extend方法来设置这些选项:

复制代码
var defaults = {    
    name: "hcy",    
    age: 22,
    job: "student",
    walk: function() {
        // ...
    }     
};
复制代码

$.extend({}, defaults, options || {});

注:参数选项设置时也可以使用如下模式,即把参数对象挂在插件命名空间下:

 

复制代码
$.fn.pluginName.defaults = {    
    name: "hcy",    
    age: 22,
    job: "student",
    walk: function() {
        // ...
    }     
};
复制代码

 

3、遍历多个元素并返回

jQuery使用Sizzle选择器引擎Sizzle可以为你的函数提供多元素操作(例如对所有类名相同的元素)。这是jQuery几个优秀的特性之一,在开发插件过程中即使你不准备为你的插件提供多元素支持,但为这做准备仍然是一个很好的实践。另外,jQuery有一个很好的特点就是可以进行方法级联,也可称为链式调用,所以我们不应该破坏这个特性,始终在方法中返回一个元素。如:

复制代码
function($) {
    // 参数选项设置...
    // 向jQuery原型中添加你的插件代码,用“pluginName”作为插件的函数名称。
    $.fn.pluginName = function(options) {
        // 遍历匹配的元素||元素集合,并返回this,以便进行链式调用。
        return this.each(function() {
            // 此处可通过this来获得每个单独的元素(jQuery对象)
            var $this = $(this);
 
        });
    };
})(jQuery);
复制代码

4. 一次性代码放在主循环以外

这一条很重要,但是常常被忽略。简单的讲,如果你有一段代码是一堆默认值,只需要被实例化一次,而不是每次调用你插件功能的时候都需要实例化,你应该把这段代码放在插件方法的外面。这样可以让你的插件运行的更高效,节省内存。如:

复制代码
function($) {
    // 参数选项设置
    var defaults = {    
        name: "hcy",    
        age: 22,
        job: "student",
        walk: function() {
            // ...
        }     
    };
    // 向jQuery原型中添加你的插件代码,用“pluginName”作为插件的函数名称。
    $.fn.pluginName = function(options) {
        var opts = $.extend({}, defaults, options || {});
    
        // 遍历匹配的元素||元素集合,并返回this,以便进行链式调用。
        return this.each(function() {
            // 此处可通过this来获得每个单独的元素(jQuery对象)
            var $this = $(this);
           // ...
        });
    };
})(jQuery);
复制代码

5、定义公有方法和私有方法

一般情况下,对于一个jQuery插件,一个基本的函数就可以很好地工作,但是对于复杂一点的插件就需要提供各种各样的方法和私有函数。你可能会使用不同的命名空间去为你的插件提供各种方法,但是添加过多的命名空间反而会使代码变得混乱,健壮性下降。所以最好的解决办法是适当地定义私有函数和方法。例子如下所示:

复制代码
(function($) {
    // 在我们插件容器内,定义一个私有方法
    var privateFunction = function() {
        // code here
    };
 
    // 通过字面量创造一个对象,存储我们需要的共有方法
    var methods = {
        // 在字面量对象中定义每个单独的方法
        init: function() {
            // 为了更好的灵活性,对来自主函数,并进入每个方法中的选择器其中的每个单独的元素都执行代码
            return this.each(function() {
                // 为每个独立的元素创建一个jQuery对象
                var $this = $(this);
                // 执行代码 例如:privateFunction()
            });
        },
        destroy: function() {
            // 对选择器每个元素都执行方法
            return this.each(function() {
                // 执行代码
            });
        }
    };
 
    $.fn.pluginName = function() {
        // 获取我们的方法,遗憾的是,如果我们用function(method){}来实现,这样会毁掉一切的
        var method = arguments[0];
 
        // 检验方法是否存在
        if(methods[method]) {
            // 如果方法存在,存储起来以便使用
            // 注意:我这样做是为了等下更方便地使用each()
            method = methods[method];
 
        // 如果方法不存在,检验对象是否为一个对象(JSON对象)或者method方法没有被传入
        } else if (typeof method === "object" || !method ) {
            // 如果我们传入的是一个对象参数,或者根本没有参数,init方法会被调用
            method = methods.init;
}
else { // 如果方法不存在或者参数没传入,则报出错误。需要调用的方法没有被正确调用 $.error("Method" + method + "does not exist on jQuery.pluginName"); return this; } // 调用我们选中的方法 // 再一次注意我们是如何将each()从这里转移到每个单独的方法上的 return method.call(this); }; })(jQuery);
复制代码

注意我把 privateFunction 当做了一个函数内部的全局变量。考虑到所有的代码的运行都是在插件容器内进行的,所以这种做法是可以被接受的,因为它只在插件的作用域中可用。在插件中的主函数(pluginName)中,我检验了传入参数所指向的方法是否存在。如果方法不存在或者传入的是参数为对象, init 方法会被运行。最后,如果传入的参数不是一个对象而是一个不存在的方法,我们会报出一个错误信息。

下面是一些用法的例子

复制代码
// 为每个类名为 ".className" 的元素执行init方法
$(".className").pluginName();
$(".className").pluginName("init");
$(".className").pluginName("init", {}); // 向init方法传入“{}”对象作为函数参数
$(".className").pluginName({}); // 向init方法传入“{}”对象作为函数参数
 
// 为每个类名为 “.className” 的元素执行destroy方法
$(".className").pluginName("destroy");
$(".className").pluginName("destroy", {}); // 向destroy方法传入“{}”对象作为函数参数
 
// 所有代码都可以正常运行
$(".className").pluginName("init", "argument1", "argument2"); // 把 "argument1" 和 "argument2" 传入 "init"
 
// 不正确的使用
$(".className").pluginName("nonexistantMethod");
$(".className").pluginName("nonexistantMethod", {});
$(".className").pluginName("argument1"); // 会尝试调用 "argument1" 方法
$(".className").pluginName("argument1", "argument2"); // 会尝试调用 "argument1" ,“argument2”方法
$(".className").pluginName("privateFunction"); // "privateFunction" 不是一个方法
复制代码

注明:该例子代码参考伯乐在线的一篇文章。

 6、添加持久性数据

在插件开发过程中,有时需要在插件中保存设置和信息,这时jQuery中的$.data函数就可以派上用场了。使用时,它会尝试获取和元素相关的数据,如果数据不存在,它就会创造相应的数据并添加到元素上。一旦你使用了$.data来为元素添加信息,请确认你已经记住remember,当不再需要数据的时候,用$.removeData函数来删除相应的数据。下面的例子也同样摘自伯乐在线一篇文章(深入理解jQuery插件开发)里的一小段:

复制代码
(function($) {
    var privateFunction = function() {
        // 执行代码
    }
 
    var methods = {
        init: function(options) {
 
            // 在每个元素上执行方法
            return this.each(function() {
                var $this = $(this);
 
                // 尝试去获取settings,如果不存在,则返回“undefined”
                var settings = $this.data("pluginName");
 
                // 如果获取settings失败,则根据options和default创建它
                if (typeof settings === "undefined") {
 
                    var defaults = {
                        propertyName: "value",
                        onSomeEvent: function() {}
                    };
 
                    settings = $.extend({}, defaults, options);
 
                    // 保存我们新创建的settings
                    $this.data("pluginName", settings);
                } else {
                    / 如果我们获取了settings,则将它和options进行合并(这不是必须的,你可以选择不这样做)
                    settings = $.extend({}, settings, options);
 
                    // 如果你想每次都保存options,可以添加下面代码:
                    // $this.data("pluginName", settings);
                }
 
                // 执行代码
 
            });
        },
        destroy: function(options) {
            // 在每个元素中执行代码
            return $(this).each(function() {
                var $this = $(this);
 
                // 执行代码
 
                // 删除元素对应的数据
                $this.removeData("pluginName");
            });
        },
        val: function(options) {
            // 这里的代码通过.eq(0)来获取选择器中的第一个元素的,我们或获取它的HTML内容作为我们的返回值
            var someValue = this.eq(0).html();
 
            // 返回值
            return someValue;
        }
    };
 
    $.fn.pluginName = function() {
        var method = arguments[0];
 
        if (methods[method]) {
            method = methods[method];
            arguments = Array.prototype.slice.call(arguments, 1);
        } else if (typeof method === "object" || !method ) {
            method = methods.init;
        } else {
            $.error("Method" + method + "does not exist on jQuery.pluginName");
            return this;
        }
 
        return method.apply(this, arguments);
 
    }
 
})(jQuery);
复制代码

在上面的代码中,首先检验元素的数据是否存在。如果数据不存在,“options”和“default”会被合并,构建成一个新的settings,然后用$.data()保存在元素中。

 

结语:终于要到结语了╮(╯▽╰)╭,整体介绍下来,部分参考别人的例子,加入自己的理解和思考,在方便了自己的同时希望对阅读的童鞋有所帮助。在jQuery插件开发的道路上任重道远( ⊙ o ⊙ )啊!加油↖(^ω^)↗

 

因为分享,所以简单;因为分享,所以快乐。
分享到:
评论

相关推荐

    jquery 插件开发 pdf

    jQuery插件开发是扩展这个库功能的一种常见方式,使得开发者能够根据项目需求创建自定义功能。以下是对jQuery插件开发的详细讲解: 1. **插件基础** - jQuery插件通常是通过扩展jQuery对象的原型链来实现的,这...

    jQuery插件开发详解

    《jQuery插件开发详解》 ...总之,jQuery插件开发是一个结合了JavaScript基础、jQuery库特性和设计模式的综合实践过程。通过理解并掌握这些知识,开发者能够更高效地构建功能丰富的交互式网页应用。

    JQuery插件开发 + 插件

    这篇博文“JQuery插件开发 + 插件”可能涉及到如何创建自定义的jQuery插件以及如何利用这些插件来增强网页功能。下面我们将深入探讨jQuery插件开发的相关知识点。 一、jQuery插件基础 1. 插件定义:jQuery插件是...

    老司机带你解读jQuery插件开发流程

    ### jQuery插件开发模式 jQuery插件开发主要有三种模式,分别是通过`$.extend()`扩展jQuery,通过`$.fn`向jQuery添加新方法,以及使用`$.widget()`方法结合jQuery UI创建。通常情况下,开发者更常使用的是通过`$.fn...

    jQuery插件开发教程

    ### jQuery插件开发详解 #### 类级别的插件开发 类级别的插件开发,是指在jQuery的全局作用域中增加新的函数或属性,这种方式相当于给jQuery类本身添加了静态方法。这种开发模式允许开发者向jQuery的核心功能集合...

    Jquery插件开发

    ### Jquery插件开发全解析 ...综上所述,Jquery插件开发提供了灵活多样的方法来扩展框架的功能,无论是通过类级别的全局函数还是对象级别的插件方法,都能有效地满足不同场景的需求,从而增强Web应用的交互性和功能性。

    jQuery插件开发精品教程(让你的jQuery更上一个台阶)

    学习jQuery插件开发对于任何希望提升自身前端开发能力的开发者而言,是一项非常重要的技能。 在插件开发中,首先需要了解的是插件开发的基本模式。根据《jQuery高级编程》所述,jQuery插件开发主要有以下几种方式:...

    jQuery切换缩略图模式和列表模式插件

    这个jQuery插件通过提供便捷的API和预设的动画效果,极大地简化了缩略图与列表模式切换功能的实现。它不仅增强了用户体验,也为开发者节省了大量编写和调试代码的时间。在实际开发中,我们可以根据项目需求对其进行...

    jquery插件库-jquery仿京东商品详情页图片放大效果.zip

    开发一个jQuery插件通常包括定义一个新的函数,该函数接受参数并利用jQuery对象进行操作。这种设计模式使得开发者能够轻松地将插件整合到自己的项目中。 京东商品详情页的图片放大效果,通常涉及到图片预览、缩放和...

    jquery插件集合,采用mvc模式开发了很多插件

    本资源包“jquery插件集合”正是基于jQuery,采用MVC(Model-View-Controller)模式开发的一系列实用插件,旨在提升前端用户体验和开发效率。 首先,让我们关注其中的一个关键组件——“多图上传”插件。在网页中...

    jquery-patterns, 用于启动插件开发的各种jQuery插件模式.zip

    jquery-patterns, 用于启动插件开发的各种jQuery插件模式 插件插件插件模式 因此,你已经尝试了模板,或者编写了一些你自己的插件。 他们工作的程度和可以读性,但是你对学习的感兴趣,如果有更好的方式可以以结构。...

    一个JQuery插件 - Javascript可拖动的模式窗口

    这个jQuery插件为网页开发提供了一个易于使用的、可拖动的模式窗口解决方案,通过简单的API就能实现丰富的交互功能。结合HTML、CSS和JavaScript,开发者可以轻松地将这个插件集成到自己的项目中,提升网站的用户体验...

    jquery插件开发

    本篇将详细介绍jQuery插件开发的基本步骤、设计模式以及一些实用技巧。 1. **创建基础结构** 开发一个jQuery插件首先需要定义一个函数,并通过$.fn(即jQuery.prototype)来扩展jQuery对象。基础结构如下: ```...

    27款jQuery Tree 树形结构插件

    在网页开发中,jQuery Tree 插件是一种常用的工具,用于展示数据的树形结构,通常用于文件系统、组织结构或层级关系的展现。这里我们列举了12款不同的jQuery Tree插件,它们各自具有独特的特性和优势。 1. **jQuery...

    教你如何做一个自己的jQuery插件,jQuery扩展笔记

    为了增强jQuery的功能,我们可以创建自定义的jQuery插件。这篇文章将指导你如何构建一个自己的jQuery插件,理解jQuery扩展的核心原理。 首先,我们要明白jQuery插件的本质是一个包装在jQuery对象上的函数。在jQuery...

    jQuery插件开发

    ### jQuery插件开发详解 #### 一、引言 随着前端技术的发展,jQuery因其轻量级、易用性以及强大的功能,在很长一段时间内成为前端开发的首选库之一。jQuery插件开发则是基于jQuery核心库的功能扩展,使得开发者...

    jquery 插件jquery 插件jquery 插件jquery 插件

    通过理解其工作原理和开发模式,开发者可以构建出符合项目需求的个性化功能,同时利用社区的丰富资源,快速解决常见的前端问题。无论是创建自己的插件还是利用现有的插件,jQuery都能让JavaScript编程变得更加灵活和...

    原创日历Jquery插件

    总之,这个【原创日历Jquery插件】是学习和实践前端开发,特别是Jquery插件开发的好材料,它涵盖了从基础的DOM操作到高级的用户体验设计等多个方面,对于提升开发者技能非常有帮助。同时,它也体现了开源和共享的...

    jQuery 树形结构插件 zTree

    **jQuery zTree 插件...总结来说,zTree 是一个强大的jQuery树形插件,它的特性、灵活性和易用性使其在Web开发中占据一席之地。通过学习和掌握zTree的使用,开发者可以轻松构建出各种复杂的树形结构,提升用户体验。

    jQuery文件树形结构菜单插件.zip

    5. **插件实现**:jQuery插件的开发通常遵循一定的模式,包括初始化函数、公共方法和私有方法。在这个插件中,可能有一个主函数负责接受数组参数,解析数据并构建DOM结构,其他辅助函数则处理如展开、收起节点等操作...

Global site tag (gtag.js) - Google Analytics