jQuery最佳实践

2014-03-27 · 30 min read

本文介绍一些使用 jQuery 的通用标准和最佳实践,这些标准不涵盖 Javascript 的标准和最佳实践,英文原文地址是 http://lab.abhinayrathore.com/jquery-standards/

加载 jQuery#

1、尽量使用 CDN 加载:

<script type="text/javascript" src="ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>"
<script>window.jQuery || document.write('<script src="js/jquery-1.11.0.min.js" type="text/javascript"><\/script>')</script>

2、就像上面的代码一样,在 CDN 加载失败时,要回源到本地服务器的同版本 jQuery。

3、使用依赖协议的 URL(不加http:https:,直接使用//),参看上面的例子。

4、尽可能在页面底部加载 jQuery 和 javascript。

5、如何选择 jQuery 版本?

  • 如果要兼容 IE6/7/8,不要使用 2.x 版本的
  • 对于新的应用,如果不考虑一些插件的兼容性问题,尽可能的使用最新版
  • 从 CDN 加载 jQuery 的时候,使用完整的版本号(例如,使用 1.11.0,不用 1.11 和 1)
  • 不要加载多个版本的 jQuery

6、如果你使用了 Prototype, MooTools, Zepto 等,尝试使用jQuery代替$。可以使用$.noConflict()让出$的控制权。

jQuery 变量#

1、所有被缓存的 jQuery 对象,变量名以$开头。

2、总是缓存 jQuery 选择器返回的对象,方便复用:

var $myDiv = $("#myDiv");
$myDiv.click(function(){...});

3、使用驼峰命名。

选择器#

1、尽可能的使用 ID 选择器。ID 选择器使用document.getElementById(),所以更快。

2、当使用类选择器的时候,不要加 DOM 元素类型:

var $products = $('div.products') // 慢
var $products = $('.products') // 快

3、使用 find 查找 ID->Child 的嵌套查询,.find()方法更快,因为第一次选择没有使用 jQuery 的选择器引擎:

// 差, 全部使用jQuery的选择器引擎
var $productIds = $('#products div.id')

// 好, #products使用document.getElementById(), 只有div.id需要使用jQuery的选择器引擎
var $productIds = $('#products').find('div.id')

4、越靠右侧越具体:

// 差
$('div.data .gonzalez')

// 最佳
$('.data td.gonzalez')

5、选择器不要太“具体”:

$('.data table.attendees td.gonzalez')

// 更好,尽可能省去中间部分
$('.data td.gonzalez')

6、给选择器指定上下文(限定范围):

// 慢,因为它在整个DOM结构中查找
$('.class')

// 快,因为它只查找 class-container 下的.
$('.class', '#class-container')

7、避免使用“*”:

$('div.container > *') // 差
$('div.container').children() // 好

8、避免隐式使用“*”:

$('div.someclass :radio') // 差,还是用了“*”
$('div.someclass input:radio') // 好

9、不要使用多个 ID 选择器,或者嵌套使用 ID 选择器,单独的 ID 选择器使用document.getElementById(),速度很快:

$('#outer #inner') // 差
$('div#inner') // 差
$('.outer-container #inner') // 差
$('#inner') // 好, 调用 document.getElementById()

DOM 操作#

1、先把元素分离出 DOM 结构,再进行复杂的操作,之后再附加回 DOM 中。不明白原因的话,可以了解下.detach()这个方法

var $myList = $('#list-container > ul').detach()
// 对 $myList 执行大量复杂操作
$myList.appendTo('#list-container')

2、使用字符串连接或者 array.join(),少用.append(),点击这里查看性能比较。

// 慢
var $myList = $('#list')
for (var i = 0; i < 10000; i++) {
  $myList.append('<li>' + i + '</li>')
}

// 快
var $myList = $('#list')
var list = ''
for (var i = 0; i < 10000; i++) {
  list += '<li>' + i + '</li>'
}
$myList.html(list)

// 更快
var array = []
for (var i = 0; i < 10000; i++) {
  array[i] = '<li>' + i + '</li>'
}
$myList.html(array.join(''))

3、不要对不存在的元素做操作:

// 差: 在发现该ID不存在之前,已经执行了3个函数
$('#nosuchthing').slideUp()

// 好
var $mySelection = $('#nosuchthing')
if ($mySelection.length) {
  $mySelection.slideUp()
}

事件#

1、一个页面只使用一个 Document ready,便于调试和跟踪。

2、不要使用匿名函数绑定事件,匿名函数不利于调试,复用,测试,debug:

$("#myLink").on("click", function(){...}); // 差

// 好
function myLinkClickHandler(){...}
$("#myLink").on("click", myLinkClickHandler);

3、Document ready 不要用匿名函数,原因同上:

$(function(){ ... }); // 差: 你没办法写单元测试和复用

// 好
$(initPage); // or $(document).ready(initPage);
function initPage(){
    //...
}

4、Document ready 的处理函数应该写在外部文件,内联的 javascript 可以在一些初始化设置之后调用 ready 函数,例如:

<script src="my-document-ready.js"></script>"
<script>
    // 做一些初始化设置.
    $(document).ready(initPage); // or $(initPage); initPage函数在外部文件中
</script>

5、不要把事件直接写在 HTML 元素上,这样不方便调试:

<a id="myLink" href="#" onclick="myEventHandler();">my link</a>
<!-- 差-->
$('#myLink').on('click', myEventHandler) // 好

6、尽可能的给事件加上命名空间。这样方便解除绑定,而不影响该 DOM 元素的其他事件:

$('#myLink').on('click.mySpecialClick', myEventHandler) // 好
// 之后,很容易的解除绑定
$('#myLink').unbind('click.mySpecialClick')

AJAX#

1、使用.ajax(),避免.getJson()或者.get(),它们在内部也是调用.ajax()的。

2、不要在https的站点上请求http,使用依赖协议的 URL

3、不要把数据加在 url 上,使用 data 属性。

// 可读性差
$.ajax({
    url: "something.php?param1=test1&param2=test2",
    ....
});

// 可读性好
$.ajax({
    url: "something.php",
    data: { param1: test1, param2: test2 }
});

4、指定 dataType 属性,更容易知道数据类型。

5、对于 ajax 加载的内容,使用委托绑定事件,这样可以在元素不存在的时候执行绑定。(之后 ajax 加载进 DOM 结构中)

$('#parent-container').on('click', 'a', delegatedClickHandlerForAjax)

6、使用 Promise

$.ajax({ ... }).then(successHandler, failureHandler);

// 或者
var jqxhr = $.ajax({ ... });
jqxhr.done(successHandler);
jqxhr.fail(failureHandler);

7、抽象出 ajax 模板,方便复用:

var jqxhr = $.ajax({
  url: url,
  type: 'GET', // default is GET but you can use other verbs based on your needs.
  cache: true, // default is true, but false for dataType 'script' and 'jsonp', so set it on need basis.
  data: {}, // add your request parameters in the data object.
  dataType: 'json', // specify the dataType for future reference
  jsonp: 'callback', // only specify this to match the name of callback parameter your API is expecting for JSONP requests.
  statusCode: {
    // if you want to handle specific error codes, use the status code mapping settings.
    404: handler404,
    500: handler500,
  },
})
jqxhr.done(successHandler)
jqxhr.fail(failureHandler)

动画效果#

1、Adopt a restrained and consistent approach to implementing animation functionality(大意:采取受限制的和统一的方法来实现动画功能。)

2、满足用户体验即可,不要做过多的动画:

  • 尽量使用简单的 show/hide,slideUp/slideDown 来切换元素
  • 尽量使用 jQuery 预定义的时间间隔(durations),“slow”,“fast”或者 400(中等)

插件#

1、选择兼容性好,文档,测试齐全何社区支持好的插件。

2、检查插件在不同版本 jQuery 下的兼容性。

3、任何参加的可复用的组件,都应该以插件的形式实现。

链式调用#

1、使用链式调用代替变量缓存和多次调用选择器:

$('#myDiv').addClass('error').show()

2、当链式调用超过 3 级的时候,适当的换行增加可读性:

$('#myLink')
  .addClass('bold')
  .on('click', myClickHandler)
  .on('mouseover', myMouseOverHandler)
  .show()

3、链太长的时候,缓存中间对象是可以接受的。

其他#

1、参数尽量使用对象形式:

$myLink.attr('href', '#').attr('title', 'my link').attr('rel', 'external') // 差, 调用三次attr()
// 好, 调用一次
$myLink.attr({
  href: '#',
  title: 'my link',
  rel: 'external',
})

2、尽量不要把 css 混在 js 中:

$('#mydiv').css({ color: red, 'font-weight': 'bold' }) // 差
.error {
  color: red;
  font-weight: bold;
} /* 好*/
$('#mydiv').addClass('error') // 好

3、不要使用过时的方法,注意新版更新时弃用的方法,不要使用它们。

4、必要的时候使用原生 js,这里看查看性能对比  http://jsperf.com/document-getelementbyid-vs-jquery/3

$('#myId') // 还是有一点点点点慢...
document.getElementById('myId')

就这么多,技术有限,翻译的不妥的地方,欢迎留言指出!