月度归档:2012年12月

php如何自动引入目录或是文件夹

遇到一个问题找了好久手册和搜索,还是没有解 决,就到这里发个贴吧,怎么说德问也是技术型问答社区,目前呢PHP好像只支持自动加载类__autoload()“spl”系列,但是我想做个小框架, 把大概的思路说明下单一路口,实现类自动加载(常见的__autoload或是数组辐射下__autoload)就可以把这个类的问题解决,可现在我想把 框架定义为app形式或是插件形式;
比如说目录结构:
/public/lib/放基类;
/public/ext/放拓展基类;
/public/mvc/这里放MVC模式的基类;
目录下唯一index.php;
那么现在来说说app目录了,现在可见的问题是,我想在app目录下创建一个功能或是插件,现在需要在这里定义下目录名称,比如:
app/name;
那么现在在app下有个name目录了,现在我就是要把action,model,templates目录建立起来,作为对应存放的MVC文件
app/name/action;
app/name/model;
app/name/templates;

大家有什么好的办法解决下这个自动加载目录的问题?
比如说设置一个参数对应app功能名称?
呵呵,小子很多方面不是很精通,只是想折腾,研究下磨练磨练自己,有啥话多说说,开拓开拓思路。。

 

有人知道的话发邮件给我或是留言哦,或是一起加入upadd的开发,upadd.cn 是个开源框架,为了更加舒服,突发奇想的想搞一个自动加目录的方法。。真难找

Linux 防火墙编辑重启命令

1.  在/etc/sysconfig/iptables里添加

# vi /etc/sysconfig/iptables

添加一条配置规则,如要想开放8080的端口,如下所示:

-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 8080 –j ACCEPT

2. 重启iptables

# /etc/init.d/iptables restart

3. 看下状态

# /etc/init.d/iptables status

4.关闭防火墙

(1) 重启后永久性生效:

开启:chkconfig iptables on

  关闭:chkconfig iptables off

(2) 即时生效,重启后失效(即重启后防火墙自动开启):

开启:service iptables start

关闭:service iptables stop

Seajs配置模式清单

seajs 支持一些配置选项,能让开发、调试更方便。

seajs.config seajs.config(options)

可以使用 config 方法来配置加载器。

seajs.config({
  alias: {
    'es5-safe': 'gallery/es5-safe/0.9.3/es5-safe',
    'json': 'gallery/json/1.0.2/json',
    'jquery': 'gallery/jquery/1.8.2/jquery'
  },
  preload: [
    Function.prototype.bind ? '' : 'es5-safe',
    this.JSON ? '' : 'json'
  ],
  debug: true,
  map: [
    ['http://example.com/js/app/', 'http://localhost/js/app/']
  ],
  base: 'http://example.com/path/to/base/',
  charset: 'utf-8'
});

支持以下配置选项:

alias

当模块标识很长时,可以使用 alias 配置来简化。

seajs.config({
  alias: {
    'app': 'http://path/to/app',
    'jquery': 'gallery/jquery/1.8.2/jquery'
  }
});

a.js:

define(function(require, exports, module) {
    var $ = require('jquery');
      //=> 加载的是 http://path/to/base/gallery/jquery/1.8.2/jquery.js

    var biz = require('app/biz');
      //=> 加载的是 http://path/to/app/biz.js
});

解析某个模块标识时,如果需要临时禁用别名解析,可以在标识前添加一个井号(#):

define(function(require, exports, module) {
    var $ = require('#jquery');
      //=> http://path/to/base/jquery.js
});

alias 最常用来做版本配置与管理,也可以用来做命名空间管理。

preload

使用 preload 配置项,可以在普通模块加载前,提前加载并初始化好指定模块。

// 在老浏览器中,提前加载好 ES5 和 json 模块:
seajs.config({
  preload: [
    Function.prototype.bind ? '' : 'es5-safe',
    this.JSON ? '' : 'json'
  ]
});

preload 中的空字符串会被忽略掉。

注意preload 中的配置,需要等到 use 时才加载。比如:

seajs.config({
  preload: 'a'
});

// 在加载 b 之前,会确保 a 模块已经加载并执行好。
seajs.use('./b');

preload 配置不能放在模块文件里面:

b.js:

seajs.config({
  preload: 'a'
});

define(function(require, exports) {
  // 此处执行时,无法保证 a 模块已经加载并执行好。
});

debug

值为 true 时,加载器会使用 console.log 输出所有错误和调试信息。 默认为 false, 只输出关键信息。

另外,还可以将 debug 值设为 2 . 这种情况下, 每个脚本请求都会加上唯一时间戳。这在测试期间很有用,可以强制浏览器每次都请求最新版本,免去 Ctrl + F5 之烦恼。

map

该配置可将某个文件映射到另一个。可用于在线调试,非常方便。更多信息,请参考 调试实践

base

SeaJS 在解析顶级标识时,会相对 base 路径来解析。详情请参阅 模块标识

注意:一般请不要配置 base 路径,保持默认往往最方便。

charset

获取模块文件时,<script> 或 <link> 标签的 charset 属性。 默认是 utf-8 。

charset 配置项还支持 function 类型:

seajs.config({

  charset: function(url) {
    // xxx 目录下的文件用 gbk 编码加载
    if (url.indexOf('http://example.com/js/xxx') === 0) {
      return 'gbk';
    }
    // 其他文件用 utf-8 编码
    return 'utf-8';
  }

});

本文来源:https://github.com/seajs/seajs/issues/262

在线浏览PDF文件的实用jquery插件推荐

在web开发当中我们经常需要进行需要在线浏览PDf内容,在线嵌入动态pdf,传统的解决方法安装客户端PDF阅读器,如果是在谷歌是可以在线浏览的,因为他自身就带了一些插件,以前遇到这样的问题往往是费时又费力,很不好解决,

今天就给大家分享一系列使用javascript实现的pdf插件效果,无需借助第三方插件就可以实现在线浏览功能,非常实用,

PDFObject

PDFobject可以帮助你在页面直接嵌入pdf文件,有时候有些项目需要动态地嵌入PDF文件。PDFObject为此而设计的,他能够快速和容易的嵌入PDF文件,PDFObject使用JavaScript来产生相同的符合标准的<OBJECT>标记,然后插入<OBJECT>到您的HTML元素的选择。您可以填满整个浏览器窗口,或将PDF格式转换成一个<DIV>或其他块级元素。

pdf.js

和 Google Chrome 使用的源自 Foxit 的闭源 PDF 浏览插件不同,PDF.js 是基于开放的 HTML5 及 JavaScript 技术实现的开源产品

pdf.js 是一个主要用于HTML5 平台上在线阅读PDF文档的小插件,基于JavaScript技术编写而成,无需任何本地技术支持。

pdf.js是由Mozilla Labs发布的。他们的目标是创建一个通用的,基于标准的网络平台,能够解析和渲染PDF文件,并最终发布一个PDF阅读器扩展,毫无疑问 pdf.js 将被整合入 Gecko 成为 Firefox 的内嵌 PDF 阅读器,但是具体整合时间表尚未确定

jsPDF

jsPDF 是一个使用Javascript语言生成PDF的开源库。你可以在Firefox插件,服务端脚本或是浏览器脚本中使用它。客户端Safari 和 iPhone Safari 支持得最好,其次是Opera和Windows下的Firefox 3等。IE暂不支持。。

jQuery Media Plugin

jQuery Media Plugin是一款基于jQuery的网页媒体播放器插件,它支持大部分的网络多媒体播放器和多媒体格式,比如:Flash, Windows Media Player, Real Player, Quicktime, MP3,Silverlight, PDF。它根据当前的脚本配置,自动将a标签替换成div,并生成object, embed甚至是iframe代码,至于生成object还是embed,jQuery Media会根据当前平台自动判别,因此兼容性方面非常出色下面这段代码是jQuery Media生成后的结果:

 

<div>

<object width="450" height="250" attr1="attrValue1" attr2="attrValue2"

codebase="http://www.apple.com/qtactivex/qtplugin.cab"

classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B">

<param name="src"      value="myBetterMovie.mov">

<param name="autoplay" value="true">

<param name="param1"   value="paramValue1">

<param name="param2"   value="paramValue2">

<embed width="450" height="250" src="myBetterMovie.mov" autoplay="true"

attr1="attrValue1" attr2="attrValue2" param1="paramValue1" param2="paramValue2"

pluginspage="http://www.apple.com/quicktime/download/" > </embed>

</object>

</div>

 

具体使用方法

html标记代码

 

<a href="sample.mov">My Quicktime Movie</a>

<a href="sample.swf">My Flash Movie</a>

<a href="sample.wma">My Audio File</a>

初始化脚本:

1

$('.media').media();

 

Google Docs PDF viewer

ZOHO Viewer

Anychart:使用JavaScript导出PDF

下图可以导出为PNG或JPG格式的静态图像或嵌入式静态图像,图表或一个完全互动的功能图

jQuery Document Viewer

Document Viewer是一个jQuery插件,可以让你在网页中直接查看多种文件格式。文档浏览器支持的文件格式:PDF文件,文本文件,代码,图像,音频,视频等。

27个jQuery网页拖放操作的插件

这篇文章为你介绍27个jQuery插件,使得你的Web前端具备拖放操作的能力。

Ajax Upload

提供文件拖放上传,并显示上传进度

\" border=

Drop n’ Save – Drag & Drop Uploader

另外一个文件拖放上传功能的实现。

\" border=

MORE INFO |DEMO by Codecanyon (premium plugin)

jqDnR

jqDnR作为jQuery是一个轻量级的,让你拖、放自如,并且调整其大小的元素插件。这个插件很简单,重量轻(972字节),非常容易实现。 能够让您的网站更方便用户使用。

\" border=

jQuery Drag Expose | Draggable Image Gallery

使用一种不同的方式来显示照片,并可进行拖放操作

\" border=

MORE INFO |DEMO by Codecanyon (premium plugin)

Sortable Lists

很酷的脚本用来对列表进行拖放操作

\" border=

jQuery OneByOne Slider Plugin

OneByOne Slider 是一个轻量级的 jQuery 插件,可用来显示图片和文本,使用 CSS3 动画效果,支持触摸设备上的左右滑动,可使用鼠标拖放操作进行显示

\" border=

MORE INFO |DEMO by Codecanyon (premium plugin)

Table Drag and Drop JQuery plugin

在表格内对行数据进行拖放

\" border=

Dynamic Drag’n Drop With jQuery And PHP

Drag’n drop 是一个完全使用 jQuery & jQuery UI 实现的拖放功能。

\" border=

Easy Scroll

可轻松实现拖放滚动效果的页面。

\" border=

MORE INFO |DEMO by Codecanyon (premium plugin)

Draggable

一个基于jQuery的拖放插件,易于使用,所有的操作均通过调用draggable进行。\" border=

Drag-and-Drop with jQuery: Your Essential Guide

学习如何使用 jQuery 和 jQuery UI 的拖放插件来创建具有拖放效果的 Web 应用,包含一个完整的扑克牌拖放操作演示。

\" border=

Zoomer jQuery Products Showcase

Zoomer! 是一个用来显示产品列表的工具,内置缩放和拖放功能。

\" border=

MORE INFO |DEMO by Codecanyon (premium plugin)

animaDrag

AnimaDrag 允许拖拉的元素具有动画效果。

\" border=

Ultra small code to drag everything in HTML pages

这是一个很基本的快速实现拖放操作的教程,可重用以及个性化定制。

\" border=

$.event.special.drag

这是 jQuery 的事件实现拖放事件模型,开发者无需了解太多拖放的细节。

\" border=

(mb)ConteinersPlus

很有用的插件用于实现皮肤化的容器,支持拖拉、大小更改以及最小化等操作。

\" border=

resizable

可对元素使用拖放操作来更改大小

\" border=

ppDrag

ppDrag 是 jQuery 的拖放插件,简化了 jQuery UI‘s Draggable.

\" border=

NestedSortable

\" border=

jQuery File Tree Aza’s revised version

\" border=

Dragscrollable

用于在一个可视范围内滚动一个很大的嵌套层,类似地图。

\" border=

dragndrop

轻松实现拖放操作

\" border=

Collidable Draggables

Adds collision detection to draggable objects. Add “collide: ‘block’” or “collide: ‘flag’” when you create a draggable: $(".box").draggable({collide: 'flag'}); or $(".box").draggable({collide: 'block'}); In ‘flag’ mode overlapping objects receive new classes – ‘ui-draggable-overlapping’ for the object being dragged and ‘ui-draggable-overlapped’ for the other object. In ‘block’ mode objects are blocked from overlapping other objects by being snapped to the edge of the object they collided with.

jQuery UI multiple draggable plugin

jQuery multiple draggable plugin 是 jQuery UI 的拖放插件扩展,可实现分组拖放

\" border=

jQuery List DragSort

一个轻量级的 jQuery 插件,提供拖放排序列表的功能

\" border=

Jquery iviewer

JQuery.iviewer 是一个用来在一个固定范围内查看图片的插件,可对图片进行缩放以及拖放移动显示

\" border=

(mb)ImgNavigator

相册插件,用于显示很大的图片,通过拖放进行浏览

\" border=

$().mapbox

实现类似 Google 地图的拖拉操作。

\" border=

Drag n Drop Scattered Gallery

Drag and drop gallery script with various look and feel options.

\" border=

MORE INFO |DEMO by Codecanyon (premium plugin)

JS常用坐标

网页可见区域宽:document.body.clientWidth

网页可见区域高:document.body.clientHeight

网页可见区域宽:document.body.offsetWidth (包括边线的宽)

网页可见区域高:document.body.offsetHeight (包括边线的宽)

网页正文全文宽:document.body.scrollWidth

网页正文全文高:document.body.scrollHeight

网页被卷去的高:document.body.scrollTop

网页被卷去的左:document.body.scrollLeft

网页正文部分上:window.screenTop

网页正文部分左:window.screenLeft

屏幕分辨率的高:window.screen.height

屏幕分辨率的宽:window.screen.width

屏幕可用工作区高度:window.screen.availHeight

屏幕可用工作区宽度:window.screen.availWidth

HTML精确定位:

scrollLeft,scrollWidth,clientWidth,offsetWidth scrollHeight 获取对象的滚动高度。

scrollLeft:设置或获取位于对象左边界和窗口中目前可见内容的最左端之间的距离

scrollTop:设置或获取位于对象最顶端和窗口中可见内容的最顶端之间的距离

scrollWidth:获取对象的滚动宽度

offsetHeight:获取对象相对于版面或由父坐标

offsetParent 属性指定的父坐标的高度

offsetLeft:获取对象相对于版面或由

offsetParent 属性指定的父坐标的计算左侧位置

offsetTop:获取对象相对于版面或由

offsetTop 属性指定的父坐标的计算顶端位置

event.clientX 相对文档的水平座标

event.clientY 相对文档的垂直座标

event.offsetX 相对容器的水平坐标

event.offsetY 相对容器的垂直坐标

document.documentElement.scrollTop 垂直方向滚动的值

event.clientX+document.documentElement.scrollTop 相对文档的水平座标+垂直方向滚动的量

IE,FireFox 差异如下: IE6.0、FF1.06+: clientWidth = width + padding clientHeight = height + padding offsetWidth = width + padding + border offsetHeight = height + padding + border IE5.0/5.5: clientWidth = width - border clientHeight = height - border offsetWidth = width offsetHeight = height (需要提一下:CSS中的margin属性,与clientWidth、offsetWidth、clientHeight、offsetHeight均无关)

12款很棒的浏览器兼容性测试工具

对于前端开发工程师来说,确保代码在各种主流浏览器的各个版本中都能正常工作是件很费时的事情,幸运的是,有很多优秀的工具可以帮助测试浏览器的兼容性,让我们一起看看这些很棒的工具。

Spoon Browser Sandbox

点击你需要测试的浏览器环境,安装插件就可以进行测试了。帮助你测试网页在Safari、Chrome、Firefox和Opera浏览器中是否正常,IE以前也有的,网站上说应微软的要求去掉了。

 

 

Superpreview

这是为微软自己发布的跨浏览器测试工具,您可以同时查看您的网页在多个浏览器的呈现情况,对页面排版进行直观的比较。

IETester

专门用于测试网页在IE浏览器各个版本中兼容性的工具,版本包含IE5.5至IE9的各个版本,很不错的一款工具,推荐。

BrowserShots

BrowserShots 是一款免费的跨浏览器测试工具,捕捉网站在不同浏览器中的截图。这是最有名,也是最古老的浏览器兼容性测试工具。

Multiple IEs

这款工具同样用于测试网页在IE浏览器各个版本的兼容性。

IE netrenderer

Netrenderer 也是用于检查你的网站在IE浏览器中的呈现情况,包括各个常用版本的检测。

Viewlike.Us!

Viewlike 是一款新推出的工具,帮助你检查浏览器在不同分辨率下得呈现情况。

BrowserSeal

这款工具的两个主要特色是独立的浏览器支持和带有自动化脚本的命令行界面。

Browsera

Browsera 是一个可测试您的网站的跨浏览器布局的工具,您会看到您网站上存在的兼容性错误。

WebDevLab

这款工具专门用于测试你的网站在苹果Safari浏览器中是什么样子的。

Litmus

这个工具可以帮助你检查你的网站在多个浏览器中的呈现情况,跟踪Bug并创建报告。

Browsercam

最后这款工具是要付费的,可以帮助你检查 Javascript 和 DHTML,提供不同的测试环境平台。

Aptana Studio3的汉化

点击 “Help” > “Install New Software”;

在弹出的“install”窗口中的“Work With”的输入框中填上如下网址:

http://archive.eclipse.org/technology/babel/update-site/R0.8.1/helios

然后,点击“add”按钮,正文会出现语言包列表,选择中文简体,接着的大家都知道了,一路“next”,直到“finish”;

 

“install”窗口关闭后,Aptana 3 会自动下载语言包并安装,安装完毕后,它会提示你重启Aptana,至此,你的Aptana 3 就是可爱的中文版啦。

Seajs引入jQuery模块介绍与 jQuery 插件的深度模块化(二)实践学习

jQuery 插件非常丰富。在传统使用方式里,比如 jquery-fancybox, 我们需要在页面中显式引入:

1 <script src="/js/jquery.min.js"></script>
2 <script src="/js/jquery.easing-1.3.pack.js"></script>
3 <script src="/js/jquery.mousewheel-3.0.4.pack.js"></script>
4 <script src="/js/jquery.fancybox-1.3.4.js"></script>
5 <link rel="stylesheet" href="/js/jquery.fancybox-1.3.4.css"/>

fancybox 依赖 easing 和 mousewheel, 因此还引入了这两个插件文件。当使用的插件越多,依赖关系越复杂时,上面的 script 列表会越难维护。

 

模块化

我们看下在 seajs 里如何做。

看 demo: FancyBox 1.3.4 | Demonstration

页面源码里,引入的 script 只剩下一处:

1 <script src="http://seajs.org/dist/sea.js" data-main="./init"></script>

来看 init.js:

1 /* init.js */
2 define(function(require) {
3   var $ = require('jquery');
4   require('./fancybox/jquery.fancybox-1.3.4.js')($);
5
6   // snip...
7 });

init 依赖 jquery 和 fancybox, 因此 require 了这两个模块。

 

require('./fancybox/jquery.fancybox-1.3.4.js') 返回的是 function, 其代码为:

1 /* jquery-fancybox-1.3.4.js */
2 define(function(require) { return function($) {
3   require('./jquery.easing.1.3.js')($);
4   require('./jquery.mousewheel.js')($);
5   require('./jquery.fancybox-1.3.4.css');
6   
7   // snip...
8 }});

 

jQuery 插件的机制是往 $ 或 $.fn 上添加插件成员。在 seajs 里,我们可以将插件包装成一个函数。这样,在使用时,传入需要被扩展的 jQuery 实例就好。

对于不依赖其它插件的 jquery 插件,模块化包装就更简单了:

1 /* jquery.mousewheel.js */
2 define(function() { return function($) {
3   // snip..
4 }});

 

通过这种方式,我们可以将任何 jquery 插件封装成 seajs 的模块!

共享模式

上面的方式可以概括为:

1 var $ = require('jquery');
2 require('some-jquery-plugin')($);

 

这是一种共享模式,一旦添加某个插件功能到 jQuery 后,其他模块里,require('jquery') 返回的 jquery 对象会自动拥有已经添加过的插件功能。这种共享模式可以对 jquery 的插件进行集中管理。比如对于具体项目,可以在 init.js 文件里:

1 /* init.js */
2 define(function(require) {
3   var $ = require('jquery');
4   require('jq-plugin-a')($);
5   require('jq-plugin-b')($);
6   require('jq-plugin-c')($);
7   
8   // snip...
9 });

 

这样,在其它模块中,通过 require('jquery') 就可以得到添加过所需要的所有插件功能的 jquery 对象。

子类模式

当项目很复杂,jquery 插件之间有可能存在冲突。为了尽可能避免冲突,我们可以通过 jQuery 子类来解决:

1 var $ = require('jquery').sub();
2 require('some-jquery-plugin')($);

 

通过 sub 方法,每个依赖 jquery 的模块,都可以得到 jQuery 的一个子类。插件往这个子类添加成员,因此各个模块之间的 jquery 是独立的了,彼此不会影响。

延续习惯

无论是共享模式还是子类模式,都不会破坏插件本身的使用方式,原来是怎么调用的,现在依旧怎么用。唯一不同的是引入方式。模块化之前,我们需要手动引入 script 标签来解决;模块化之后,我们通过 require 来管理加载和依赖。

小结

通过这种包装,我们就可以在 seajs 里使用任何 jquery 插件了,并且通过 seajs 的 node 模块,还可以让 jquery 的插件在 node 环境中运行。

一切就这么简单。看起来没什么变化,但变化就在其中!

 

转载来源:http://lifesinger.wordpress.com/2011/05/18/jquery-plugins-modulization/

Seajs引入jQuery模块介绍与 jQuery 插件的深度模块化(一)入门学习

jQuery 模块

大名鼎鼎的 jQuery 就不多介绍了,详细介绍推荐官网:jquery.com

几点感悟:

  1. jQuery 是 DOM 操作类库,其核心功能是找到 DOM 元素并对其进行操作。
  2. 拿 jQuery 与 YUI, Dojo 等框架相比是不公平的,就如拿轮胎和汽车相比一样。jQuery 只是一个轮胎,功能很单一,YUI 和 Dojo 等则是相对完整的汽车,除了轮胎,还有引擎、外壳等等。
  3. 说 jQuery 不适合构建大型应用,就如说轮胎不适合参加赛车比赛一样不合逻辑。你可以用 jQuery 做轮胎,然后选择其他部件组合起来去 DIY 一辆赛车。能否胜出,得看赛车手的 DIY 水准。
  4. jQuery 的困局在于 DIY 高手不多,经常是一个好轮胎挂上一堆破破烂烂的外壳就上前线了。jQuery 的破局也在于 DIY. DIY 意味着灵活、可替换性,意味着可快速前行和高性能。
  5. jQuery 灵活性带来的缺陷,比如有可能由选择器和链式风格导致的低效 DOM 操作,目前在提供了同类功能的 YUI3 等类库中同样存在。这不是类库的问题,更多是因为使用者的经验欠缺导致的。就如一把优秀的菜刀,到了一个拙劣的厨子手中,依旧切不好菜一样。工具很重要,但更重要的是我们得提升自己的刀工。
  6. 最后,回到第一点:jQuery 是 DOM 操作类库。非 DOM 操作,都是 jQuery 的辅助功能,不是 jQuery 的强项,就如菜刀不能当斧头用一样。

我们可以通过简单封装,让 jQuery 成为 CommonJS 的模块。这样,调用时只要 require 即可:

test.html:

2 <script>
3 seajs.use('./init');
4 </script>

 

init.js:

01 seajs.config({
02   alias: {
03     'juery': 'jquery/1.6.1/jquery'
04   }
05 });
06
07 define(function(require, exports, module) {
08   var $ = require('jquery');
09   // do something with jQuery
10 });

 

jQuery 插件的模块化

jQuery 提供了 DOM 操作功能,在实际应用中,我们还需要 cookie, template, storage 等等一系列功能。这时可以从 jQuery 社区中寻找各种插件来完成。大部分插件通过 jQuery 插件的模块化 一文中提供的方法封装就好。

之前的封装方法,总结成一句话是:“jQuery 穿肠过,插件身上留”。正如 Kidwind 反馈的一样,每次“穿肠过”的时候都要运行一次插件代码,频繁调用某些插件时,会存在 CPU 浪费,还可能带来隐患:

假设有以下jquery插件a, b, c, d,它们之间的关系如下
b 依赖于 a
c 依赖于 a
d 依赖于 b c

假设页面使用到d插件,那么插件a将进行两次初始化,也就是会调用两次
var $ = require(‘jquery’);
require(‘a’)($);
进行插件a的注册,当系统复杂时,重复的插件注册会不会影响系统的性能,同时会不会存在隐患?如插件b对引用的插件a进行了部分功能扩展,当引入插件c的时候又重新注册了插件a,那么插件b对插件a的扩展将不存在了,当然改写插件功能的实际情况也许不会存在,此处只是举个例子,说明隐患的存在。
如何避免重复的插件注册,可以避免隐患,同时获得更好的性能(避免了多次插件注册的运算耗时)。

面对这种情况,我们究竟应该如何做好 jQuery 插件的模块化?

jQuery 插件的形式

jQuery 插件一般可以总结为以下模板

01 (function($) { 
02   // Main plugin function
03   $.fn.PLUGIN = function(options) {
04     // snip...
05   };
06
07   // Public plugin function
08   $.fn.PLUGIN.FUNCT = function() {
09     // Cool JS action
10   };
11
12   // Default settings for the plugin
13   $.fn.PLUGIN.defaults = { /* snip... */ };
14
15   // Private function that is used within the plugin
16   // snip...
17 })(jQuery);

 

简言之就是往 $.fn 上添加新成员,有部分插件还会往 $ 上添加成员。

之前的“穿肠过”模块化方式,可以表示为:

1 define(function() { return function($) {
2   $.fn.PLUGIN = ...
3 }});

 

调用方式:

1 define(function(require, exports) {
2   var $ = require('jquery');
3   require('some-jquery-plugin')($);
4
5   $(sth).PLUGIN(...);
6 });

 

不是很直观,不够方便,还有前面提到的隐患。

深度模块化

为了更好的模块化,意味着我们要添加更多代码:

some-jquery-plugin.js:

01 define(function(require, exports, module) {
02   var $ = require('jquery').sub();
03
04   // Main plugin function
05   $.fn.PLUGIN = function(options) {
06     // snip...
07   };
08
09   // Public plugin function
10   $.fn.PLUGIN.FUNCT = function() {
11     // Cool JS action
12   };
13
14   // Default settings for the plugin
15   $.fn.PLUGIN.defaults = { /* snip... */ };
16
17   // Private function that is used within the plugin
18   // snip...
19
20   module.exports = $;
21 });

 

这样封装后,调用变成:

1 define(function(require, exports) {
2   var $ = require('jquery');
3   var PLUGIN = require('some-jquery-plugin');
4
5   PLUGIN(sth).PLUGIN(...);
6 });

 

这样能解决之前提到的重复初始化问题,但是 PLUGIN(sth).PLUGIN(...) 的使用方式怪怪的。比如这个非常帅的 chosen插件,按照上面的方式模块化后,调用方式为:

1 chosen('#some-id').chosen();

 

虽然可用,但怎么看怎么别扭。这是因为 jQuery 是以 DOM 为中心的,代码的默认流程是找到要操作的 DOM 元素,然后对其进行操作。这种代码书写方式,对于模块后的插件来说,很别扭。更好的期待中的调用方式是:

1 define(function(require, exports) {
2   var $ = require('jquery');
3   var Chosen = require('chosen');
4
5   var chosen = new Chosen(selector, options);
6   chosen.doSth(...);
7 });

 

理论上,我们甚至可以不知道 chosen 依赖 jQuery, 我们需要关心的只是 chosen 的 API. 上面这种理想的调用方式,需要我们对插件进行“深度”模块化:

some-jquery-plugin.js:

01 define(function(require, exports, module) {
02   var $ = require('jquery');
03
04   // Main plugin function
05   function PLUGIN(selector, options) {
06     var els = $(selector);
07     // snip...
08   };
09
10   // Public plugin function
11   PLUGIN.FUNCT = function() {
12     // Cool JS action
13   };
14
15   // Default settings for the plugin
16   PLUGIN.defaults = { /* snip... */ };
17
18   // Private function that is used within the plugin
19   // snip...
20
21   module.exports = PLUGIN;
22 });

 

也就是说,在 plugin 的代码里,我们并不对 $.fn 或 $ 进行扩展,只用 $ 来进行 DOM 操作而已,返回的是独立的 PLUGIN 对象,就和我们写普通的业务模块一样。这样,就实现预期中更优雅的调用方式。

jQuery 的插件机制,在模块化面前很鸡肋。jQuery 一直被冠以“不适合大型项目”,也和 jQuery 的这种插件机制有关系。这会导致大家都去污染 $.fn, 这就和污染全局变量一样。项目一大,冲突的概率,和调试的成本都会变大,很悲剧。

因此,推荐大家利用模块的机制去重构一部分好用的 jQuery 插件,目前 dew 项目里已经重新实现了 cookie 等部分模块。强烈推荐大家都参与进来,将自己喜欢的,常用的 jQuery 等插件迁移过来。或者推进插件作者直接修改源码,增加对 CommonJS 的支持。路漫漫,但众人拾柴火焰高,星火可燎原,期待大家的参与。

建议大家直接 fork dew 项目,可以将自己重构的模块 pull request 过来,邮件给 seajs(at)googlegroups.com 群组。讨论和 code review 后,就可以转成 dew 的正式模块。

等模块丰富起来,我们就可以有更多时间去做更意思的事情了。

转载来源:http://lifesinger.wordpress.com/2011/08/19/jquery-introduction-and-plugins-modulization/