美文网首页
jQuery插件 / 进阶

jQuery插件 / 进阶

作者: _chuuuing_ | 来源:发表于2017-12-15 18:37 被阅读0次
    Provide Public Access to Default Plugin Settings

    为了使用插件的程序员能更加直观的看到插件的参数(settings),我们常常会把这些数据暴露(expose)出来,比如下面例子中的$.fn.hilight.defaults
    ==> 将setting从插件中抽离出来

    /* plugin definition */
    $.fn.hiLight = function( options ) {
        var opts = $.extend({}, $.fn.hiLight.defaults, options);
    };
    
    
    /* plugin default - added as properties into the empty {} */
    $.fn.hiLight.defaults = {
        foreground: "red",
        background: "yellow"
    }
    ____________________________________________________________________________________
    
    /* 一个叫Jim的程序员使用了该插件,并对它的设置进行了修改 */
    /* This needs only be called once and does not hace to be called from within a "ready-block" */
    $.fn.hiLight.defaults.foreground = "blue";
    
    
    /* 按照自己的意愿修改完setting之后,Jim开始使用该插件了 */
    $("#myDiv").hiLight();
    

    => And now we can call the plugin method like this and it will use a blue foreground color
    Jim 也可以这样简化上面两句代码:

    $("#myDiv").hiLight({
        foreground: "blue",
    });
    

    关于extend()函数:

    $.extend( target [, object1 ] [, objectN ] )
    
    - target:   Object类型 目标对象,其他对象的成员属性将被附加到该对象上。
    - object1:  可选, Object类型 第一个被合并的对象。
    - object2:  可选, Object类型 第N个被合并的对象。
    
    Provide Public Access to Secondary Functions as Applicable

    To let others extend your custom plugin.
    => To expose the format function so that it can be redefined. In other words, you can say, we now are capable to write plugins for a plugin.
    ==> 将function从插件中抽离出来

    // Plugin definition.
    $.fn.hilight = function( options ) {
        // Iterate and reformat each matched element.
        return this.each(function() {
            var elem = $( this );
            // ...
            var markup = elem.html();       // html(): set content
            // Call our format function.
            markup = $.fn.hilight.format( markup );
            elem.html( markup );            // html(): return content
        });
    };
     
    // Define our format function.
    $.fn.hilight.format = function( txt ) {
        return "<strong>" + txt + "</strong>";
    };
    

    关于html()函数:

    $(selector).html()
    
    The html() method sets or returns the content (innerHTML) of the selected elements.
    - To return content, it returns the content of the FIRST matched element.
    - To set content, it overwrites the content of ALL matched elements.
    
    Keep Private Functions Private

    虽然以上两种expose提高了plugin的可重写和灵活性。我们插件的大多数函数仍然需要是private的,举例:

    (function($) {      // closure
        $.fn.hilight = function( options ) {
            debug(this);
        };
    
        function debug(obj) {
            if (window.console && window.console.log) {
                window.console.log("hilight selection count: " + obj.length);
            }
        }
    })(jQuery);
    
    Bob and Sue

    先来看Bob小朋友写的插件:

    jQuery.fn.superGallery = function( options ) {
        // Bob's default settings:
        var defaults = {
            textColor: "#000",
            backgroundColor: "#fff",
            fontSize: "1em",
            delay: "quite long",        // 控制动画延迟的参数
            getTextFromTitle: true,
            getTextFromRel: false,
            getTextFromAlt: false,
            animateWidth: true,
            animateOpacity: true,
            animateHeight: true,
            animationDuration: 500,
            clickImgToGoToNext: true,
            clickImgToGoToLast: false,
            nextButtonText: "next",
            previousButtonText: "previous",
            nextButtonTextColor: "red",
            previousButtonTextColor: "red"
        };
        var settings = $.extend( {}, defaults, options );
        return this.each(function() {
            // Plugin code would go here...
        });
    };
    

    另一位小朋友Sue决定用Bob的插件编写一些东西,当她想要修改 宽度动画变化速度 animateWidthDuration时,发现Bob写的插件中居然没有这个选项 >> 懵逼小脸(●' - '●)
    ==> It's not really about how many options your plugin has; but what options it has! 这是Bob犯的第一个错误,参数定义的不够全

    Bob小朋友犯的第二个错误 来自参数 delay。他将delay的选项定义成了抽象的描述:

    var delayDuration = 0;
    switch ( settings.delay ) {
        case "very short":   delayDuration = 100;    break;
        case "quite short":  delayDuration = 200;    break;
        case "quite long":   delayDuration = 300;    break;
        case "very long":    delayDuration = 400;    break;
        default:             delayDuration = 200;
    }
    

    => not only limit the level of control the people have(here I mean Sue or you), but also take quite a bit of place.
    ==> 应该就直接用数字

    Give Full Control of Elements

    If your plugin creates elements to be used within the DOM, then it's a good idea to give certain elements IDs or classes.
    BUT note that your plugin sholdn't rely on these hooks INTERNALLY!
    ==> 用人话说,就是不要把选择元素的代码(比如$(".gallery-wrapper").append("...");)放在plugin的闭包里面!
    反例:

    $.fn.inLight = function( options ) {
        // ...
        $( "<div class='gallery-wrapper' />" ).appendTo( "body" );
        $( ".gallery-wrapper" ).append( "..." );
    }
    

    以上这种情况,有个隐患,万一用户使用该plugin的时候,想要修改元素的某些属性(比如颜色或者字体)将无法实现。
    To allow users to access and even manipulate that information, you can store it in a variable containing the settings of your plugin.

    $.fn.hilight = function( options ) {
    
        // ...
    
        var defaults = {
            wrapperAttrs : {
                class: "gallery-wrapper"
            },
        };
         
        // We can use the extend method to merge options/settings as usual:
        // But with the added first parameter of TRUE to signify a DEEP COPY:
        var settings = $.extend( true, {}, defaults, options );
    
        // Retain an internal reference
        var wrapper = $("<div />")
                        .attr( settings.wrapperAttrs )
                        .appendTo( settings.container );
    };
    
    // Easy to reference later
    wrapper.append("...");
    

    ==> 用户可以通过定义的变量wrapper来修改类的名字, 同理,我们也可以修改元素的CSS样式,比如这里,我们将变量多设置一个css()方法

    var defaults = {
        wrapperAttrs: {...};
        wrapperCSS: {...},
        // ... rest of settings
    };
    
    // Retain an internal reference:
    var wrapper = $('<div />')
           .attr( settings.wrapperAttrs )
           .css( settings.wrapperCSS )        // 允许我们修改CSS样式
           .appendTo( settings.container );
    
    Provide Callback Capabilities

    What is a callback? – A callback is essentially a function to be called later, normally triggered by an event.

    => If your plugin is driven by events then it might be a good idea to provide a callback capability for each event.
    ==> Plus, you can create your own custom events and then provide callbacks for those.

    var defaults = {
        /**
         *  We define an empty anonymous function
         *  so that we don't need to check its existence before calling it.
         *  because it exists
         */
        onImageShow: function() {},
    
        //... rest of settings...
    }
    
    nextButton.on("click", showNextImage);  // Event "Click" triggered the function showNextImage()
    
    function showNextImage() {
        var image = getNextImage();     // Returns reference to the next image node
    
        //... code to show the image here
    
        settings.onImageShow.call(image);    // CALLBACK: image call the function onImageShow()
    }
    

    关于call()函数:

    call( [ thisObj [,arg1 [, arg2 [, [,.argN ]]]]] ) 
    call 方法可以用来代替另一个对象调用一个方法
    
    ---------------- 相似的方法 > apply() ----------------
    apply([thisObj[,argArray]]) 
    应用某一对象的一个方法,用另一个对象替换当前对象。 
    
    ---------------- 举例 ----------------
    /**定义一个animal类*/  
        function Animal(){   
            this.name = "Animal";   
            this.showName = function(){   
                alert(this.name);   
            }   
        }   
    /**定义一个Cat类*/  
        function Cat(){   
            this.name = "Cat";   
        }   
          
    /**创建两个类对象*/  
        var animal = new Animal();   
        var cat = new Cat();   
          
    /*通过call或apply方法,将原本属于Animal对象的showName()方法交给当前对象cat来使用了。*/   
    
        animal.showName.call(cat,",");           //输入结果为"Cat"   
        // 或 animal.showName.apply(cat,[]);   
    
    ---------------- 结论 ----------------
    以上代码无论是采用animal.showName.call或是animal.showName.apply方法,运行的结果都是输出一个"Cat"的字符串。
    说明showName方法的调用者被换成了cat对象,而不是最初定义它的animal了。这就是call和apply方法的妙用!
    

    这里的callback初始化的方法比较特别
    => 我们调用了imagecontext
    ==> 也就是说,我们可以通过this访问当前的image对象, 比如:

    $(" ul.img li ").superGallery({
        onImageShow: function() {
            $(this).after( "<span>" + $(this).attr("longdesc") + "</span>" )
        }
    });
    

    关于after()函数:

    .after( content )
    - Insert content, specified by the parameter, after each element in the set of matched elements. 
    content can be one or more HTML string, DOM element, text node, array of elements and text nodes, or jQuery object to insert after each element in the set of matched elements.
    
    .after(function)
    - a function that returns aforementioned content
    
    Remember, It's a Compromise

    And equally, it's not going to be very useful if you offer no or very few methods of control. So, remember, it's always going to be a compromise.

    Three things you must always take into account are:

    • Flexibility: How many situations will your plugin be able to deal with?
    • Size: Does the size of your plugin correspond to its level of functionality? I.e. Would you use a very basic tooltip plugin if it was 20k in size? – Probably not!
    • Performance: Does your plugin heavily process the options in any way? Does this affect speed? Is the overhead caused worth it for the end user?

    相关文章

      网友评论

          本文标题:jQuery插件 / 进阶

          本文链接:https://www.haomeiwen.com/subject/xaioixtx.html