资讯专栏INFORMATION COLUMN

「jQuery插件开发日记」(二)高级插件理念 - [翻译]

paulquei / 1767人阅读

摘要:我们也可以在设置中间允许一个回调函数,来覆盖默认的函数,这也是一个支持定制的非常棒的方法。对外暴露了一个对象。所以我们的设置应该像这样对于也可以使用同样的方法来实现提供回调函数如果你的插件是事件驱动的话,最好为每个事件提供回调函数。

_Advanced Plugin Concepts_,翻译自 jQuery 官方网站。

默认设置的共有接口

对于上一篇文章最后的代码,我们可以改进,也应该改进的地方就是,为我们的插件的默认设置提供共有接口,使得用户可以直接更改默认设置。

这样做的好处就是可以让用户用最少的代码量来定制我们的插件。这次的例子是:

// Plugin definition.
$.fn.hilight = function( options ) {
 
    // Extend our default options with those provided.
    // Note that the first argument to extend is an empty
    // object – this is to keep from overriding our "defaults" object.
    var opts = $.extend( {}, $.fn.hilight.defaults, options );
 
    // Our plugin implementation code goes here.
 
};
 
// Plugin defaults – added as a property on our plugin function.
$.fn.hilight.defaults = {
    foreground: "red",
    background: "yellow"
};

现在用户可以这样更改默认设定:

// This needs only be called once and does not
// have to be called from within a "ready" block
$.fn.hilight.defaults.foreground = "blue";

这样使用我们的插件:

$( "#myDiv" ).hilight();

你可以看到,我们允许用户使用仅仅一行代码就覆盖了某个默认设定。除此之外,用户仍然可以传入参数来覆盖他们设定的默认设置。

// Override plugin default foreground color.
$.fn.hilight.defaults.foreground = "blue";
 
// ...
 
// Invoke plugin using new defaults.
$( ".hilightDiv" ).hilight();
 
// ...
 
// Override default by passing options to plugin method.
$( "#green" ).hilight({
    foreground: "green"
});
附属函数的公共接口

为某些附属函数提公共接口,能够非常好的去扩展和让别人扩展你的插件。

举个例子,我们的插件可能实现了一个叫 format 的函数, 这个函数格式化强调文本的形式。我们在 hilight 函数下面定义了 format 的默认方法。

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

我们也可以在设置中间允许一个回调函数,来覆盖默认的 format 函数, 这也是一个支持定制的非常棒的方法。
使用这些技术,其他人可以非常方便的定制你的插件,然后发布。换句话说,其他人可以为你的插件来写插件。

考虑到这篇文章里这个苍白的例子并不是非常具有说服力,一个现实的例子就是 Cycle Plugin。这个插件是一个幻灯片插件,内置非常多切换特效,像滚动、滑动、淡出等。但是实际上它不可能定义每个人想要的效果,那么插件的扩展性就非常重要了。

Cycle Plugin 对外暴露了一个 transitions 对象。 在这里用户可以自己定义他们的切换特效。

$.fn.cycle.transitions = {
 
    // ...
 
};
保持私有函数私有

对外提供一部分你的插件的公共接口确实很强大,但是你要想清楚哪些部分需要提供给公共接口,哪些不需要。当函数一旦暴露在外,任何对参数和语义(函数的功能)的更改都会摧毁向后兼容性。一般来说,如果你不确定一个方法是否应该设为公有,那么也许答案是不。

所以我们如何在不搞乱命名空间并且保持私有的情况下定义更多的函数呢?这就是闭包的事情了。

为了展示如何解决这个问题,我们在我们的插件里加了一个函数 debug。这个函数在 console 中输出选定的对象。我们将整个插件用一个函数包裹起来(上一篇文章也有提到)。

// Create closure.
(function( $ ) {
 
    // Plugin definition.
    $.fn.hilight = function( options ) {
        debug( this );
        // ...
    };
 
    // Private function for debugging.
    function debug( obj ) {
        if ( window.console && window.console.log ) {
            window.console.log( "hilight selection count: " + obj.length );
        }
    };
 
    // ...
 
// End of closure.
 
})( jQuery );
Bob & Sue(实例)

Bob 已经创建了一个新的画廊插件(叫 "superGallery")。这个插件使得一系列图片变得可导航的。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...
    });
 
};

你想到的第一件事情可能就是,这个插件该有多大才能实现这么多可定制功能。这个插件的体积可能完全没必要这么大。

Bob 对他的插件非常满意。他觉得他的插件会在不同的情景之下会是一个通用的解决方案。

Sue 决定去用一用这个新插件。她设置了所有的选项,但是她意识到,如果图片的宽度以低速变化的话,会获得更加好的效果。她赶紧去搜索了 Bob 的文档,但是并没有找到 animateWidthDuration 类似的选项。

你看到问题了吗?

问题的关键是并不是你的插件有多少个选项,而是有什么选项。

Bob 做的有点儿过了。他提供的定制性看起来很高,其实非常低。特别是考虑到一个人可能想要在这个插件中控制的所有特性。Bob 犯了个错误,它提供了非常多荒诞的选项,殊不知让他的插件变得更难定制了。

一个更好的模型

所以现在非常明显了,Bob 需要一个新的定制模型。一个并没有放弃必须的控制和抽象细节的定制模型。

这里有一些建议,可以让你更好的创建一个可定制化插件。

不要创建自己的语法

使用你的插件的开发者不应该要去学一门新的语言或新的技术,只要搞定他们的工作。

Bob 他为 delay 这个选项提供了最大的定制性。他设置了4个不同的延迟:

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;
 
}

这导致不仅仅用户所能控制的延迟水平变少了,还花费了比较多的空间。20行代码仅仅就为了定义一个延迟时间,有点儿多了。

一个更加好的方式就是让用户自己传入延迟的时间。

元素的完全控制权

如果你的插件在DOM中创建了一些元素。那么你最好让用户有方法去控制它。有些时候这意味着提供给用户传入ID或者类名的方法。但是注意你的插件不应该全局依赖这些。

一个不好的实现:

// Plugin code
$( "

一个好一点儿的实现:

// Retain an internal reference:
var wrapper = $( "
" ) .attr( settings.wrapperAttrs ) .appendTo( settings.container ); // Easy to reference later... wrapper.append( "..." );

注意我们使用了 .attr() 来增加特定的属性。所以我们的设置应该像这样:

var defaults = {
    wrapperAttrs : {
        class: "gallery-wrapper"
    },
    // ... rest of settings ...
};
 
// 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 );

对于CSS 也可以使用同样的方法来实现:

var defaults = {
    wrapperCSS: {},
    // ... rest of settings ...
};
 
// Later on in the plugin where we define the wrapper:
var wrapper = $( "
" ) .attr( settings.wrapperAttrs ) .css( settings.wrapperCSS ) // ** Set CSS! .appendTo( settings.container );
提供回调函数

如果你的插件是事件驱动的话,最好为每个事件提供回调函数。

var defaults = {
 
    // We define an empty anonymous function so that
    // we don"t need to check its existence before calling it.
    onImageShow : function() {},
 
    // ... rest of settings ...
 
};
 
// Later on in the plugin:
 
nextButton.on( "click", showNextImage );
 
function showNextImage() {
 
    // Returns reference to the next image node
    var image = getNextImage();
 
    // Stuff to show the image here...
 
    // Here"s the callback:
    settings.onImageShow.call( image );
}
记住,这是一个权衡问题

你的插件不可能在所有的情况下都能工作。同样的,当你提供很少的控制的方法的时候,它也有可能没啥用。所以,权衡是非常重要的事情。以下有三点:

灵活性:你的插件要处理多少种情况?

大小:你的插件大小和它的功能相匹配吗?

性能:你的插件无论什么情况都会处理设置选项吗?影响速度吗?值得吗?

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/85935.html

相关文章

  • jQuery插件开发日记」(一)如何建立一个基础的插件 - [翻译]

    摘要:,翻译自官方网站。如何建立一个基础的插件有时,你想要在你的代码里面实现一个可复用的功能。译者注建立一个基础的插件假设我们现在要建立一个让元素里的文字变绿的插件。链式操作最大的特点之一就是支持链式操作。例如译者注的作用是返还的控制权。 _How to Create a Basic Plugin_, 翻译自 jQuery 官方网站。 如何建立一个基础的插件 有时,你想要在你的代码里面实现一...

    Sunxb 评论0 收藏0
  • 小白成长日记:一步一步写个轮播图插件

    摘要:并不是所有人写的代码或者插件都适合小白使用,比如这是一个的滚动插件,大多数人使用了之后发现滚动不了,去作者提,其实是他们并不懂滚动的原理。 最近在这里看了一篇关于面试的文章《回顾自己三次失败的面试经历》,作者三次倒在了轮播图上。囧,所以我也写个轮播图看看。这次是用jQuery写的,因为最近一直在研究jQuery插件的写法,所以用jQuery写的,而且我发现,我vue用太多,完全不熟悉d...

    notebin 评论0 收藏0
  • 基于 Laravel Route 的 社交系统ThinkSNS+ Component【研发日记系列三

    摘要:在社交系统中有这样一个命令主要是用作包的安装,升级,卸载。这在开发过程中很有用。内测申请方式提供个人企业联系方式及认证信息实名企业营业执照照片或扫描件及申请说明,发送邮件至将有机会获得首批内测资格,名额有限,申请从速。 在前面,我介绍了拓展类型,分别有 plus-compnent 和 plus-plugin 两个,这里重点讲以下如何实现 plus-component 的。 plus-c...

    pf_miles 评论0 收藏0
  • ElasticSearch学习日记(一)

    摘要:工作这么多年,第一次想起来写技术博客,记录自己的学习历程。这几天项目中集成全文检索,在此记录自己的学习历程与各位友人共同分享。学习是在自己的电脑安装一环境以下文中所提及的是简称下载地址下载新的版本下载完成解压到你的开发目录即可。 工作这么多年,第一次想起来写技术博客,记录自己的学习历程。这几天项目中集成ES全文检索,在此记录自己的学习历程与各位友人共同分享。学习是在自己的电脑安装Ela...

    codecraft 评论0 收藏0
  • [ 前端实习日记 ] 构建静态页面基础架构

    以前我们敲静态页面都是写好html,css, js,然后再去刷新浏览器,艾尼马又不行,有重新写过再刷新,一个页面下来按chrl+r的次数可让你的键盘多活好几天,要不会刷新快捷按钮那不得手残了都。 后来,grunt,gulp等工具应运而生,当然它们不止这个功能,但却很好地减轻了我们的负担。这篇文章介绍一些如何使用这些工具使构建页面变得简单高效。这只是个人的目前在用的不成熟的方案,更专业的还请参考...

    lidashuang 评论0 收藏0

发表评论

0条评论

paulquei

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<