标签:jquery

浏览模式: 标准 | 列表 | 图文
jQuery 1.3.3 新功能

jQuery 1.3.3 新功能

jQuery是目前我用的最多的JS框架,毕竟他简化了我很多JS的操作,而且目前它的插件也非常多。所以看到有更新就放上来。(当然不是我翻译的,以我的水平,翻译出来的文章会比英文原文更难懂)

原文:http://www.5iya.com/blog/post/jquery-1-3-3-new.asp

全部翻译自 Brandon Aaron 的blog。

增强的toggleClass()

1.toggleClass也可以和addClass一样,用空格分隔多个class名称了。

.toggleClass("a b") == .toggleClass("a").toggleClass("b")

2.无参数时,自动删除、恢复全部class,也可以传递一个布尔值,true为恢复class,false为删除class。

3.也可以第一个参数为class名,第二个参数为布尔值,具体用法如下。

// 原始代码
// <div class="a b c"></div>

// 删除、恢复全部class
$('div').toggleClass(); // <div class="" />
$('div').toggleClass(); // <div class="a b c" />
$('div').toggleClass( false ); // <div class="" />
$('div').toggleClass( true ); // <div class="a b c" />

// 删除、恢复多个 class
$('div').toggleClass( "a b" ); // <div class="c" />
$('div').toggleClass( "a c" ); // <div class="a" />
$('div').toggleClass( "a b c", false ); // <div class="" />
$('div').toggleClass( "a b c", true ); // <div class="a b c" />

简化的hover()

1.3.3中,hover绑定事件可仅传递一个函数,将默认用做mouseenter/mouseleave公用的函数。

旧代码:

$('li').hover(function() {
$(this).addClass('test');
}, function() {
$(this).removeClass('test');
});

新代码:

$('li').hover(function() {
$(this).toggleClass('test');
});

live冒泡事件支持预设参数

// 预设参数
var eventConfig = {
selectedClass: "selected"
};

$("li").live("click", eventConfig, function( event ) {
// 绑定函数的参数event的data属性即为传递的预设参数
var selectedClass = event.data.selectedClass;
});

更好的支持其它windows、document对象

通过.contents()获得其它框架的document对象。

var iframeDoc = $('iframe').contents().get(0);

这样就可以获取其height/width/CSS属性或绑定事件。

// 获得框架宽度
$(iframeDoc).width();

// 获得框架高度
$(iframeDoc).height();

// 绑定事件
$(iframeDoc).bind('click', function( event ) {
// do something
});

// 获得CSS属性值
$('div', iframeDoc).css('backgroundColor');

注意,如果要处理框架内部网页元素,请使用此插件(配合jQuery 1.3.3/+),和以下语法:

$('iframe').win().bind('load', fn);
$('iframe').doc().find('a').click(fn);

增强的index()

两个变化,第一个,支持传递selector作为参数。

旧代码:

$("img").index( $("img.selected") );

新代码

$("img").index( ".selected" );

第二个,无参数传递,直接查找在同级元素中的位置。

旧代码:

var $this = $(".selected");

$this.parent().children().index( $this );

新代码:

$(".selected").parent().index();

自行指定this对象

在1.3.3中,可以在bind/live绑定事件时,自行指定this参数代表的对象。这个用法需求不多,而且可用event.target,event.currentTarget代替。

具体用法请参看原文。

jQuery性能优化指南(3)

jQuery性能优化指南(3)

原文来自:https://docs.google.com/View?docID=dft4vhq9_23cnccgwc7&revision=_latest

8,尽量使用ID代替Class。

前面性能优化已经说过,ID选择器的速度是最快的。所以在HTML代码中,能使用ID的尽量使用ID来代替class。
看下面的一个例子:

// 创建一个list
var $myList = $('#myList');
var myListItems = '<ul>';
for (i = 0; i < 1000; i++) {
myListItems += '<li class="listItem' + i + '">This is a list item</li>'; //这里使用的是class
}
myListItems += '</ul>';
$myList.html(myListItems);
// 选择每一个 li
for (i = 0; i < 1000; i++) {
var selectedItem = $('.listItem' + i);
}

在代码最后,选择每个li的过程中,总共用了5066毫秒,超过5秒了。

接着我们做一个对比,用ID代替class:

// 创建一个list
var $myList = $('#myList');
var myListItems = '<ul>';
for (i = 0; i < 1000; i++) {
myListItems += '<li id="listItem' + i + '">This is a list item</li>'; //这里使用的是id
}
myListItems += '</ul>';
$myList.html(myListItems);
// 选择每一个 li
for (i = 0; i < 1000; i++) {
var selectedItem = $('#listItem' + i);
}
在上段代码中,选择每个li总共只用了61毫秒,相比class的方式,将近快了100倍。
9,给选择器一个上下文

jQuery选择器中有一个这样的选择器,它能指定上下文。
jQuery( expression, context );

通过它,能缩小选择器在DOM中搜索的范围,达到节省时间,提高效率。
普通方式:
$('.myDiv')
改进方式:
$('.myDiv' , $("#listItem") )

10,慎用 .live()方法(应该说尽量不要使用)

这是jQuery1.3.1版本之后增加的方法,这个方法的功能就是为 新增的DOM元素 动态绑定事件。
但对于效率来说,这个方法比较占用资源。所以请尽量不要使用它。
例如有这么一段代码:

<script type="text/javascript" >
$(function(){
$("p").click(function(){
alert( $(this).text() );
});
$("button").click(function(){
$("<p>this is second p</p>").appendTo("body");
});
})
</script>
<body>
<p>this is first p</p> <button>add</button>
</body>

运行后,你会发现 新增 的 p元素,并没用被绑定click事件。

你可以改成.live("click")方式解决此问题,代码如下:

$(function(){
$("p").live("click",function(){ //改成live方式
alert( $(this).text() );
});
$("button").click(function(){ $("<p>this is second p</p>").appendTo("body"); });
})

但我并不建议大家这么做,我想用另一种方式去解决这个问题,代码如下:

$(function(){
$("p").click(function(){
alert( $(this).text() );
});
$("button").click(function(){
$("<p>this is second p</p>").click(function(){ //为新增的元素重新绑定一次
alert( $(this).text() );
}).appendTo("body");
});
})

虽然我把绑定事件重新写了一次,代码多了点,但这种方式的效率明显高于live()方式,
特别是在频繁的DOM操作中,这点非常明显。


11,子选择器和后代选择器

后代选择器经常用到,比如:$("#list p");
后代选择器获取的是元素内部所有元素。

而有时候实际只要获取 子元素,那么就不应该使用后代选择器。
应该使用子选择器,代码如下:
$("#list > p");

12,使用data()方法存储临时变量

下面是一段非常简单的代码,

$(function(){
var flag = false;
$("button").click(function(){
if(flag){
$("p").text("true");
flag=false;
}else{
$("p").text("false");
flag=true;
}
});
})

改用data()方式后,代码如下:

$(function(){
$("button").click(function(){
if( $("p").data("flag") ){
$("p").text("true");
$("p").data("flag",false);
}else{
$("p").text("false");
$("p").data("flag",true);
}
});

})
jQuery性能优化指南(3)到此结束。
相信你也有你的idea,请共享出来吧。 Email : cssrain@gmail.com
jQuery性能优化指南(2)

jQuery性能优化指南(2)

原文来自:https://docs.google.com/View?docID=dft4vhq9_22g93szvdd&revision=_latest

4,对直接的DOM操作进行限制
这里的基本思想是在内存中建立你确实想要的东西,然后更新DOM 。
这并不是一个jQuery最佳实践,但必须进行有效的JavaScript操作 。直接的DOM操作速度很慢。

例如,你想动态的创建一组列表元素,千万不要这样做,如下所示:

var top_100_list = [...], // 假设这里是100个独一无二的字符串
$mylist = $("#mylist"); // jQuery 选择到 <ul> 元素
for (var i=0, l=top_100_list.length; i<l; i++){
$mylist.append("<li>" + top_100_list[i] + "</li>");
}

我们应该将整套元素字符串在插入进dom中之前先全部创建好,如下所示:

var top_100_list = [...],$mylist = $("#mylist"), top_100_li = ""; // 这个变量将用来存储我们的列表元素
for (var i=0, l=top_100_list.length; i<l; i++){
top_100_li += "<li>" + top_100_list[i] + "</li>";
}
$mylist.html(top_100_li);
注:记得以前还看过一朋友写过这样的代码:
for (i = 0; i < 1000; i++) {
var $myList = $('#myList');
$myList.append('This is list item ' + i);
}

呵呵,你应该已经看出问题所在了。既然把#mylist循环获取了1000次!!!

5,冒泡

除非在特殊情况下, 否则每一个js事件(例如:click, mouseover等.)都会冒泡到父级节点。
当我们需要给多个元素调用同个函数时这点会很有用。

代替这种效率很差的多元素事件监听的方法就是, 你只需向它们的父节点绑定一次。

比如, 我们要为一个拥有很多输入框的表单绑定这样的行为: 当输入框被选中时为它添加一个class

传统的做法是,直接选中input,然后绑定focus等,如下所示:

$("#entryform input").bind("focus", function(){
$(this).addClass("selected");
}).bind("blur", function(){
$(this).removeClass("selected");
});

当然上面代码能帮我们完成相应的任务,但如果你要寻求更高效的方法,请使用如下代码:

$("#entryform").bind("focus", function(e){
var $cell = $(e.target); // e.target 捕捉到触发的目标元素
$cell.addClass("selected");
}).bind("blur", function(e){
var $cell = $(e.target);
$cell.removeClass("selected");
});
通过在父级监听获取焦点和失去焦点的事件,对目标元素进行操作。
在上面代码中,父级元素扮演了一个调度员的角色, 它可以基于目标元素绑定事件。
如果你发现你给很多元素绑定了同一个事件监听, 那么现在的你肯定知道哪里做错了。
同理,在Table操作时,我们也可以使用这种方式加以改进代码:
普通的方式:
$('#myTable td').click(function(){
$(this).css('background', 'red');
});

改进方式:

$('#myTable').click(function(e) {
var $clicked = $(e.target);
$clicked.css('background', 'red');
});
假设有100个td,在使用普通的方式的时候,你绑定了100个事件。
在改进方式中,你只为一个元素绑定了1个事件,
至于是100个事件的效率高,还是1个事件的效率高,相信你也能自行分辨了。

6,推迟到 $(window).load

jQuery对于开发者来说有一个很诱人的东西, 可以把任何东西挂到$(document).ready下。
尽管$(document).rady 确实很有用, 它可以在页面渲染时,其它元素还没下载完成就执行。
如果你发现你的页面一直是载入中的状态,很有可能就是$(document).ready函数引起的。

你可以通过将jQuery函数绑定到$(window).load 事件的方法来减少页面载入时的cpu使用率。
它会在所有的html(包括<iframe>)被下载完成后执行。

$(window).load(function(){
// 页面完全载入后才初始化的jQuery函数.
});

一些特效的功能,例如拖放, 视觉特效和动画, 预载入隐藏图像等等,都是适合这种技术的场合。

7,压缩JavaScript
压缩和最小化你的JavaScript文件。
在线压缩地址: http://dean.edwards.name/packer/
压缩之前,请保证你的代码的规范性,否则可能失败,导致Js错误。
jQuery性能优化指南(2)到此结束,指南(3)正在进行中....
相信你也有你的idea,请共享出来吧。 Email : cssrain@gmail.com
jQuery性能优化指南(1)

jQuery性能优化指南(1)

原文来自:https://docs.google.com/View?docid=dft4vhq9_21hjb7j9fz&revision=_latest

1,总是从ID选择器开始继承

在jQuery中最快的选择器是ID选择器,因为它直接来自于JavaScript的getElementById()方法。

例如有一段HTML代码:

<div id="content">
<form method="post" action="#">
<h2>交通信号灯</h2>
<ul id="traffic_light">
<li><input type="radio" class="on" name="light" value="red" /> 红色</li>
<li><input type="radio" class="off" name="light" value="yellow" /> 黄色</li>
<li><input type="radio" class="off" name="light" value="green" /> 绿色</li>
</ul>
<input class="button" id="traffic_button" type="submit" value="Go" />
</form>
</div>

如果采用下面的选择器,那么效率是低效的。
var traffic_button = $("#content .button");

因为button已经有ID了,我们可以直接使用ID选择器。如下所示:
var traffic_button = $("#traffic_button");

当然 这只是对于单一的元素来讲。如果你需要选择多个元素,这必然会涉及到 DOM遍历和循环,
为了提高性能,建议从最近的ID开始继承。
如下所示:
var traffic_lights = $("#traffic_light input");


2,在class前使用tag(标签名)

在jQuery中第二快的选择器是tag(标签)选择器( 比如:$("head") )。
跟ID选择器累时,因为它来自原生的getElementsByTagName() 方法。

继续看刚才那段HTML代码:

<div id="content">
<form method="post" action="#">
<h2>交通信号灯</h2>
<ul id="traffic_light">
<li><input type="radio" class="on" name="light" value="red" /> 红色</li>
<li><input type="radio" class="off" name="light" value="yellow" /> 黄色</li>
<li><input type="radio" class="off" name="light" value="green" /> 绿色</li>
</ul>
<input class="button" id="traffic_button" type="submit" value="Go" />
</form>
</div>
比如需要选择 红绿 单选框,
那么可以使用一个tag name来限制(修饰)class ,如下所示:
var active_light = $("input.on");
当然也可以结合 就近的ID,如下所示:
var active_light = $("#traffic_light input.on");


在使用tag来修饰class的时候,我们需要注意以下几点:
(1) 不要使用tag来修饰ID,如下所示:
var content = $("div#content");
这样一来,选择器会先遍历所有的div元素,然后匹配#content。
(好像jQuery从1.3.1开始改变了选择器核心后,不存在这个问题了。暂时无法考证。)

(2)不要画蛇添足的使用ID来修饰ID,如下所示:
var traffic_light = $("#content #traffic_light");

注:如果使用属性选择器,也请尽量使用tag来修饰,如下所示:
$('p[row="c3221"]').html();而不是这样:$('[row="c3221"]').html();

3,将jQuery对象缓存起来

把jQuery对象缓存起来 就是要告诉我们 要养成将jQuery对象缓存进变量的习惯。
下面是一个jQuery新手写的一段代码:

$("#traffic_light input.on").bind("click", function(){ ... });
$("#traffic_light input.on").css("border", "1px dashed yellow");
$("#traffic_light input.on").css("background-color", "orange");
$("#traffic_light input.on").fadeIn("slow");

但切记不要这么做。

我们应该先将对象缓存进一个变量然后再操作,如下所示:

var $active_light = $("#traffic_light input.on");
$active_light.bind("click", function(){ ... });
$active_light.css("border", "1px dashed yellow");
$active_light.css("background-color", "orange");
$active_light.fadeIn("slow");

记住,永远不要让相同的选择器在你的代码里出现多次.

注:(1)为了区分普通的JavaScript对象和jQuery对象,可以在变量首字母前加上 $ 符号。
(2)上面代码可以使用jQuery的链式操作加以改善。如下所示:

var $active_light = $("#traffic_light input.on");
$active_light.bind("click", function(){ ... })
.css("border", "1px dashed yellow")
.css("background-color", "orange")
.fadeIn("slow");

如果你打算在其他函数中使用jQuery对象,那么你必须把它们缓存到全局环境中。
如下代码所示:

// 在全局范围定义一个对象 (例如: window对象)
window.$my = {
head : $("head"),
traffic_light : $("#traffic_light"),
traffic_button : $("#traffic_button")
};
function do_something(){
// 现在你可以引用存储的结果并操作它们
var script = document.createElement("script");
$my.head.append(script);
// 当你在函数内部操作是, 可以继续将查询存入全局对象中去.
$my.cool_results = $("#some_ul li");
$my.other_results = $("#some_table td");
// 将全局函数作为一个普通的jquery对象去使用.
$my.other_results.css("border-color", "red");
$my.traffic_light.css("border-color", "green");
}

//你也可以在其他函数中 使用它

jQuery性能优化指南(1)到此结束,请查看指南(2)。

扩展JQuery Ajax请求错误机制

扩展JQuery Ajax请求错误机制

如何对ajax的错误进行更好的处理?本文给出了一个简单的解决方案。想当于类的扩展和继承一样。有新意,一直以来,对于框架我们要么是扩展,要么是写新方法,就从来没有想过要继承这些方法。所以,作者这个给了我很多启发。

原文:http://www.cnblogs.com/lyk831216/archive/2009/04/24/1442791.html

JQuery使我们在开发Ajax应用程序的时候提高了效率,减少了许多兼容性问题,但时间久了,也让我们离不开他。比如简单的Jquery Ajax请求的封装让我们忘却了最原始的XmlHttpRequest对象和他的属性,方法,也让我们远离事情的真相。

在Ajax项目中,经常遇到需要服务器端返回错误的消息提示,或者消息码之类的数据。查过一些帮助,解决方案,很多网站是返回错误的消息JSON数据或者 脚本,这种方式当我们用JQuery.ajax()的时候出现了问题,jquery.ajax()回调函数success(data)的data参数可能 是 xmlDoc, jsonObj, html, text, 等等...这取决于我们dataType设置和MIME.很多时候我们的错误处理都是统一的处理,不管你请求的是XML,JSON...。不光不好统一, 还容易出现解析错误等等情况。

参考了Prototyp框架的做法,做了一个Jquery的错误扩展。

原理:Prototype思路是把服务器处理结果状态信息写在Header里面,这种方式既保证了reponse body的干净,同时适应XML,JSON,HTML,Text的返回情况。

   服务器端只需要 Response.AddHeader("Error-Json", "{code:2001,msg:'User settings is null!',script:''}");

实现:为了不影响原有的Jquery.ajax方法,同时不破坏jquery库源文件,做了如下扩展,代码很简单都能看懂:

;(function($){
var ajax=$.ajax;
$.ajax=function(s){
var old=s.error;
var errHeader=s.errorHeader||"Error-Json";
s.error=function(xhr,status,err){
var errMsg = window["eval"]("(" + xhr.getResponseHeader(errHeader) + ")");
old(xhr,status,errMsg||err);
}
ajax(s);
}

})(jQuery);

使用方法:

  服务器端:我们是对错误进行扩展,如果要让jquery.ajax破获[膘叔:应该为捕获]错误,必须要服务器端返回非200的错误码,由于Opera浏览器下面对 400以上的错误码,都无法获得请求的Header,建议如果要支持Opera,最好返回30*错误,这是Opera能接受Header的错误范围。没有 做包装,可以再单独把Catch内容出来。

try {
context.Response.Write(GetJson(context));
throw new Exception("msg");
}
catch {
context.Response.ClearContent();
context.Response.StatusCode = 300;
context.Response.AddHeader("Error-Json", "{code:2001,msg:'User settings is null!',script:''}");
context.Response.End();
}

 客户端:

$.ajax({
url: this.ajaxUrl,
type: "POST",
success: callback,
error: function(xhr,status,errMsg){
alert(errMsg.code+"<br/>"+errMsg.msg);
}
});

也许不是最好的,但觉得用起来很方便,忘了个写新增参数errorHeader:"Error-Json",这个header头key根据你后台设定配置。

jQuery简单开发

jQuery简单开发

jQuery这种轻量级的框架大家使用的都比较多,1.3后效率据说又上升了不少,因此,开发基于jQuery的插件也就显得那么理所当然了。
一般来说,jQuery有两种插件模式,一种是:$.extends({}) ,另一种是:$.fn.extends({})
个人理解:前一种是属于全局性的调用,后一种是针对某个元件的绑定调用。这当然是简单的理解。但事实上,也基本上就是这么做的。

官方的例子也比较简单:

$.extend({
max: function(a, b) {
return a > b ? a : b;
},
min: function(a, b) {
return a > b ? b : a;
},
avg: function(a, b) {
return a / b;
}
});

看上去是不是容易?然后就可以直接调用了。 $.min(2,3) 返回2
一般情况下,为了在扩展中使用$,却又担心的页面使用了jQuery.noConflict()而取消了$指向jQuery的引用,则需要这样写

( function($){
$.fn.extend({
//....code in here
});
})(jQuery);

这样写不仅能够将$显式指向jQuery,而且将产生的变量封在function的作用范围内,不会污染window全局。
而基于$.fn.extends({})的扩展又如何开发呢?

在这里我引用Roby的译文:http://www.robysky.com/archives/171
英文原文:http://www.learningjquery.com/2007/10/a-plugin-development-pattern

我认为以下插件开发模式是必须应该掌握的:
1.在JQuery命名空间内声明一个特定的命名;
2.接收参数来控制插件的行为;
3.提供公有方法访问插件的配置项值;
4.提供公有方法来访问插件中其他的方法(如果可能的话);
5.保证私有方法是私有的;
6.支持元数据插件;

下面,我将逐一讲述上面的内容,并在同时给出相关的简单插件开发代码。
1.在JQuery命名空间内声明一个特定的命名

这意味着开发的是一个单一命名的插件脚本,如果你的脚本包含多个插件或者有补充性质的插件,比如$.fn.doSomething() 和$.fn.undoSomething(),那你得声明多个命名了。但是总体来说,当开发一个插件时,我们应该努力做到用一个单一的命名来搞定整个插件。

在例子中,我们将声明一个名为“hilight”的插件。

$.fn.hilight = function() {
// Our plugin implementation code goes here.
};

我们可以这样调用:
$(’#myDiv’).hilight();
但是假如我们需要打破这种单一的命名和调用方式呢?有很多理由支持我们这么做:设计上的需要;更加简单和可读的配置;而且那样将更加符合OO的要求。

在没有给命名空间来到麻烦的前提下,将插件的部署打破成为多个函数的形式将是十分繁琐的。我们通过认识并利用JavaScript中 functions是最高层的对象,和其他对象一样,functions可以被赋予属性,前面我们已经将hilight命名声明在了JQuery的原型对象上,那么,其实,其他的我们想扩展的属性或对象都能够在hilight上进行声明。稍后将详细讲述此点。
2.接收参数来控制插件的行为;

来为我们的hilight插件添加指定前景和背景色的功能,我们需要在函数中允许一个object类型的选项设置。如下所展示的那样:

$.fn.hilight = function(options) {
var defaults = {
foreground: 'red',
background: 'yellow'
};
// Extend our default options with those provided.
var opts = $.extend(defaults, options);
// Our plugin implementation code goes here.
};

现在,我们的插件可以这样来调用:

$(’#myDiv’).hilight({
foreground: ‘blue’
});
3.提供公有方法访问插件的配置项值;

上面的代码我们可以做一下改进,使得插件的默认值可以在插件之外被设置。这无疑是十分重要的,因为它使得插件用户可以使用最少的代码来修改插件配置,这其实是我们利用函数对象的开始。

// plugin definition
$.fn.hilight = function(options) {
// Extend our default options with those provided.
// Note that the first arg 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'
};

4.提供公有方法来访问插件中其他的方法(如果可能的话)

这里要讲的方法和前面的讲解一脉相承,用此方法来扩展你的插件(而且能够让其他人进行扩展)是件很有意思的事情。例如,在扩展hilight插件时,我们可以定义一个format方法用来格式化高亮显示的文本,原来的hilight插件和扩展了format方法的插件代码如下:

$.fn.hilight = function(options) {
// iterate and reformat each matched element
return this.each(function() {
var $this = $(this);
...
var markup = $this.html();
// call our format function
markup = $.fn.hilight.format(markup);
$this.html(markup);
});
};

// define our format function
$.fn.hilight.format = function(txt) {'
return '<strong>' + txt + '</strong>';
};

如前面所述,我们已经很容易的通过设置options对象的属性来允许一个回调函数来覆写默认的格式设置。在这里有另外一个非常棒的方法来个性化你的插件,上面展示的方法实际上就是通过暴露format方法,使其可以被重新定义。这种做法使得其他人可以采用他们自己的习惯和方式来重写你的插件,这意味着他们可以为你的插件写额外的扩展插件。
仔细考量一下前面我们用到的插件例子程序,你可能会想“我们究竟应该在什么时候使用这种插件方式来实现需求”的问题。一个来自现实应用中的插件便是“ Cycle Plugin”,它是一个支持多种滑动显示特效的插件,特效包括滚动、滑动和渐变等等。但是,实际上,并没有办法来定义每一个可能会用在滑动变幻上的特效。这就是这种扩展方式的有用之处。“ Cycle Plugin”插件暴露了”transitions”对象,这使得用户只需要按照如下方式便可以添加自己的变幻定义:
$.fn.cycle.transitions = {
…
};
这种技巧使得用户可以定义或者采用自己习惯的方式来扩展“ Cycle Plugin”。
5.保证私有方法是私有的;

上面提到的暴露插件中的公有方法的技巧使得插件能够被覆写,这将使插件变得十分灵活而强大,但至于哪一部分,那些属性和方法应该被暴露出来,你得小心了。一旦使其能够被外界访问到,你就得注意到任何调用参数和语义化的变动都可能使其丧失向前的兼容性。作为一般准则,如果不确定是否应该暴露某个属性或对象的话,那就最好别那样做。
那么我们应该怎样来定义多个方法而不至于使命名空间混乱并且保证不被暴露再外呢?这就是闭包的工作,为了便于演示,我们给插件加入了一个叫做 “debug”的功能,它用来记录firebug控制台所选择的网页元素数目。为了创建一个闭包,我们将整个功能的定义放入在一个function中了(有关这方面的知识,可参见JQuery手册)。

// 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.size());
};
...
// end of closure
})(jQuery);

debug方法在这里是无法被在插件以外访问到的,因此,我们称之为它是插件私有的。
6.支持元数据插件;

根据你所写的插件的类型,为你的插件加入元数据插件的支持将使其变得更强大。就我个人来说,喜欢采用元数据插件的重要原因便是它可以让你使用定义之外的标签来覆写你的插件属性设置(这在创建demo和例子时十分有用),而且支持它十分的简单。
更新:这部分内容可以在本文的评论中展开讨论(既然有争议的话)

// plugin definition
$.fn.hilight = function(options) {
...
// build main options before element iteration
var opts = $.extend({}, $.fn.hilight.defaults, options);
return this.each(function() {
var $this = $(this);
// build element specific options
var o = $.meta ? $.extend({}, opts, $this.data()) : opts;
...

改动部分的代码会做如下的事情:
*测试metadata插件是否可用
*如果可以,将用metadata扩展options对象
这被加入到jQuery.extend,作为其最后一个参数,所以它可以覆写任何其他参数设置。现在我们可以通过下面的方式控制其行为:

<!-- markup -->
<div class="hilight { background: 'red', foreground: 'white' }">Have a nice day!</div>
<div class="hilight { foreground: 'orange' }">Have a nice day!</div>
<div class="hilight { background: 'green' }">Have a nice day!</div>

而在调用方面,我们通过一行简单的代码就可以实现预期的效果:
$(’.hilight’).hilight();

将上面所述内容涉及到的代码放在一起,完整的例子程序代码如下:

//
// create closure
//
(function($) {
//
// plugin definition
//
$.fn.hilight = function(options) {
debug(this);
// build main options before element iteration
var opts = $.extend({}, $.fn.hilight.defaults, options);
// iterate and reformat each matched element
return this.each(function() {
$this = $(this);
// build element specific options
var o = $.meta ? $.extend({}, opts, $this.data()) : opts;
// update element styles
$this.css({
backgroundColor: o.background,
color: o.foreground
});
var markup = $this.html();
// call our format function
markup = $.fn.hilight.format(markup);
$this.html(markup);
});
};
//
// private function for debugging
//
function debug($obj) {
if (window.console && window.console.log)
window.console.log('hilight selection count: ' + $obj.size());
};
//
// define and expose our format function
//
$.fn.hilight.format = function(txt) {
return '<strong>' + txt + '</strong>';
};
//
// plugin defaults
//
$.fn.hilight.defaults = {
foreground: 'red',
background: 'yellow'
};
//
// end of closure
//
})(jQuery);

看完以上的内容,你是不是对jQuery的插件开发加深了一定的了解了呢?
顺便提一下,yhustc在自己的博客上写了一个基于jQuery的软键盘插件,你是不是又可以根据上面的教程来写一个基于$.fn.extends的扩展呢?让yhustc的插件可以绑定在某个元件上?

基于JQUERY制作的仿GOOGLE自动完成插件

基于JQUERY制作的仿GOOGLE自动完成插件

本例子来自博客园,其实关于Autocompleted的例子,用jquery的话,是很多很多,但那都是国外的,难得有国内的例子,看到了就复制回来一份,呵呵

原文:http://www.cnblogs.com/cntlis/archive/2009/03/14/1412144.html

数据采用JSON,格式为{keylist:[{'keyname':关键字1,'keyextend':扩展文字(譬如说结果数目)},{'keyname':关键字2,'keyextend':扩展文字(譬如说结果数目)}]}

/**//*
* jQuery AutoComplete
*
* Author: cntlis
* http://blog.csdn.net/cntlis
*
* Licensed like jQuery, see http://docs.jquery.com/License
*
* 作者:cntlis
* QQ:8112857
*/
$.fn.AutoComplete = function(url,option){
var me= this;
var strKey= $(me).val();
var strKeyBak= "";
var isShow = false;
var doption={
iwidth: '0px', //下拉框的宽度
iLengthLower: 1, //当表单的长度大于iLengthLower小于iLengthUpper时才开始执行搜索
iLengthUpper: 50,
strPara: "Keyword", //变量名称
zIndex: 1, //提示框的Z-INDEX值
hasscroll: 0, //是否出现滚动条0无1有
hasclose: 1, //是否拥有关闭窗口
desfun:function(){}
};

$.extend(doption,option);
var iLengthLower= doption.iLengthLower;
var iLengthUpper= doption.iLengthUpper;
var strPara= doption.strPara;
if ($("#autocomplete").length<1){$("body").append("<div id='autocomplete' class='autocompletefloor'></div>");}
$("#autocomplete").hide();

$(me).keyup(function(e){keysearch(e.keyCode);});
$(me).keydown(function(e){LineSelect(e.keyCode);});
$(me).bind("blur",function(){
strKeyBak= $("#autocomplete ul .selected .keyname").text(); //为click事件增加处理
if (strKeyBak.length>0 && strKeyBak!=$(me).val()){
$(me).val(strKeyBak);
doption.desfun();
};
floorHide();
});

var encode=function(v){//如果包含中文就escape,避免重复escape)
return escape(v).replace(/\+/g, '%2B').replace(/\"/g,'%22').replace(/\'/g, '%27').replace(/\//g,'%2F');
}

function floorHide(){
$("#autocomplete").hide().html("");
strKey= "";
isShow = false;
}

function floorShow(){
var p= $(me).offset();
var w= (doption.iwidth == "0px") ? $(me).width()+2 : doption.iwidth;
$("#autocomplete").css({
'z-index:':doption.zIndex,
width:w,
top:parseInt(p.top+$(me).outerHeight())+"px",
left:parseInt(p.left)+"px"
}).show();
strKey= "";
isShow = true;
}

function keysearch(code){
var strKeyNow=$(me).val();
if(code == 38 || code == 40 || code == 13 || code == 27 || code == 9) return; //TAB/回车、ESC、向上、向下
if((strKey == "" || strKeyNow != strKey) && strKeyNow.length >= iLengthLower && strKeyNow.length <= iLengthUpper){
$.ajax({
type: "Get",
dataType: "json",
url: url,
data: strPara != "" ? strPara + "=" + encode(strKeyNow) : "",
success: function(json){
jsonjson=json.keylist;
if (json.length>0){
//获取搜索数据
var strContent= "<ul>";
$.each(json, function(i, n){
if(n.keyname.length>0){ //如果
//alert(n.keyname);
strContent+= '<li class="keyinfo"><span class="keyname">'+n.keyname+'</span>';
try{
if (n.keyextend.length>0){strContent+='<span class="keyextend">'+n.keyextend+'</span>';}
}catch(E){};
strContent+= '</li>';
};
});
if (doption.hasclose==1){
strContent+= '<li class="close"><span>关闭</span></li>';
}
strContent+='</ul>';
$("#autocomplete").html(strContent);
$("#autocomplete .keyinfo").mouseover(function(){$("#autocomplete .selected").removeClass("selected");$(this).removeClass("unselected").addClass("selected");}).mouseout(function(){$(this).removeClass("selected").addClass("unselected");}).click(function(){if(strKeyBak.length()>0){$(me).val(strKeyBak);}});
floorShow();
}else{
//没有搜索数据
floorHide();
return;
}
}
});
strKey=$(me).val();
}
if(strKey.length == 0 || strKey.length <= iLengthLower || strKey.length >= iLengthUpper) floorHide();
}

function LineSelect(code){
if(code == 27){floorHide();};//回车键、ESC键
if(code == 13){floorHide();doption.desfun();};
if(!isShow) return;
ObjSelected=$("#autocomplete ul .selected");
if (ObjSelected.length>0){ //如果已经有选定
//alert('dasfdas');
if(code == 38){ //向上键
if(ObjSelected.prev().text() != ""){ //如果不是第一个数据
ObjSelected.removeClass("selected").addClass("unselected").prev().removeClass("unselected").addClass("selected");
$(me).val($("#autocomplete ul .selected .keyname").text());
}else{
ObjSelected.removeClass("selected").addClass("unselected");
$("#autocomplete .keyinfo:last").removeClass("unselected").addClass("selected");
$(me).val($("#autocomplete ul .selected .keyname").text());
}
}else if (code == 40){ //向下键
if(ObjSelected.next().text() != ""){ //如果不是第一个数据
ObjSelected.removeClass("selected").addClass("unselected").next().removeClass("unselected").addClass("selected");
$(me).val($("#autocomplete ul .selected .keyname").text());
}else{
ObjSelected.removeClass("selected").addClass("unselected");
$("#autocomplete .keyinfo:first").removeClass("unselected").addClass("selected");
$(me).val($("#autocomplete ul .selected .keyname").text());
}
}
}else if(code == 38){
$("#autocomplete .keyinfo:last").removeClass("unselected").addClass("selected");
$(me).val($("#autocomplete .keyinfo:last .keyname").text());
}else if(code == 40){
$("#autocomplete .keyinfo:first").removeClass("unselected").addClass("selected");
$(me).val($("#autocomplete .keyinfo:first .keyname").text());
}
}
}
#autocomplete{}{ border: 1px solid #000; position: absolute; }
/**//*每行的格式*/
#autocomplete li{}{ display: block; text-align: left; height: 20px; line-height: 20px; background-color: #fff; cursor: default; padding: 0 5px; clear: both; }
/**//*鼠标选中时的格式*/
#autocomplete .selected{}{ background-color: #565da9; color: #fff; overflow: hidden; }
/**//*鼠标离开时代格式*/
#autocomplete .unselected{}{ background-color: #fff; color: #666; }
/**//*关键字信息*/
#autocomplete .keyname{}{ display: block; float: left; }
/**//*关键字扩展信息*/
#autocomplete .keyextend{}{ display: block; float: right; color: green; }
#autocomplete .unselected .keyextend{}{ color: green; }
#autocomplete .selected .keyextend{}{ color: #fff; }
/**//*关闭*/
#autocomplete .close{}{ text-align: right; }
#autocomplete .close span{}{ color: blue; cursor: pointer; text-decoration: underline; }

调用范例

$("#Keyword").AutoComplete("search.asp");


是不是很简单的?只是search.asp返回的数据要是上面所提供的格式,对于PHP来说就太方便了,只要生成相应的数组,然后json_encode一下就全出来了,呵呵

jQuery UI 1.7 发布

jQuery UI 1.7 发布

继jQuery 1.3.1发布之后,UI包一直没跟上,3月6日,兼容jQuery 1.3.1的UI包终于发布了。大家可以来这里下载jquery-ui-1.7.custom.zip,svn方式:http://jquery-ui.googlecode.com/svn/tags/1.7/

这次改动主要如下:

  • 和jQuery1.3兼容。
  • 修补和优化以前的UI插件。
  • 崭新的CSS框架。
    jQuery UI 1.7建立在一个崭新的强大的css框架上,这个框架不仅仅用于jQuery UI的插件,还可以用于定制插件,任何开发者都能很容易地基于ThemeRoller(jQuery UI 的换肤插件)为插件创建皮肤。更多关于CSS框架
  • 新版的ThemeRoller(V2)。
  • 健全的演示和文档。
  • 完全离线的帮助文档。
  • 重构了download builder,即使javascript被禁用,这个插件仍然能运作。
  • 皮肤打包。
    点击这里可以立即下载所有皮肤: jquery-ui-themes-1.7.zip,svn: http://jquery-ui.googlecode.com/svn/tags/1.7/themes/
  • 为jQuery UI新建了一个网站http://www.jqueryui.com/。
    这个网站和主站分开,专注于UI研发。


-----------------

  • 出处:http://kaima.cnblogs.com
  • 作者:kai.ma
jQuery插件——文章自动生成导航

jQuery插件——文章自动生成导航

这个插件很实用,适合那种写着教程内容的页面,以前如果有多个标题的话,必须一个一个的加锚点,然后再加链接,这样不太方便。所以看到这个插件的时候,我忍不住记录下来。

代码我没有细看,我只看了demo,自己觉得还是很有用的。
代码来自CSSRain.cn,图片同样来自他那里。
网站说:

首先根据文章 自动在 右上角生成 导航菜单,
然后导航菜单可以 跟随 滚动条滚动 ,实时导航。
导航采用平滑方式,更人性化。

演示:
http://cssrain.cn/demo/createTitle/title.html

下载:
http://cssrain.cn/demo/createTitle/createTitle.rar

有问题 请留言, 只测试了 google 和 firefox 。

不过,IE或者其他的一些多窗口版的浏览器,会不会把它当成AD层屏蔽掉呢?
截图:
4b904d256102f55f2aa808736b6a6a8b
源码分流:
0aaf23c65f132be5afed04d6df108908

JS/CSS/images lazyLoader for JQuery

JS/CSS/images lazyLoader for JQuery

在jQuery的插件库里面,有一个imageLazyLoader,是专门用来进行延迟加载图片的。这次看到这个对于JS,CSS,IMAGE三者都能进行延迟加载的代码,当然是用来查看一下的。代码很小,大约只有3K左右,100多行代码,却实现了这么多的效果,看来jQuery的功能是被挖掘的越来越多了。

/*
* xLazyLoader 1.0 - Plugin for jQuery
* Load js, css and images
* Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
* and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
* Depends:
* jquery.js
* Copyright (c) 2008 Oleg Slobodskoi (jimdo.com)
*/
;(function($){
$.xLazyLoader = function ( method, options ) {
if (typeof method == 'object') {
options = method;
method = 'load';
};
xLazyLoader[method]( options );
};

var xLazyLoader = new function ()
{
var head = document.getElementsByTagName("head")[0];
this.load = function ( options )
{
//Defaults
var d = {
js: [],
css: [],
image: [],
name: null,
load: function(){}
};
$.extend(d, options);

var self = this,
ready = false,
loaded = {
js: [],
css: [],
image: []
}
;

each('js', d.js);
each('css', d.css);
each('image', d.image);

function each (type, urls)
{
if ( $.isArray(urls) && urls.length>0 )
$.each( urls, function(i, url){
load(type, url);
});
else if (typeof urls == 'string')
load(type, urls);
};
function load (type, url)
{
self[type](url, function() {
$.isArray(d[type]) ? loaded[type].push(url) : loaded[type] = url;
d.js.length == loaded.js.length
&& d.css.length == loaded.css.length
&& d.image.length == loaded.image.length
&& d.load.apply(loaded, []);
return;
}, d.name ?'lazy-loaded-'+ d.name : 'lazy-loaded-'+new Date().getTime());
};
};

this.js = function (src, callback, name)
{
if ($('script[src*="'+src+'"]').length>0) {
callback();
return;
};
var script = document.createElement('script');
script.setAttribute("type","text/javascript");
script.setAttribute("src", src);
script.setAttribute('id', name);
if ($.browser.msie)
script.onreadystatechange = function () {
/loaded|complete/.test(script.readyState) && callback();
}
else
//FF, Safari, Opera
script.onload = callback;
head.appendChild(script);
};

this.css = function (href, callback, name)
{
if ($('link[href*="'+href+'"]').length>0) {
callback();
return;
};

var link = $('<link rel="stylesheet" type="text/css" media="all" href="'+href+'" id="'+name+'"></link>')[0];
if ($.browser.msie)
link.onreadystatechange = function () {
/loaded|complete/.test(link.readyState) && callback();
}
else if ($.browser.opera)
link.onload = callback;
else
//FF, Safari, Chrome
(function(){
try {
link.sheet.cssRule;
} catch(e){
setTimeout(arguments.callee, 20);
return;
};
callback();
})();
head.appendChild(link);
};

this.image = function (src, callback)
{
var img = new Image();
img.onload = callback;
img.src = src;
};

this.disable = function ( name )
{
$('#lazy-loaded-'+name, head).attr('disabled', 'disabled');
};
this.enable = function ( name )
{
$('#lazy-loaded-'+name, head).removeAttr('disabled');
};

this.destroy = function ( name )
{
$('#lazy-loaded-'+name, head).remove();
};
};
})(jQuery);
使用方法也很方便 :

Example 1:

Load some files

 $.xLazyLoader({
js
: 'jquery.ui.all.js',
css
: 'ui.allplugins.css',
image
: 'your_image.jpg',
load
: function(){
alert
('All files are loaded');
}
});

Example 2:

Load multiple files of each type

 $.xLazyLoader({
js
: ['ui.core.js','ui.dialog.js'],
css
: ['ui.core.css', 'ui.dialog.css'],
image
: ['your_image.jpg', 'your_image1.jpg', 'your_image2.jpg'],
name
: 'dialog',
load
: function(){
alert
('All files are loaded');
}
});

Example 3:

Remove tags from head (javascript is still working, but css is completely destroyed )

 $.xLazyLoader('destroy','dialog');

Example 4:

Disable css.

 $.xLazyLoader('disable','dialog');

Enable css.

 $.xLazyLoader('enable','dialog');

项目存在于GOOGLECODE上,网址为:http://code.google.com/p/ajaxsoft/
估计还是会有BUG,不过相信作者应该会更新的