A post from iPhone

测试用iphone发个帖子,
后台的richtext editor不能用,
wordpress的网页显示还可以,
form表单输入也没什么问题,
bug也有使用ajax取数据的地方有时候不响应,
滚动条显示不出来,safari挂过一次!
iphone输入法的联想和搜狗比则显得功能不够强劲
有空再写个iphone的使用感受!

炫酷CSS超链接按钮一

上一篇文章提到用CSS分割图片的技巧,例子中也展示了一个很漂亮的CSS按钮,今天在tutorialzine看到这篇教程 Sweet AJAX Tabs With jQuery 1.4 & CSS3的按钮也很漂亮,把demo代码下载下来之后,看了一下也是用CSS定位分割图片的技巧做出来的,和上一篇文章中按钮实现略有不同,下面就来解析怎么做出如下的效果:







首先按钮的HTML代码,

<a class="green" href="#">Tab two <span class="left"></span><span class="right"></span></a>

这个按钮的图片由左中右三部分构成,两边的图片是做好了边框效果的,中间的图片可以无限扩展。即下图显示的效果(注:图像来源于tutorialzine原教程)

源图像是这样的,其实还分成了亮度有区别的上下两部分,使用上文中已经介绍过的CSS技巧达到鼠标移上去高亮的效果。
->->->

让我们来看看实现一个按钮核心的CSS代码:

a.blue{background:url(img/blue_mid.png) repeat-x top center; color:#03426e;}
a.blue span.left{ background:url(img/blue_left.png) no-repeat left top;}
a.blue span.right{ background:url(img/blue_right.png) no-repeat right top;}

然后是定义按钮size、边框、边距等的CSS代码:

a,a:visited{
	/* Styling the hyperlinks of the tabs as colorful buttons */
	float:left;
	font-size:18px;
	/* display:block allows for additinal CSS rules to take effect, such as paddings: */
	display:block;
	padding:7px 16px 1px;
	margin:4px 5px;
	height:29px;
	/* Giving positioning */
	position:relative;
	/* CSS3 text-shadow */
	text-shadow:1px 1px 1px #CCCCCC;
}
.left{
	/* The left span in the hyperlink */
	height:37px;
	left:0;
	position:absolute;
	top:0;
	width:10px;
}
.right{
	/* The right span in the hyperlink */
	height:37px;
	right:0;
	position:absolute;
	top:0;
	width:10px;
}

CSS分割背景图片的技巧


因为我也不是CSS高手,所以本文的目的是写清楚如何弄明白CSS中分割图片的技巧,说到分割其实并不是真正意义上的剪裁图片,只是已经流行多年了的一种CSS best practise,用一个拼接起来的大的图片资源替代加载多个小图片的一种方法,优点是节约页面的加载速度,不会出现有的图片能显示有的还在加载的情况,这个效果或者性能用firebug可以测试出来。

当然用这个技巧也要选对地方用才行,要是经常需要改动的图像用这个技术还是有点折腾的。

核心的属性是这个:background-position 参数值从w3schools找出来的

Property Values

Value Description
top left
top center
top right
center left
center center
center right
bottom left
bottom center
bottom right
If you only specify one keyword, the second value will be “center”. Default value is: 0% 0%
x% y% The first value is the horizontal position and the second value is the vertical. The top left corner is 0% 0%. The right bottom corner is 100% 100%. If you only specify one value, the other value will be 50%.
xpos ypos The first value is the horizontal position and the second value is the vertical. The top left corner is 0 0. Units can be pixels (0px 0px) or any other CSS units. If you only specify one value, the other value will be 50%. You can mix % and positions
inherit Specifies that the setting of the background-position property should be inherited from the parent element

这里有篇不错的文章描述的是下面这个例子,将原图竖着的1234显示成横着的4个盒子
CSS: Using Percentages in Background-Image


.box1
.box2
.box3
.box4

下面这个例子也是常用到的:
鼠标移到按钮上,用稍微亮一点点的图片显示的悬停效果。
用到的green.png原图: green.png
按钮的代码:

<a class="green" href="#">Green<span> </span></a>

按钮的CSS:

a {
	/* The section titles */
	display:block;
	font-size:21px;
	height:34px;
	overflow:hidden;
	padding:10px 20px 0;
	position:relative;
	width:200px;
}
a {
	text-decoration: none;
}
a:hover{
	/* Removing the inherited underline from the titles */
	text-decoration:none;
}
a span{
	/* This span acts as the right part of the section's background */
	height:44px;
	position:absolute;
	right:0;
	top:0;
	width:4px;
	display:block;
}
a.green{background:url(img/green.png) repeat-x top left; color:#436800;}
a.green span{ background:url(img/green.png) repeat-x top right;}
/* The hover effects */
a:hover{ background-position:bottom left;}

最重要的一行,鼠标移上去的时候设置图像的位置为bottom left,而下半部分的图像比上半部分亮一点。
效果如下:

最后一个按钮样式和第一个其实是一样的,只不过最后是从sprite.png加载过来的,我使用了CSS 图片拼合生成器将四张图拼接起来了,然后再用CSS去定位。
拼接完成之后的图:sprite.png

使用AJAX集成Gravatar头像到自己的评论系统

无图无真相,点击下图可以去测试页面查看源码

Gravatar头像这玩意基本上凡事用wordpress的博客的用户都用笔墨介绍过,所以我就不废话了,不知道的自己google一下。

集成Gravatar头像的核心是构造一个图像的URL地址,Gravatar的最简单的头像URL地址是这样生成的

1. 用MD5Hash算法加密你的邮箱地址

2. 头像 URL= http://www.gravatar.com/avatar/+第一步加密后的值

当然Gravatar还提供了几个有意思的参数,如?d=monsterid加上这个参数,如果邮箱地址未在Gravatar注册过,则动态生成一个小怪兽的头像(例子:左图的右下头像)

JavaScript的MD5Hash所幸也有人早就写过了,到这里下载一个。

现在我们需要关心的就是页面怎么写了,左图的评论表单是从wordpress里抠出来的,CSS我不是高手,简单的弄了下不至于太难看。

AJAX的标题有点噱头啦,但是在这个例子的基础上做成AJAX评论也只剩下一小步了。

其实测试页面值得一提的代码是这一段,用户输入完email地址之后,这个输入框失去焦点,这个时候我们动态加载其头像,这样一来用户体验能够得到明显提升,不要看是个小小的功能,有时候就是这些细节才抓住了你的目标客户。

//jQuery的blur事件
("#email").blur(function(event){
//清空上一个头像
$("#ajaxgravatar").html('');
$email = $.trim($("#email").val()).toLowerCase();
//调用MD5 JavaScript文件的API
$gavatar = hex_md5($email);
//构造URL
$gavatar_url = "http://www.gravatar.com/avatar/"+$gavatar;
//动态修改头像
$("#ajaxgravatar").html('<img id="ajaxgravatar" alt="Gravatar" src="'+ $gavatar_url +'?d=monsterid"/>')
});

jQuery1.4发布: 你必须知道的15个新特性

原文地址:jQuery 1.4 Released: The 15 New Features you Must Know
原文作者:James Padolsey

译文地址:jQuery1.4发布: 你必须知道的15个新特性
译文作者:Ji Hao

1. 传递属性给jQuery(…)构造器

早在1.4版本之前,jQuery就支持通过有用的”attr“方法为元素集合添加属性,参数可以传递属性的名-值对或者是一个指定了多个属性的对象。jQuery1.4则支持元素创建的时候传递一个属性对象作为jQuery构造器的第二个参数。

举例来说,如果你要用jQuery1.4创建一个有多个属性的超链接对象,用如下简单的代码即可实现:

jQuery('<a/>', {
    id: 'foo',
    href: 'http://google.com',
    title: 'Become a Googler',
    rel: 'external',
    text: 'Go to Google!'
});

你可能已经注意到了”text”属性——可能你正怀疑它在这里出现是干啥的,毕竟超链接这玩意没有”text”属性!好吧,jQuery1.4其实统一了它自身的一些方法接受某些属性的行为。上面指定的”text”属性将会引起jQuery调用”.text()”方法,传递”Go to Google!”作为它的参数。

一个现实中更好点的例子:

jQuery('<div/>', {
    id: 'foo',
    css: {
        fontWeight: 700,
        color: 'green'
    },
    click: function(){
        alert('Foo has been clicked!');
    }
});

“id”被作为一个普通的属性添加,而”css”和”click”属性则触发了相应方法的调用。上面的代码在1.4之前需要链式的这样写出来:

jQuery('<div/>')
    .attr('id', 'foo')
    .css({
        fontWeight: 700,
        color: 'green'
    })
    .click(function(){
        alert('Foo has been clicked!');
    });

更多关于构造器方法请参考文档: jQuery(…)

2. 所有的”until”方法!

在1.4中DOM遍历兵工厂里加入了3个新的方法, ”nextUntil“, “prevUntil“和 “parentsUntil“。这3个方法都是朝着某个方向遍历DOM直到指定的选择器条件满足。假定你有如下的水果列表:

<ul>
    <li>Apple</li>
    <li>Banana</li>
    <li>Grape</li>

    <li>Strawberry</li>
    <li>Pear</li>
    <li>Peach</li>
</ul>

如果你要选择”Apple”后面的直到”Strawberry”为止的所有列表元素,可以用如下简单的代码即可实现:

jQuery('ul li:contains(Apple)').nextUntil(':contains(Pear)');
// Selects Banana, Grape, Strawberry

更多请参考文档:prevUntil, nextUntil, parentsUntil

3. 绑定多个事件处理器

除了将多个事件绑定代码链式的写在一起之外,你还可以在一个bind方法里写多个事件绑定代码如下:

jQuery('#foo).bind({
    click: function() {
        // do something
    },
    mouseover: function() {
        // do something
    },
    mouseout: function() {
        // do something
    }
})

这种写法对于.one()方法同样有效

更多请参考文档:.bind(…)

4. 按照每个属性的擦除(Easing)效果

以前你只能为单个动画指定其擦除效果,现在你能为当前定义动画效果的每个属性来指定擦除效果。jQuery包含了两个擦除效果”linear” 和”swing”(默认).其他的效果你需要单独下载

要为每个属性指定擦除效果,只要把目标属性定义为数组即可,数组的第一个值是你要的动画效果设置的属性值,第二个值是擦除效果函数使用的值:

jQuery('#foo').animate({
    left: 500,
    top: [500, 'easeOutBounce']
}, 2000);

 

看看这段代码的实际运行效果!

你还可以在可选参数options对象属性”specialEasing”里按照名-值对的形式定义每个属性的擦除效果:

jQuery('#foo').animate({
    left: 500,
    top: 500
}, {
    duration: 2000,
    specialEasing: {
        top: 'easeOutBounce'
    }
});

原文编辑注:本文的作者James Padolsey谦虚了,这个新特性其实是他的主意。

更多请参考文档: per-property easing

5. 全新的Live事件代理!

jQuery1.4增加了对”submit“, “change“, “focus” 和”blur“事件的代理支持。在jQuery中我们使用”.live()”方法来代理事件。当你需要对很多元素进行事件处理器注册的时候很有用,或者是当新的元素在将来被加入到DOM文档中我们却需要对其进行事件处理器绑定的情况下(使用”.live()”方法比进行重新绑定更高效)(译者注:更多关于jQuery事件代理请参考:Working with Events, Part 3: More Event Delegation with jQuery

但是,要小心哪!你必须使用事件的名称,如果你要代理”focus”和”blur”,则必须用”focusin“和”focusout

jQuery('input').live('focusin', function(){
    // do something with this
});

6. 控制函数的上下文

jQuery1.4在其命名空间下提供了一个新的”proxy”函数。这个函数接受两个参数,一个”scope”加一个方法名,或者是一个函数加目标作用域。JavaScript的”this”关键字是非常难掌握的。有时候你希望它是你之前创建出来的对象而不是一个元素。

举个例子:我们有如下的一个”app”对象,它有两个属性,一个”clickHandler”方法和一个config对象:

var app = {
    config: {
        clickMessage: 'Hi!'
    },
    clickHandler: function() {
        alert(this.config.clickMessage);
    }
};

“clickHanlder”方法在被这样调用时”app.clickHandler()”将有”app”对象作为其上下文,也就是说”this”关键字访问的就是”app”。如果我们只是做这样的简单调用,这个工作起来完全没有问题:

app.clickHandler(); // "Hi!" is alerted

让我们来试试将其作为事件处理器来绑定到某个事件上:

jQuery('a').bind('click', app.clickHandler);

当我们点击超链接的时候,它看上去并没有工作(因为没有警告消息弹出来)。这是因为jQuery(以及大多数健全的事件模型)都默认的将事件处理器的上下文设置成了事件目标元素——即:使用”this”访问的其实是被点击的元素。但是我们并不想要这样的结果,我们希望”this”能够访问”app”对象。在jQuery1.4中实现这个再容易不过了:

jQuery('a').bind(
    'click',
    jQuery.proxy(app, 'clickHandler')
);

现在不管什么时候点击超链接,总是会有”Hi!”这个警告消息。

这个proxy函数返回你的函数的一个包装过的版本,”this”被设置成你指定的值。proxy函数在其他上下文也是有用的,例如传递一个回调函数给其他的jQuery方法或者传递给插件。

更多请参考文档:jQuery.proxy

7. 延迟一个动画队列

你现在可以为你的动画队列设置一个延迟。事实上任何队列都能设置延迟,但是最通用的场景应该是”fx”队列。它允许你在动画之间暂停,而不用再使用回调函数和”setTimeout”写的乱七八糟的。”.delay()”的第一个参数是你要延迟的毫秒数。

jQuery('#foo')
    .slideDown() // Slide down
    .delay(200) // Do nothing for 200 ms
    .fadeIn(); // Fade in

如果你要延迟默认的”fx”队列之外的队列,则需要传递队列的名称作为第二个参数。

更多请参考文档:.delay(…)

8. 检查是否一个元素包含某些元素

jQuery1.4是的检查一个元素或者一个集合是否”.has()”某些元素更加容易。程序上等同于jQuery选择过滤器”:has()”。这个方法将选择当前集合内的符合参数(选择器)的所有元素。

jQuery('div').has('ul');

上面的这行代码将选择所有包含UL元素的所有DIV元素。这个情况下你用选择过滤器 (“:has()”)也够用了,但是这个方法在你需要用编程的方式过滤一个集合的时候是很有用的。

jQuery1.4 在jQuery名称空间下还提供了一个 “contains”函数。这是一个底层的函数,接受两个DOM节点作为参数,返回boolean值以指示第二个元素是否在第一个元素内。看下面的例子:

jQuery.contains(document.documentElement, document.body);
// Returns true - <body> is within <html>

更多请参考文档:.has(…), jQuery.contains(…)

9.  解除元素的包装

有”.wrap()”方法已经一段时间了,jQuery1.4新增了”.unwrap()”方法做的是和”wrap()”完全相反的事情。假定有如下的DOM结构:

<div>
    <p>Foo</p>
</div>

我们可以解除段落元素的包装:

jQuery('p').unwrap();

结果DOM结构如下:

    <p>Foo</p>

本质上,这个方法简单的去除了任何元素的父元素

更多请参考文档:.unwrap(…)

10. 删除元素而不删除其数据

新的 ”.detach()“方法允许你从DOM文档中删除元素,和”.remove()”方法很像。关键的区别在于这个方法不会删除jQuery保存在这个元素上的数据。这些数据也包含使用”.data()”加上去的数据,也包含使用jQuery事件机制加上去的事件处理器。

这个适用于需要从DOM删除元素然后还要再加入DOM中的情况。被.detach的元素的事件监听器以及其他数据都会被保留。


var foo = jQuery('#foo');

// Bind an important event handler
foo.click(function(){
    alert('Foo!');
});

foo.detach(); // Remove it from the DOM

// … do stuff

foo.appendTo('body'); // Add it back to the DOM

foo.click(); // alerts "Foo!"

更多请参考文档:.detach(…)

11. index(…)的增强

jQuery1.4提供了两种新的方法使用”.index()”方法。之前,你只能传递一个元素作为它的参数,改方法返回一个数字只是当前集合中目标元素的位置。

如果不传参数,则返回当前元素在同辈元素中的位置。假定我们有下面的DOM结构:

<ul>
    <li>Apple</li>
    <li>Banana</li>
    <li>Grape</li>

    <li>Strawberry</li>
    <li>Pear</li>
    <li>Peach</li>
</ul>

当一个列表选项被点击的时候你想要知道他在其他列表选项中的位置:

jQuery('li').click(function(){
    alert( jQuery(this).index() );
});

jQuery1.4还允许你指定一个选择器作为”.index()”方法的第一个参数,这么做将返回当前元素在选择器工作产生的结果集里的位置。

要注意的是这个方法返回整数值,如果选择器没有匹配的结果则返回-1

更多请参考文档:.index(…)

12. DOM操作方法接受回调函数作为参数

现在大多数的DOM操作方法都支持接受一个函数作为单个参数(或者第二个参数,如果是”.css()”和”.attr()”方法的话)。这个传递的函数将会为每个集合中的元素都运行一遍,函数的返回结果将作为DOM操作方法的值。

下面的方法都有接受回调函数作为参数的能力:

在这个回调函数里,你可以通过”this”访问当前正在遍历的元素,回调函数的第一个参数的值是当然遍历元素的位置。

jQuery('li').html(function(i){
    return 'Index of this list item: ' + i;
});

还有,上面某些方法,在回调函数中还可以接收第二个参数。如果你正在调用一个设值方法(如”.html()”或者”.attr(‘href’)”)你可以访问当前要设置成的值,例如:

jQuery('a').attr('href', function(i, currentHref){
    return currentHref + '?foo=bar';
}); 

正如你所看到的使用”.css()”和”.attr()”方法的时候,你可以传递函数作为第二个参数,因为第一个参数是你想要改变的属性的名称。

jQuery('li').css('color', function(i, currentCssColor){
    return i % 2 ? 'red' : 'blue';
});

13. 判断对象的类型

jQuery1.4增加了两个副主函数(在jQuery名称空间下)帮助你检测正在处理的对象类型。

首先,有个”isEmptyObject”,这个函数返回boolean值,指示传递的对象是否为空(没有属性-直接或者间接的)。其次,有个”isPlainObject”,这个函数返回boolean值,指示传递的对象是否是一个纯的JavaScript对象,即使用”{}”或者”new Object()”创建出来的对象。

jQuery.isEmptyObject({}); // true
jQuery.isEmptyObject({foo:1}); // false

jQuery.isPlainObject({}); // true
jQuery.isPlainObject(window); // false
jQuery.isPlainObject(jQuery()); // false

更多请参考文档: isPlainObject(…), isEmptyObject(…)

14. closest()的增强

jQuery的”.closest()”方法现在能接受一组选择器作为参数。这个特性使得你在遍历一个元素祖先节点的时候,或者查找(多个)含有某些特定字符的最近元素的时候更有用。

除此之外,本方法还接受一个context作为其第二个参数,意思是你能控制遍历的深度。这两项增加适用的场景不是很多,但是jQuery内部使用这个方法来获得更好的性能。

更多请参考文档:.closest(…)

15. 新事件!focusIn 和 focusOut

其实上文已经提到,要代理”focus”和”blur”事件,你必须使用新的事件名称”focusin”和”focusout”。这些事件允许你在元素或者某元素的子元素获得焦点的时候干一些事情。

jQuery('form')
    .focusin(function(){
        jQuery(this).addClass('focused');
    });
    .focusout(function(){
        jQuery(this).removeClass('focused');
    });

你还应该注意到的一点是,这些事件是不传播的(冒泡),他们是捕获型事件。意思就是,最外层的元素首先触发该事件,然后才是”目标”元素。

更多请参考文档:focusInfocusOut 事件

享受最受期望的,最具特色的,到目前为止性能最好的jQuery1.4吧!

好吧,差不多了。我已经把自己认为对你们有影响的新特性涵盖到了。

如果你还没有准备好,应该看看”14 days of jQuery“,一个很酷的为jQuery1.4发布以及jQuery4岁生日准备的在线活动。

还有不要忘记看看新的API 文档!

Working with Events, Part 3: More Event Delegation with jQuery


原文地址:http://www.learningjquery.com/2009/09/working-with-events-part-3-more-event-delegation-with-jquery
原文作者:  Louis-Rémi Babé

正如本系列的第一篇文章中描述的那样,事件代理是利用事件冒泡机制来避免多次绑定事件监听器的一种办法。jQuery1.3和即将到来的jQuery1.4有很多新的特性可以使你的网页中使用事件代理更容易。这篇指南的目标就是帮助你理解这些新特性是如何工作的。

从传统的事件监听到事件代理

既然一个DOM元素上发生的事件会被传递到它所有的祖先元素(或者说是DOM节点)上,那么一个事件监听器就能被绑定在众多DOM元素的单一的那个祖先节点上,而不用为所有的DOM元素每个都单独绑定事件监听器。

看下面的列表先,再考虑下面的问题:

<ul class="myList">
  <li class="red">The first item.</li>
  <li class="green">The second item.</li>
  <li class="yellow">The third item.</li>
  <li class="blue">The fourth item.</li>
</ul>
<p>Class of the last clicked item: <span id="display"> </span>
</p>

如果我们想知道被点击的列表元素的class,使用传统事件监听器的jQuery代码应该是这样写的:

$("li").click( function( event ) {
  $("#display").text(event.target.className);
});

传递给事件处理器的参数event对象有一个target属性,对应于被点击的元素。

使用事件代理的等价的代码是这样写的:

$("ul").click( function( event ) {
  $("#display").text(event.target.className);
});

试试看实际效果:

  • The first item.
  • The second item.
  • The third item.
  • The fourth item.

Class of the last clicked item:?

事件代理有两个主要的优势:
1. 使用一个事件监听器代替多个事件监听器明显更快
2. 任何页面加载完成之后动态新插入的元素也将会拥有相同的行为(在Working with Events, Part 1中已经演示过了)

这个转换成事件代理太简单了,因为我们原来的目标只是显示列表元素的class。使用前面的这个代码片断,无序列表本身的class(myList,点列表那个黑点的左边就能看出效果)也会被显示出来。因此,我们还应该判断一下点击的目标是个<li>元素。

$("ul").click( function( event ) {
  if(event.target.nodeName == "LI") {
 $("#display").text(event.target.className);
  }
});

试试看现在的效果:

  • The first item.
  • The second item.
  • The third item.
  • The fourth item.

Class of the last clicked item: ?

扫描event.target的祖先节点: .closest() 方法

操作像上面的例子一样如此简单的DOM文档,使用事件代理非常容易搞定。但是如果列表项里还包含子元素的话事情就会变得复杂许多,如下面这个列表元素:

<ul class="myList">
  <li class="red"><b>The <i>first <u>item</u></i></b>.</li>
  <li class="green"><b>The <i>second <u>item</u></i></b>.</li>
  <li class="yellow"><b>The <i>third <u>item</u></i></b>.</li>
  <li class="blue"><b>The <i>fourth <u>item</u></i></b>.</li>
</ul>
<p>Class of the last clicked item: <span id="display"> </span>
</p>

这种情况下,如果用户点击了 item 这个单词,event.target就会使<u>.这样的话就必须遍历当前目标元素的所有的祖先节点,来找到我们关心的元素:即<li>.

$("ul").click( function( event ) {
  var elem = event.target;
  while( elem.nodeName != "LI" && elem.parentNode) {
 elem = elem.parentNode;
  }
  if(elem.nodeName == "LI") {
 $("#display").text(event.target.className);
  }
});

注意如果用户点击到<li>的外面,我们需要在某个时候停止对祖先节点的循环,这个例子,我们会一直找到根节点(根节点没有父节点)。

jQuery1.3引入了一个.closest() 方法,可以用一行代码替换刚刚的循环。

$("ul").click( function( event ) {
 var $elem = $(event.target).closest("li");
 if($elem.length) {
 $("#display").text($elem.attr("class"));
 }
});

试试看用.closest()的效果是不是还正确:

  • The first item.
  • The second item.
  • The third item.
  • The fourth item.

Class of the last clicked item:?

传递给.closest()方法的参数是一个CSS选择器,这个选择器将会匹配第一个感兴趣的祖先节点。

上下文参数

可以这样说:当点击事件发生在<li>外面的时候,我们可以在查找的祖先节点在找到<ul>的时候就停止,而不用等到一直文档根节点才停止循环。jQuery1.4将会引入一个可选的context参数到.closest()方法来达到这个目的。

$("ul").click( function( event ) {
  $("#display").text($(event.target).closest("li", this).attr("class"));
});

这里的this即事件监听器绑定的<ul>元素。这个可选参数因为避免了查找可能不存在的祖先节点的资源浪费,从而提高了事件代理的性能。

用一行代码实现事件代理: .live()方法

jQuery1.3引入了一个.live()方法,这个方法绑定事件监听器的时候隐式调用.closest()方法来决定事件监听器是不是该被执行。

$("li").live("click", function( event ) {
  $("#display").text(
 $(event.currentTarget).attr("class")
  );
});

注意使用.live()方法的语法是不同的。看上去我们换回了传统的事件绑定的写法。但是最大的不同是,这样.live()方法写的事件监听器对于当前页面中已存在的元素和之后动态插入的元素都是有效的。当然没什么神秘的:.live()方法幕后只是把事件监听器绑定在文档根节点上,然后使用.closest()方法过滤任何event.target.

和传统的事件绑定语法相比一个值得注意的区别是,在事件处理器内部,我们不再使用event的target属性,而是使用currentTarget。事实上,event对象的target可能是一个<li>的子元素,而currentTarget属性则是被隐式的.closest()方法找到的元素。

正如在Event对象文档中将的,currentTarget属性应该是事件冒泡阶段的当前DOM元素,即:事件监听器检测到的元素总是事件监听器被绑定的元素。当使用.live()方法的时候,currentTarget总是文档根节点,你需要再一次用.closest()方法根据target找到感兴趣的祖先节点。

$("li").live("click", function( event ) {
  $("#display").text(
 $(event.target).closest("li").attr("class")
  );
});

如果使用jQuery1.3则必须要写成这样,如果使用jQuery1.4,currentTarget已经在内部被默认修改掉了,可以避免在事件处理器内部使用额外的.closest()方法来查找目标。

上下文参数

在jQuery1.3中所有使用live方式的事件监听器实质上都是绑定在DOM文档根节点上的。因为一个事件监听器检测到的所有事件都将触发执行隐式的.closest()方法,即使事件的目标元素不是我们所感兴趣的,所以这将影响网页的性能。

在jQuery1.4中.live()方法利用jQuery对象的上下文参数,它能够将事件监听器绑定到文档的一个具体的我们关心的元素上:

$("li", $("ul")[0]).live("click", function( event ) {
  $("#display").text(
 $(event.currentTarget).attr("class")
  );
});

上下文参数就是创建jQuery对象的第二个参数。为了对.live()方法有用,它必须被置成一个纯的DOM元素,这就是为什么$(“ul”)后面跟了个[0]的原因。Brandon Aaron 有一篇有用的文章详细解释了上下文参数

解除.live()绑定: .die()方法

就像.bind()和.unbind()互为补充允许事件的绑定和解除绑定,.live()也有与其互为补充的.die()方法。

和.bind()不一样的是.live()不支持使用 namespaced events

处理不冒泡的事件

事件代理对于有些事件不能实现,因为这些事件不会冒泡。jQuery1.4允诺.live()方法依然能够支持这些不冒泡的事件。这个已经实现,而且将会在接下来的第四篇文章中被涵盖到。

本文包含的脚本:

Working with Events, part 2

 

原文地址:http://www.learningjquery.com/2008/05/working-with-events-part-2
原文作者:  Karl Swedberg

我的上一篇文章中,描述了一个常见的问题,即事件对新加入HTML文档的元素表面上不工作的情况,不管这个元素是通过ajax方式还是修改DOM的方式加入进来的。我们也检查了一个解决此问题办法:事件代理。使用这种办法,我们将事件绑定到一直在DOM中的容器元素上然后再检查事件发生的目标元素。

Cloning Nodes

这一次,我们将一起看看解决此问题的另一个方法:重新绑定事件处理器。但是这么做之前,我应该要提一下,在jQuery1.2中事件处理器能够随着元素一起被克隆。看这个无序列表:

<ul id="list3" class="eventlist">
  <li>plain</li>
  <li class="special">special <button>I am special</button></li>
  <li>plain</li>
</ul>

我们可以拷贝一个<li class=”special”>然后插入到被拷贝的元素后面,同时取得任何绑定在原来元素上的事件处理器。jQuery提供的这个.clone()方法不会为我们把这任务都干了,它只会做元素的拷贝

$(document).ready(function() {
  $('#list3 li.special button').click(function() {
 var $parent = $(this).parent();
 $parent.clone().insertAfter($parent);
  });
});

试试看:

  • plain
  • special
  • plain

正如你所看到的,原按钮能够继续创建新的列表元素,但是“动态生成”的列表元素内的按钮不能创建新的按钮。

为了使得事件处理器也能被拷贝到新的元素上,我们只需要传递true给clone方法:

$(document).ready(function() {
  $('#list4 li.special button').click(function() {
 var $parent = $(this).parent();
 $parent.clone(true).append(' I\'m a clone!').insertAfter($parent);
  });
});

注:我加了个.append(‘ I\’m a clone!’)只是为了让发生的事情看上去更明显。
试试看:

  • plain
  • special
  • plain

当我们想拷贝已有元素及其事件处理器的时候使用.clone(true)尤为有效,但是还有很多其他和克隆不相关的情况我们也希望事件处理器能够被保留。

Re-binding基础

re-binding的概念相当直接:我们定义一个绑定事件处理器的函数,然后每当有新元素加入的时候调用这个函数。例如:上面的无序列表,我们首先创建一个addItem函数,这个函数注册一个事件处理器,这个事件处理器的意图是点击事件发生的时候,添加一个新的列表元素。

function addItem() {
  $('#list5 li.special button').click(function() {
 var $newLi = $('<li>special and new <button>I am new</button></li>');
 $(this).parent().after($newLi);
  });

下一步,当DOM加载完成的时候调用这个函数:

$(document).ready(function() {
  addItem();
});

最后我们在click事件处理器内再次调用这个函数,这样做的话,新加入的元素也能绑定事件处理器。

我们在多加一个事件处理器绑定在按钮上,但是不为这个做re-bind,为了试验的时候能看出区别。

为#list5内button做处理的全部的代码:

function addItem() {
  $('#list5 li.special button').click(function() {
 var $newLi = $('<li>special and new <button>I am new</button></li>');
 $(this).parent().after($newLi);
 addItem();
  });
}
$(document).ready(function() {
  addItem();
  // non-rebinding click handler ...
  $('#list5 li.special button').click(function() {
 $(this).after(' pressed');
  });
});

试试看(IE下还是不要点击了,死循环啊!!!):

  • plain
  • special
  • plain

可以看到每当第一个列表项的按钮被点击的时候”pressed”会被添加到这个列表项的后面,但是不会被添加到我们动态创建的列表元素的后面。另一方面,动态创建出来的按钮也能创建新的列表元素,因为函数已经被重新绑定过了。

然而,如果我们点击不只一次这个按钮,就会发现我们刚刚做的这一切产生了不受欢迎的结果。每点击一个按钮都会再绑定一次事件处理器,产生乘法的效果,即:第1次点击产生1个额外的列表项,第2次点击产生2个,第2次点击产生4个,循环下去。

Unbind和Bind

为了避免乘积型的绑定,我们可以先解除绑定然后再重新绑定。所以上面代码的第二行,我们将替换原来的

 $(‘#list5 li.special button’).click(function() {

$(‘#list6 li.special button’).unbind(‘click’).bind(‘click’,(function() {

注意这里的.bind()方法,这是jQuery通用的事件绑定处理方法。所有其他的诸如.click(), .blur(), .resize()等等都是等价的.bind(‘event’)的简写形式。

全部的代码如下,作为对比再看一下非重新绑定的事件处理器代码

function addItemUnbind() {
  $('#list6 li.special button')
 .unbind('click')
 .bind('click', function() {
   var $newLi = $('<li>special and new <button>I am new</button></li>');
   $(this).parent().after($newLi);
   addItemUnbind();
  });
}
$(document).ready(function() {
  addItemUnbind();
  // non-rebinding click handler
  $('#list6 li.special button').click(function() {
 $(this).after(' pressed');
  });
});

看看这次它怎么工作?

  • plain
  • special
  • plain

不幸的是,我们尝试解除函数addItemUnbind()绑定的方法过头了,把”non-rebinding”的点击处理器(甚至它连一次运行的机会都没得到)也解除了绑定,(证据可以从运行结果看出来,因为在”I am special”的按钮后面没有加上”pressed”的文本)。很明显,我们将不得不对我们需要解除绑定的东西更加小心。

使用事件名称空间

一种避免过度的解除绑定的方法是为绑定和解除绑定的相应点击事件加上“名称空间”。所以,不同于.bind('click').unbind('click)例如我们用这样的方法.bind('click.addit').unbind('click.addit').这是一个代码的示例除了使用有名称空间的事件之外和之前的代码基本一样。

function addItemNS() {
  $('#list7 li.special button')
 .unbind('click.addit')
 .bind('click.addit', function() {
   var $newLi = $('<li>special and new <button>I am new</button></li>');
   $(this).parent().after($newLi);
   addItemNS();
  });
}
$(document).ready(function() {
  addItemNS();
  // non-rebinding click handler
  $('#list7 li.special button').click(function() {
 $(this).after(' pressed');
  });
});

终于,我们有了期望得到的这一堆按钮和其被加上的正确的事件行为。(IE下还是不要点击了,这个也会产生死循环啊!!!):

  • plain
  • special
  • plain

请阅读Brandon Aaron的文章以了解更多关于事件名称空间的知识: Namespace Your Events.

Bonus:通过函数引用的方式解除绑定

如果你一直看到这里,证明你是个非常有耐心的人,所以我将特别奖励一个重新绑定的终极方法。除了使用事件名称空间之外,我们还可以在调用.bind()和.unbind()的方法时,增加第二个参数以引用函数。我们需要稍微调整一下代码防止递归,最终下面的代码应该是OK的.

function addItemFinal() {
 var $newLi = $('<li>special and new <button>I am new</button></li>');
 $(this).parent().after($newLi);
 $('#list8 li.special button')
   .unbind('click', addItemFinal)
   .bind('click', addItemFinal);
}
$(document).ready(function() {
$('#list8 li.special button').bind('click', addItemFinal);
  // non-rebinding click handler
  $('#list8 li.special button').click(function() {
 $(this).after(' pressed');
  });
});

注意这里在bind和unbind里的addItemFinal是没有括号的,因为我们只是在引用函数,而不是在做函数调用,让我们最后再测试一下吧:

  • plain
  • special
  • plain

实现此功能可选的jQuery插件

有三个很棒的插件能为我们干上面的事:

如果本文让你困惑的或者你只想要一个快速的测试过的解决方案,你一定要试试这几个插件中的一个,每个插件工作起来略有不同,但是都用样精彩。

更新:使用事件名称空间的添加删除例子

回复Nick Johns 下面的评论,我做了一个允许增加和删除的例子,代码基于我们所讲的”使用事件名称空间”的方法如下:

function addRemoveItemNS() {
  var $newLi = $('<li>special and new <button>I am new</button> <button>remove me</button></li>');
$('#list9 li.special')
  .find('button.addone')
 .unbind('click.addit')
 .bind('click.addit', function() {
   $(this).parent().after($newLi);
   addRemoveItemNS();
  })
  .end()
  .find('button.removeme')
  .unbind('click.removeit')
  .bind('click.removeit', function() {
 $(this).parent().remove();
  });
}
$(document).ready(function() {
  addRemoveItemNS();
});

我为初始的按钮家了一个”addone”的class,否则列表就和其他一样了,试试下面的例子:

  • plain
  • special
  • plain
<ul class="eventlist" id="list9">
<li>plain</li>
<li class="special">special <button class="addone">I am special</button></li>
<li>plain</li>
</ul>

本文所包含的脚本:

为wordpress博客文章设置单独的CSS

因为想要在文章中插入一些动态的内容来做一些前端的demo,自然用到了JavaScript和CSS,目前我用的wordpress2.9对插入JavaScript的功能已经支持得蛮好,即使使用富文本编辑器和HTML视图切换的时候JavaScript不会被过滤掉,但是用link标签还是会被过滤。 

网上有个per post css的wordpress插件,利用的是自定义meta域的方法,在页面渲染的时候插入css的link,虽然我没搞过WP的插件开发,但是代码倒也挺容易看懂,基本上不用解释了。 

下面这个插件,性能不好,如果文章和css比较多的,每次查看的时候都要做很多次无效的循环(比如单独查看每个页面的时候),所以我没有选择这个插件。我换了个思路解决不能插入link标签的问题。 


<?php

/*
Plugin Name: Per-Post CSS
Version: 1.1
Plugin URI: <a href="http://trevorcreech.com/geekery/wordpress/per-post-css/">http://trevorcreech.com/geekery/wordpress/per-post-css/</a>
Description: This plugin allows you to specify a chunk of CSS, which will be included in the header only when viewing that post, or a page where that post appears.  Put the custom CSS in a Custom Field called "Per-Post CSS".  The Custom Fields interface can be found directly below the file upload interface when you are creating or editing a post.
Author: Trevor Creech
Author URI: <a href="http://trevorcreech.com">http://trevorcreech.com</a>
*/

function ppc_header()
{
 global $posts;
 for($i=0;$i<count($posts);$i++)
 {
  $ppc_embed = get_post_meta($posts[$i]->ID, 'Per-Post CSS', false);
  $ppc_ext = get_post_meta($posts[$i]->ID, 'Per-Post CSS File', false);
  for($j=0;$j<count($ppc_embed);$j++)
  {
   $ppc_output .=  '/* Embedded CSS for "' . $posts[$i]->post_title . "\" */\n";
   $ppc_output .= $ppc_embed[$j] . "\n";
  }
  for($j=0;$j<count($ppc_ext);$j++)
  {
   $ppc_output .=  '/* Externel CSS for "' . $posts[$i]->post_title . "\" */\n";
   $ppc_output .= "@import url(\"$ppc_ext[$j]\")" . "\n";
  }
 }
 if($ppc_output)
 {
  echo "<style type=\"text/css\">\n/* Per-Post CSS */\n";
  echo $ppc_output;
      }
 echo "</style>\n";
}

add_action('wp_head', 'ppc_header');
?>

我的解决办法是既然JavaScript标签现在wordpress已经有支持了,那么就用JavaScript为需要单独使用css的文章或者页面加载css文件,下面的代码摘录自我的一个测试页面: 

 
<script src="http://www.google.com/jsapi"></script>

<script type="text/javascript">// <![CDATA[
    google.load("jquery", "1.3.2");
// ]]&gt;</script>

<script src="http://www.haojii.com/webdev/working-with-events/events.js" type="text/javascript"></script>
<script src="http://www.haojii.com/webdev/working-with-events/loadcss.js" type="text/javascript"></script>

 

//loadcss.js
$(document).ready(function() {
   var $per_post_css = $('<link href="http://www.haojii.com/webdev/working-with-events/working-with-events-part-1.css" media="screen, projection" rel="stylesheet" type="text/css"></link>');
   $(document.body).append($per_post_css);
});

AVATAR

今天下班后去看了3D版的AVATAR, 视觉效果的确非常棒,剧情的确很一般

感觉本片对于观众感情的掌控还不够,不管是同情、爱情、友情的渲染都不到位

也许对于一部以特效镜头为卖点的影片来说,各种媒体的评论宣传自然不会提及这些明显不足的

说到特效其实Avatar的战斗场面没有《变形金刚系列》来得震撼

影片的世界观其实也没有最近的那集《星际迷航》来得壮阔

悬浮在空中的磁悬浮山和N年前电影《蜀山》中的镜头很类似

那颗被轻易就弄倒的巨大的树不免让我想起了宫崎骏《龙猫》中的那颗大榕树

元神出窍的功能无非也只是之前看过的《未来警察》中的生物克隆版

比较震撼我的打动我的其实是那些奇妙的avatar星球的生物,特别是那些小东西很美很有想象力,透过3D眼镜看来就在眼前飘来飘去,很舒服,能让我看到这些美妙的东西,我觉得电影票的钱就很值了

演员中亮点是那个开飞机的有点野性的美女,一眼就认出来是《Lost》中的Ana-Lucia,身材不错

总的来说本片套路还是一般的商业片模式,看了开头就能猜到结尾的那种,不需要动脑子,好人坏人一目了然,无非就是把美好的东西毁给你看,中间表达一下人性的邪恶和人性的反思,准备收手的时候先来个N多人混战PK加爆炸,最后是最终BOSS战,一番苦斗之后终于消灭了BOSS,我们的英雄差点死了,结果没死,最后再给大家留个期望看到的美好的结局,happily ever after…

唉,这样的剧本我觉得可以编个程序自动生成,无非定义一些时间、地点、人物、动物、装备、爆炸级别什么的。。。

虽然上面批评比较多,但是本片视觉效果非常棒,错过了可惜,还是建议大家看看,追随一下潮流。。。

最后的最后送上我的avatar肉身(戴眼镜那个是我老婆的)

p.s. 若你也想化生一把,请访问这个地址 http://www2.mcdonalds.fi/day/avatar/avatarize.php?lid=china ,成功了的,别忘记和我分享一下