竹磬网-邵珠庆の日记 生命只有一次,你可以用它来做些更多伟大的事情–Make the world a little better and easier


1910月/120

jQuery性能优化指南

发布在 邵珠庆

现在jquery应用的越来越多, 有些同学在享受爽快淋漓coding时就将性能问题忽略了,  比如我.  jquery虽在诸多的js类库中性能表现还算优秀, 但毕竟不是在用原生的javascript开发, 性能问题还是需要引起重视的. 在twitter上发现了<jQuery Performance Rules>这篇文章, 简单的摘译了一下:

  1. 总是从ID选择器开始继承
  2. 在class前使用tag
  3. 将jquery对象缓存起来
  4. 掌握强大的链式操作
  5. 使用子查询
  6. 对直接的DOM操作进行限制
  7. 冒泡
  8. 消除无效查询
  9. 推迟到 $(window).load
  10. 压缩js
  11. 全面掌握jquery库

 

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

在jquery中最快的选择器是ID选择器. 因为它直接来自于Javascript的getElementById()方法.

<div id=“content”>

<form method=“post” action=“/”>

<h2>Traffic Light</h2>

<ul id=“traffic_light”>

<li><input type=“radio” class=“on” name=“light” value=“red” /> Red</li>

<li><input type=“radio” class=“off” name=“light” value=“yellow” /> Yellow</li>

<li><input type=“radio” class=“off” name=“light” value=“green” /> Green</li>

</ul>

<input class=“button” id=“traffic_button” type=“submit” value=“Go” />

</form>

</div>

像这样选择按钮是低效的:

var traffic_button = $(‘#content .button’);

用ID直接选择按钮效率更高:

var traffic_button = $(‘#traffic_button’);

选择多个元素

提到多元素选择其实是在说DOM遍历和循环, 这些都是比较慢的东西.为了提高性能, 最好从就近的ID开始继承.

var traffic_lights = $(‘#traffic_light input’);

2. 在class前使用tag

第二快的选择器是tag选择器($(’head’)). 同理,因为它来自原生的getElementsByTagName() 方法.

<div id=“content”>

<form method=“post” action=“/”>

<h2>Traffic Light</h2>

<ul id=“traffic_light”>

<li><input type=“radio” class=“on” name=“light” value=“red” /> Red</li>

<li><input type=“radio” class=“off” name=“light” value=“yellow” /> Yellow</li>

<li><input type=“radio” class=“off” name=“light” value=“green” /> Green</li>

</ul>

<input class=“button” id=“traffic_button” type=“submit” value=“Go” />

</form>

</div>$$

总是用一个tag name来限制(修饰)class (并且不要忘记就近的ID):

var active_light = $(‘#traffic_light input.on’);

注意: 在jquery中Class是最慢的选择器. IE浏览器下它会遍历所有DOM节点不管它用在那里.

不要用用tag name来修饰ID. 下面的例子将会遍历所有的div元素来查找id为’content’的哪一个节点:

var content = $(‘div#content’);

用ID修饰ID也是画蛇添足:

var traffic_light = $(‘#content #traffic_light’);

3.将jquery对象缓存起来

要养成将jquery对象缓存进变量的习惯.

永远不要这样做:

$(‘#traffic_light input.on).bind(’click‘, function(){…});

$(’#traffic_light input.on).css(‘border’, ‘3px 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’, ‘3px dashed yellow’);

$active_light.css(‘background-color’, ‘orange’);

$active_light.fadeIn(’slow’);

为了记住我们本地变量是jquery的封装, 通常用一个$作为变量前缀. 记住,永远不要让相同的选择器在你的代码里出现多次.

缓存jquery结果,备用

如果你打算将jquery结果对象用在程序的其它部分,或者你的function会多次执行, 那么就将他们缓存到一个全局变量中.

定义一个全局容器来存放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’);

}

4. 掌握强大的链式操作

上面的例子也可以写成这样:

var $active_light = $(‘#traffic_light input.on’);$active_light.bind(‘click’,function(){…})

.css(‘border’, ‘3px dashed yellow’)

.css(‘background-color’, ‘orange’)

.fadeIn(’slow’);

这样可以写更少的代码, 让我们的js更轻量.

5.使用子查询

jQuery 允许我们对一个已包装的对象使用附加的选择器操作. 因为我们已经在保存了一个父级对象在变量里, 这样大大提高对其子元素的操作:

<div id=“content”>

<form method=“post” action=“/”>

<h2>Traffic Light</h2>

<ul id=“traffic_light”>

<li><input type=“radio” class=“on” name=“light” value=“red” /> Red</li>

<li><input type=“radio” class=“off” name=“light” value=“yellow” /> Yellow</li>

<li><input type=“radio” class=“off” name=“light” value=“green” /> Green</li>

</ul>

<input class=“button” id=“traffic_button” type=“submit” value=“Go” />

</form>

</div>

例如, 我们可以用子查询的方法来抓取到亮或不亮的灯, 并缓存起来以备后续操作.

var $traffic_light = $(‘#traffic_light’),

$active_light = $traffic_light.find(‘input.on’),

$inactive_lights = $traffic_light.find(‘input.off’);

提示: 你可以用逗号分隔的方法一次声明多个局部变量–节省字节数



6.对直接的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);

我们在插入之前将多个元素包裹进一个单独的父级节点会更快:

var top_100_list = [...],

$mylist = $(‘#mylist’),

top_100_ul = ‘<ul id=”#mylist”>’;

for (var i=0, l=top_100_list.length; i<l; i++){

top_100_ul += ‘<li>’ + top_100_list[i] + ‘</li>’;

}

top_100_ul += ‘</ul>’; //关闭无序列表

$mylist.replaceWith(top_100_ul);

如果你做了以上几条还是担心有性能问题,那么:

  • 试试jquery的 clone() 方法, 它会创建一个节点树的副本, 它允许以”离线”的方式进行dom操作, 当你操作完成后再将其放回到节点树里.
  • 使用DOM DocumentFragments. 正如jQuery作者所言, 它的性能要明显优于直接的dom操作.

7. 冒泡

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

代替这种效率很差的多元素事件监听的方法就是, 你只需向它们的父节点绑定一次, 并且可以计算出哪个节点触发了事件.

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

像这样绑定事件是低效的:

$(‘#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 grabs the node that triggered the event.

cell.addClass(’selected’);

}).bind(‘blur’, function(e){

var cell = $(e.target);

cell.removeClass(’selected’);

});

父级元素扮演了一个调度员的角色, 它可以基于目标元素绑定事件. 如果你发现你给很多元素绑定了同一个事件监听, 那么你肯定哪里做错了.

8.消除无效查询

尽管jquery可以很优雅的处理没有匹配元素的情况, 但它还是需要花费时间去寻找. 如果你整站只有一个全局js, 那么极有可能把所有的jquery函数塞进$(document)ready(function(){//所有你引以为傲的代码})里.

只运行在页面里用到的函数. 大多数有效的方法就是使用行内初始化函数, 这样你的模板就能准确的控制何时何处该执行js.

例如, 你的”文章”页面模板, 你可能会引用如下的代码在body结束处:

<script type=“text/javascript>

mylib.article.init();

</script>

</body>

如果你的页面模板包含一些多变的模块可能不会出现在页面中, 或者为了视觉呈现的原因你需要它们能够快速加载, 你可以将初始化函数紧跟在模块之后.

<ul id=“traffic_light”>

<li><input type=“radio” class=“on” name=“light” value=“red” /> Red</li>

<li><input type=“radio” class=“off” name=“light” value=“yellow” /> Yellow</li>

<li><input type=“radio” class=“off” name=“light” value=“green” /> Green</li>

</ul>

<script type=“text/javascript>

mylib.traffic_light.init();

</script>

你的全局js库可能会是这样子的:

var mylib ={

article_page :{

init : function(){

// Article 特有的jQuery函数.

}

},

traffic_light :{

init : function(){

// Traffic light 特有的jQuery函数.

}

}

}

9. 推迟到 $(window).load

jquery对于开发者来说有一个很诱人的东西, 可以把任何东西挂到$(document).ready下冒充事件. 在大多数例子中你都会发现这样的情况.

尽管$(document).ready确实很有用, 它可以在页面渲染时,其它元素还没下载完成就执行. 如果你发现你的页面一直是载入中的状态, 很有可能就是$(document).ready函数引起的.

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

$(window).load(function(){

// 页面完全载入后才初始化的jQuery函数.

});

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

10. 压缩js

推荐一个js在线压缩地址: http://dean.edwards.name/packer/

11. 全面掌握jquery库

知己知彼, 百战百胜.  只有更深入的了解jQuery才能更灵活的使用它.  这里提供一个jQuery的速查手册, 可以打印出来随身携带.  要是有能力将jQuery源码通读一遍那就更好了.

298月/112

网站导航设计模式指南

发布在 邵珠庆

在网页设计中有一些通用的交互设计模式。网站导航各种各样的通用和大家熟知的设计模式,可以用来作为为网站创建有效地信息架构的基础。这篇指南涵盖了流行的站点导航设计模式。对于每一种网站导航栏设计模式,我们将讨论它的一般特征,它的缺点,以及什么时候使用它最好。


 

顶部水平栏导航
顶部水平栏导航是当前两种最流行地网站导航菜单设计模式之一。它最常用于网站的主导航菜单,且最通常地放在网站所有页面的网站头的直接上方或直接下方。

顶部水平栏导航设计模式有时伴随着下拉菜单,当鼠标移到某个项上时弹出它下面的二级子导航项。

顶部水平栏导航一般特征
导航项是文字链接,按钮形状,或者选项卡形状
水平栏导航通常直接放在邻近网站logo的地方
它通常位于折叠之上


顶部水平栏导航的缺点
顶部水平栏导航最大的缺点就是它限制了你在不采用子级导航的情况下可以包含的链接数。对于只有几个页面或类别的网站来说,这不是什么问题,但是对于有非常复杂的信息结构且有很多模块组成的网站来说,如果没有子导航的话,这并不是一个完美的主导航菜单选择。

何时使用顶部水平栏导航
顶部水平栏导航对于只需要在主要导航中显示5-12个导航项的网站来说是非常好的。这也是单列布局的网站的主导航的唯一选择(除了通常用于二级导航系统的底部导航)。当它与下拉子导航结合时,这种设计模式可以支持更多的链接。

竖直/侧边栏导航
侧边栏导航的导航项被排列在一个单列,一项在一项的上面。它经常在左上角的列上,在主内容区之前——根据一份针对从左到右习惯读者的导航模式的可用性研究,左边的竖直导航栏比右边的竖直导航表现要好。
侧边栏导航设计模式随处可见,几乎存在于各类网站上。这有可能是因为竖直导航是当前最通用的模式之一,可以适应数量很多的链接。


它可以与子导航菜单一起使用,也可以单独使用。它很容易用于包含很多链接的网站主导航。侧边栏导航可以集成在几乎任何种类的多列布局中。

侧边栏导航的一般特征
文字链接作为导航项很普遍(包含或不包含图标)
很少使用选项卡(除了堆叠标签导航模式)
竖直导航菜单经常含有很多链接 


 

竖直/侧边栏导航缺点

因为可以处理很多链接,当竖直菜单太长时有时可能将用户淹没。尝试限制你引入的链接数,取而代之可以使用飞出式子导航菜单以提供网站的更多信息。同时考虑将链接分放在直观的类别当中,以帮助用户很快地找到感兴趣的链接。

何时使用竖直/侧边栏导航
竖直导航适用于几乎所有种类的网站,尤其适合有一堆主导航链接的网站。

选项卡导航
选项卡导航可以随意设计成任何你想要的样式,从逼真的,有手感的标签到圆滑的标签,以及简单地方边的标签等。它存在于各种各样的网站里,并且可以纳入任何视觉效果。


选项卡比起其它类别的导航有一个明显的优势:它们对用户有积极的心理效应。人们通常把导航与选项卡关联在一起,因为他们曾经在笔记本或资料夹里看见选项卡,并且把它们与切换到一个新的章节联系在一起。这个真实世界的暗喻使得选项卡导航非常直观。

选项卡导航的一般特征
样子和功能都类似真实世界的选项卡(就像在文件夹,笔记本等中看到的一样)
一般是水平方向的但也有时是竖直的(堆叠标签) 
 

选项卡导航的缺点

选项卡最大的缺点是它比简单的顶部水平栏更难设计。它们通常需要更多的标签,图片资源以及CSS,具体根据标签的视觉复杂度而定。选项卡的另一个缺点是它们也不太适用于链接很多的情况,除非它们竖直地排列(即使这样,如果太多的话它们还是看起来很不合适)。

何时使用选项卡导航
选项卡也适合几乎任何主导航,虽然它们在可以显示的链接上有限制,尤其在水平方向的情况下。将它们用于拥有不同风格子导航的主导航的较大型网站是个不错的选项。

面包屑导航
面包屑的名字来源于Hansel和Gretel的故事,他们在沿途播撒面包屑以用来找到加家的路,这可以告诉你在网站的当前位置。这是二级导航的一种形式,辅助网站的主导航系统。


面包屑对于多级别具有层次结构的网站特别有用。它们可以帮助访客了解到当前自己在整站中所处的位置。如果访客希望返回到某一级,它们只需要点击相应的面包屑导航项。

面包屑的一般特征
一般格式是水平文字链接列表,通常在两项中间伴随着左箭头以指示层及关系
从不用于主导航 
 

面包屑导航的缺点

面包屑不适于浅导航网站。当网站没有清晰的层次和分类的时候,使用它也可能产生混乱。何时使用面包屑导航。面包屑导航最适用于具有清晰章节和多层次分类内容的网站。没有明显的章节,使用面包屑是得不偿失。

标签导航
标签经常被用于博客和新闻网站。它们常常被组织成一个标签云,导航项可能按字母顺序排列(通常用不同大小的链接来表示这个标签下有多少内容),或者按流行程度排列。

标签是出色的二级导航而很少用于主导航。他可以提高网站的可发现性和探索性。标签云通常出现在边栏或底部。如果没有标签云,标签则通常包括于文章顶部或底部的元信息中,这种设计让用户更容易找到相似的内容。

标签导航的一般特征
标签是以内容为中心的网(博客和新闻站)站的一般特性
仅有文字链接
当处于标签云中时,链接通常大小各异以标识流行度
经常被包含在文章的元信息中
标签导航的缺点
人们通常把标签和博客和新闻网站联系在一起(有时候也可能是电子商务网站),所以如果你的网站与这些网站有本质的不同,它可能对你就没有帮助。标签也会给内容创作者带来一定量的工作量,因为为了使标签系统有效,每篇文章都需要打上准确的标签。

何时使用标签
如果你拥有很多主题,为内容打上关键词标记是很有利的。如果你仅有几个页面(可能你的网站是一个公司网站),可能就不需要给内容打标签了。是否结合标签云或只是将标签包含在元信息中得取决于你的设计。

搜索导航
近些年来网站检索已成为流行的导航方式。它非常适合拥有无限内容的网站(像维基百科),这种网站很难使用其它的导航。搜索也常见于博客和新闻网站,以及电子商务网站。

搜索对于清楚知道自己想要找什么的访客非常有用。但是有了搜索并不代表着就可以忽略好的信息结构。它对于保证那些不完全知道自己要找什么或是想发现潜在的感兴趣内容的浏览者可以查找到内容依然非常重要。

搜索导航的一般特征
搜索栏通常位于头部或在侧边栏靠近顶部的地方
搜索栏经常会出现在页面布局中的辅助部分,如底部
搜索导航的缺点
搜索最大的缺点是并非所有搜索引擎都是平等的。取决于你选择的方案,你网站的搜索特性可能不能返回精确的结果或者缺失一些东西如文章元数据。搜索导航,对于大部分网站来说,应该作为次要的导航形式。搜索是用户在无法被导航到他们想找的东西的地方时的可靠选择。

何时使用搜索导航
对于具有无数页面并且有复杂信息结构的网站来说,肯定必须引入搜索功能。没有它用户可能很难通过遍历链接和多层的导航来找到他们想要的信息。搜索对于电子商务网站也非常重要,而关键的一点是电子商务网站的搜索结果要根据网站存货的多少具有相应的筛选和排序功能。

出式菜单和下拉菜单导航
出式菜单(与竖直/侧边栏导航一起使用)和下拉菜单(一般与顶部水平栏导航一起使用)是构建健壮的导航系统的好方法。它使得你的网站整体上看起来很整洁,而且使得深层章节很容易被访问。

他们通常结合水平,竖直或是选项卡导航一起使用,作为网站主导航系统的一部分。

出式菜单和下拉菜单导航的一般特征
用于多级信息结构
使用JavaScript和CSS来隐藏和显示菜单
显示在菜单中的链接是主菜单项的子项
菜单通常在鼠标悬停在上面时被激活,而有时候也可能是鼠标点击时激活


出式菜单和下拉菜单导航缺点
除非你在主导航链接边上放置一些标识(通常是箭头图标),不然访客可能不知道那有包含子导航项的下拉或出式菜单,因此使这些标识很明显是非常重要的。同时出式菜单和下拉可能使得导航在移动设备上非常难用,所以要确保你的移动样式表处理了这种情况。

 

何时使用出式菜单和下拉菜单导航
如 果你想在视觉上隐藏很大的或很复杂的导航层次,出式菜单和下拉是很好的选择,因为它让用户决定他们想看见什么,以及什么时候可以看见它们。它们可以用来在 不弄乱网页的情况下按需显示很大数量的链接。它们还可以用来显示子页面和局部导航,并且不需要用户首先点击打开新的页面。

分面/引导导航
分面/引导导航(也叫做分面检索或引导检索)最常见于电子商务网站。基本上来说引导导航给你提供额外的内容属性筛选。假设你在浏览一个新的LCD显示器,引导导航可能会列出大小,价格,品牌等选顶。基于这些内容属性,你可以导航到匹配你的条件的项。

引导导航在拥有巨大数量货物的大型电子商务网站中是非常宝贵的。用户通过直接搜索通常很难找到他们想要的东西,并且增加了用户漏掉一个产品的或能性。例如他们可能搜索一个灰褐色的产品,但你可能将它标记了灰色或褐色,虽然它可能就是用户想要的东西。

分面/引导导航的一般特征
最常见于电子商务网站
通常让用户对不同的特征做多次筛选
几乎总是使用文字链接,分解在不同的类别下或是下拉菜单下
常常与面包屑导航一起使用
分面/引导导航的缺点
引导导航可能会引起一些用户的迷惑。另外不能保证用户会在你预先定义的类别中查找。

何时使用分面/引导导航
分面导航对于大型电子商务网站非常有用。它方便了用户购物,提升了购物体验,并更容易找到它们真正想要的东西。它也可以用于其它目录风格的网站。

页脚导航
页脚导航通常用于次要导航,并且可能包含了主导航中没有的链接,或是包含简化的网站地图链接。

访客通常在主导航找不到他们要找的东西时会去查看页脚导航。

页脚导航的一般特征
页脚导航通常用于放置其它地方都没有的导航项
通常使用文字链接,偶尔带有图标
通常链接指向不是那么关键的页面
页脚导航的缺点
如果你的页面很长,没有人愿意仅仅为了导航而滚动到页面底部。对于较长的页面,页脚导航最好作为重复链接和简要的网站地图的地方。它不适合作为主导般形式。

何时使用页脚导航
绝大多数网站都有这样那样的页脚导航,即使它只是重复其它地方的链接。考虑什么放在那有用,以及你的访客可能最想找什么。

结论
大 多数网站使用不只一种导航设计模式。例如一个网站可能会用顶部水平栏导航作为主导航系统,并使用竖直/侧边栏导航系统来辅助它,同时还用页脚导航来作冗 余,增加页面的便利度。当选择你的导航系统基于的导航设计模式时,你必须选择支持你的信息结构以及网站特性的方案。导航是网站设计的重要部分,它的效果必 须有坚实的基础设计。