之前可以这样写
$('[href=#hash]')
现在必须这样写
$('[href="#hash"]')
其它属性选择器,如 attr^="#value" 等,也一样。
之前可以这样写
$('[href=#hash]')
现在必须这样写
$('[href="#hash"]')
其它属性选择器,如 attr^="#value" 等,也一样。

原创不够,译文来凑。
跟上篇一样是编译,不准备逐字翻。比如,我会把“we”译成“jQuery官方团队”,或者“他们”。
正文开始。
(初译版,待校正)
歪果仁也要双喜临门,于是 jQuery 官方团队选在 jQuery 面世10周年之际发布 3.0 beta。大家还记得上周发布的1.x和2.x小版本更新吧,他们日后会继续维护这俩分支,一段时间,当然只改bug。因为3.0才是未来嘛!
需要支持IE6-8的可怜虫请继续使用1.12分支上的最新版。

看过 alpha 发布公告的同学可能还记得,他们起初准备同时发布3.0和“3.0兼容版”,适配老浏览器。但是现在他们想通了。微软今年1月12日宣布放弃IE8910,jQuery 会保守一些,不过至少不打算支持IE8,所以就放弃所谓的兼容版,以后就只有一个版本了。
尽管大版本号发生变化,jQuery 团队仍然认为升级不会太麻烦。大变化是有,不过影响应该没有很大,而且他们还开发了3.0专用迁移插件,可以帮助我们找到代码中的兼容性问题。所以,请尽早使用新版本,并及时将体验反馈给他们,这样才能让jQuery 越来越好。
你可以直接通过CDN使用:
https://code.jquery.com/jquery-3.0.0-beta1.js
https://code.jquery.com/jquery-3.0.0-beta1.min.js
或者用NPM安装到本地
npm install jquery@3.0.0-beta1
接下来就是需要关注的新功能、升级、以及 Bug 修正了。完整列表见于 Github。
.show() 和 .hide()刚启动3.0的时候,他们尝试将这两个方法修改为“删除行内 display:none 样式”(.show())和 “增加行内 display:none 样式”(.hide())。这样可以极大的简化实现所需的代码,并且显著改善性能(计算量大幅下降了嘛)。但是,这给广大用户带来了不小的麻烦,因为移除 display:none 很多时候并不能让元素显示出来,比如有其它CSS将它置为隐藏。最终 jQuery 团队不得不承认没有办法完成期望中的简化。
于是他们放弃了这次尝试。不过,即便如此,他们还是想办法改善了隐藏大量元素时的性能。
.data() 的注意事项为了兼容 HTML5 dataset 规范,jQuery 团队升级了 .data() 实现。如今所有的 key 都会从短线连接(a-bc-de)转换成驼峰式(aBcDe),数字不再转换。于是,“foo-bar”转换后和“fooBar”是一样的,但“foo-42”和“foo42”就不一样。当用户直接使用 .data() 取所有数据时,就需要注意这个区别,尤其不要再误用 .data('foo42') 取代 .data('foo-42')。
Promise 我用的比较少,看到的文档也不多,不太清楚里面的几个名词怎么翻译,所以我尽量用括号备注。
jQuery.Deferred 得到升级,兼容 Promises/A+ 和 ES2015 Promises,并且已经通过 Promises/A+ Compliance Test Suite 认证。这意味着 .then() 的使用机制发生了非常显著的变动:
.then() 回调函数里抛出的异常,会成为失败(rejection)处理函数的参数。之前,异常会冒泡,中断函数执行,并永久性锁死上下级 Deferred 对象。.then() 返回的 Deferred 对象,如果它的回调函数抛出异常,将会调用失败(rejection)处理函数,并作为参数传进去;如果返回其它不能继续 .then() 的对象,就会调用成功(fulfillment)处理函数,返回值也作为参数传进去。以前,失败处理函数返回任何值都会将其置为失败。以下代码演示当上级 Deferred 触发 rejected 时,下级调用失败回调函数之后的结果:
var parent = jQuery.Deferred();
var child = parent.then( null, function() {
return "bar";
});
var callback = function( state ) {
return function( value ) {
console.log( state, value );
throw new Error( "baz" );
};
};
var grandchildren = [
child.then( callback( "fulfilled" ), callback( "rejected" ) ),
child.then( callback( "fulfilled" ), callback( "rejected" ) )
];
parent.reject( "foo" );
console.log( "parent resolved" );
在 jQuery 3.0 中,会先输出“parent resolved”,然后再执行回调函数;然后下级 Deferred 进入失败状态,执行函数,返回“bar”;“bar”被转化为三级 Deferred 的成功,于是输出“fulfilled bar”;接着,抛出错误“baz”,导致三级函数进入错误处理;最后,输出“rejected baz”。如果是之前的版本,下级 Deferred 会认为上级 Deferred 失败,进入错误处理,输出“rejected bar”;并且在未捕获的错误“baz”被抛出后,整个进程立刻被终止;此时,由于三级函数未处理完,“parent resolved”也不会输出。
捕获异常不仅对在浏览器里调试有帮助,在失败后的回调函数中处理它们,也使得代码更加直观合理。请谨记,这也意味着使用 Promise 模式的时候,要至少设置一个函数处理失败。不然的话,所有错误都会被忽略掉。
如果你还想使用以前的代码,可以用 .pipe() 函数替换 .then()。后者虽然已经被标记为不建议使用,但它接口一样,而且会暂时延续之前的逻辑。
我们还开发了辅助调试调试 Promises/A+ 的工具。如果你觉得有些错误好像没触发出来,可以试用之。
jQuery.when 函数也升级了,现在可以传入任何支持 .then() 的对象,包括原生 Promise 对象。
https://github.com/jquery/jquery/issues/1722
https://github.com/jquery/jquery/issues/2102
.catch() 方法Promise 对象增加 .catch()方法, 作为 .then(null, fn) 的别名,专门处理失败。
jQuery.ajax 的 Deferred 同名方法的特殊用法jqXHR 是 Promise 对象,同时也有一些专有方法,比如 .abort(),用于取消请求。
现在,越来越多的开发者已经在异步中(如AJAX)使用 Promise 模式,如此一来,jQuery.ajax 返回的对象再包含特殊用法就不合时宜了。
success, error, complete(这些将被移除)
done, fail, always(这些应该会保留)
需要注意的是,那些继续存在的回调函数不会有任何变化,只有 Promise 的方法会受影响。
有时候我们难免会想:“window 的偏移值(window.offset)是多少?”等你回过味儿来你会发现这个问题其实挺蠢的,window 怎么会有偏移呢?
过去,jQuery 面对这种情况,从来不会抛出错误,而是尽量返回有意义的值,比如刚才那个问题,就返回 { top: 0, left: 0 }。3.0之后,他们尝试不再什么乱七八糟的代码都兼容,而是直接抛出错误,让用户不要忽略这些问题。大家可以试用 beta 版,看看你的代码有没有“参数无效”之类的错误。
.width(),.height(),.css('width'),.css('height')都将返回小数之前,jQuery 取宽高的时候会返回四舍五入之后的整数值。有些浏览器可以返回次像素,比如 IE 和 Firefox,有些用户需要这些精细的数据来调整布局。jQuery 官方团队认为这项变化对大多数人没有影响,不过如果你受此困扰,也请告知他们。
jQuery 1.8之后弃用的 .load,.unload,.error 方法被正式移除。以后都请使用 .on() 注册事件侦听器。
requestAnimationFrame 改善动画效果新版 jQuery 在支持 requestAnimationFrame 的平台上会自动使用它来改善性能。除去 IE9 和 低于4.4的Android,都可以藉此让动画效果更平滑,占用更少的CPU时间,降低移动设备的电力损耗。
其实 jQuery 团队几年前就曾尝试使用这项技术,但是当时遇到很严重的兼容性问题,以致于不得不放弃。如今他们采用新策略,当浏览器 tab 不显示时挂起动画,这样就可以规避大部分问题。不过这样一来,那些必须依赖动画全局实时播放的功能就无法实现了。
.unwrap( selector )3.0之前,.unwrap() 方法不接受任何参数。如今,用户可以通过传入选择器来移除指定的外部容器。
jQuery.fn.domManip 不能再使用了1.12 和 2.2 版本把 jQuery.dir,jQuery.sibling,jQuery.buildFragment,jQuery.access,和 jQuery.swap 都修改为私有函数。现在,jQuery.fn.domManip 也一样。它们未来都只允许内部使用,不会被载入使用文档。官方团队认为这样做可以避免用户困惑。
https://github.com/jquery/jquery/pull/2182
https://github.com/jquery/jquery/issues/2224
https://github.com/jquery/jquery/issues/2225
拜 Paul Irish 在 Google 的工作所赐,新版 jQuery 可以躲过一些坑,比如前文提到的 :visible,通过减少冗余代码,获得了17倍的速度提升!
但用户仍需小心,即便经过优化,:visible 和 :hidden 选择器仍然会消耗大量的系统资源,因为它们需要浏览器检查元素是否显示在页面上。在最坏的情况下,有可能需要重新计算全部 CSS 样式和页面布局!当然也不是说不要用(不然还写它做甚),只是记得测试一下,看有没有因此导致性能问题。
这项工作他们 1.12/2.2 时就完成了,只不过拿到这里来说。

本文编译自官方博客,不是照字翻译。
新年新气象,jQuery 团队于昨日发布了两个新版本:1.12 和 2.2。这两个版本都包含了大量的Bug修正和功能改进。基本上这会是3.0之前最后一次发布。不过由于3.0不做向下兼容,所以届时 jQuery 团队仍然会继续维护这两个版本,当然肯定只做Bug修正。关于3.0的消息将在不久之后公布。
那么新版本都有些什么变化呢?
此版本缩短了 Sizzle 的引用路径,这样当原生 querySelectorAll 和 matchesSelector 无法使用时,可以带来性能提升。在生产环境中效果明显。
小升级很多,这里只拣要紧的说。
作为 HTML 库,支持 SVG 元素是理所应当的。新版本里大家就可以使用 .addClass() 、 .removeClass() 、 .toggleClass() 、 .hasClass() 操作 SVG 对象的 class 了。不过需要注意的是,因为 SVG 和 HTML 还是有很多不同,所以如果真的要进行复杂操作,还是选用其它更专业的类库比较好。
如题:
jQuery.post({
url: “/example”
});
这样一来好处还比较多,比如设置回调函数的 context,或者跨域 post 时可以 withCredential: true。
支持 ES6/ES2015 引入的新运算符, jQuery 对象可以用 for-of 遍历了。
for (element of $elements) {
console.log(element);
}
jQuery.htmlPrefilter()HTML5不要求标签必须闭合,但是XML要求。这个函数就是用来作转换的。这样我们使用 .html() 、 .append() 、.replaceWith() 时就不需要人工转换了。进而,我们也就不需要那么严格的校验输入了。
jQuery.uniqueSort()jQuery.unique() 命名有点问题,没能体现排序,所以这次新增了 jQuery.uniqueSort()。它们俩其实是一回事儿,不过文档中将只记录后者。
这个函数仍然专注于 DOM 节点的排序和排重,请勿乱用。
这个版本理论上没有太大变化,可以平滑升级。不过如果谁还是脸黑遇到什么问题,也请汇报给官方。
就不一一翻译了,想了解的可以看原文:jQuery 2.2 and 1.12 Released

HTML5中提供了跨域加载数据的方法,让我们得以从JSONP或者Flash中介等各种绕行方案中解脱出来,更加顺畅地与服务器交流。另一方面,因为PHP是最好的语言……所以在它与Node.js之间,我选择前者作为后端语言开发内容服务。
这篇文章记录使用jQuery+PHP开发跨域应用时的小心得。
做身份验证,最简单的办法就是使用PHP的SESSION保存用户信息,于是就要用到Cookie。默认情况下,跨域Ajax请求发起时候不包含Cookie,需要我们主动将XHR的withCredentials属性设为true才行。
jQuery会把XHR封装成jqXHR,并且不暴露真正的XHR(说实话这点有点难以理解,尤其是在做上传进度条的时候)。然后它提供一个给真正XHR赋值的接口xhrField,所以写成代码就是这样事儿的:
$.ajax(url, {
xhrField: {
withCredentials: true
}
}
如果不需要验证用户身份,直接在HTTP头中输出Access-Control-Allow-Origin: *即可。
我的产品需要验证,那么首先,HTTP头中必须有Access-Control-Allow-Credentials: true;此时对域的限制也严格许多,不再允许像前面那样使用*放开给任何来源,必须指明哪个具体域可以接受。
关于Access-Control-Allow-Origin的值,规范中的说明是“域名列表或null”,然则接下来的“注意”有点诡异:“实际生产中,‘列表或null’要求更严格。你可以认为它实际只允许单一域名或null,而非空格分隔的域名列表。”——既然如此你干脆写个“域名或null”不就完了……
总之对于我们而言,返回的HTTP头中还要包含Access-Control-Allow-Origin: http://域名,指定允许作为来源的协议、域名、端口,并且只能有一个(组)。因为通常来说我们开发环境和生产环境不一样,所以这里的域名最好不要写在服务器配置里;使用PHP,通过$_SERVER['HTTP_ORIGIN']取出访问来源,与白名单比对,通过后再输出相应的头,更加合适。
我选择JSON作为前后端交流的格式。为了方便浏览器解析(也是HTML5的要求),我还返回了Content-type: application/json头。
使用PHP少不了使用Xdebug。出现错误时,Xdebug会返回完整的栈,有利排查。但是为了方便阅读,Xdebug还会给返回信息套上<table>结构,这时Chrome的Network工具就会把它解析成奇怪的格式,所以Content-type一定要最后和数据一起返回。
与之相反的是前文说到的Access-Control-Allow-Origin和Access-Control-Allow-Credentials,这二位必须放在最前面。不然如果出现500错,响应头不包含这两个跨域标记,Chrome就会理所当然地不显示返回内容,也就无法看到错误描述,根本无法排查。
尼玛折腾了一早上,居然这样写会导致事件无法触发:
var script = document.createElement('script');
script.src = 'somefile.js';
script.onload = function () { console.log('xx'); };
$('head').append(script);
最后一句换成纯js就解决了:
document.head.appendChild(script);
正如我在前一篇文章《前端框架点评》中所说,jQuery UI库中最有用的是那几个 xxxable,而不是里面的组件(因为自带样式且较丑)。所以当它们在某些环境下没法正常工作就比较老火了,比如draggable,在iPad之类的移动设备中,就无法使用,因为它没有针对触摸事件进行侦听。
经过Google,发现有人已经解决了这个问题,就是我说的jquery-ui-touch-punch,开源,代码托管在github。直接在html中引用jQuery UI和这个补充包,后者会覆盖前者的实现,帮助它支持触摸拖动。感兴趣的同学可以到这个页面去尝试。感谢它的作者furf。
顺便说下我对开源、免费、盗版的态度。开源和免费都是好东西,影响着改变着我们的世界。但是决定一个作品一段代码一款产品是否开源免费的人,只能是其作者或者其版权拥有者,别人无权“替”他们做出选择。换句话说,我是反盗版的,对于海盗湾也无甚好感,对于那些有意无意忽视盗版危害反而替海盗湾摇旗呐喊的人,很是反感。
现在的版权政策和专利制度,确实在某种程度上阻碍着创新,也给流氓(比如苹果)留下可乘之机。但是在更好的方案出台之前,我们只应该尽力输送好的原创作品给开源社区,而不是盗版他人的东西,再冠以自己“开放、分享”之名。那样太无耻了。


jQuery托管事件是个好东西,减少侦听器的数量,还能降低内存泄露的风险,尤其在列表类的应用比较常见。
想象一个如右图所示的下载列表,点击各列表项会展开详情,用户可以在里面查看详细信息;不展开的话也可以直接点击右边的下载按钮,就会直接下载应用。使用jQuery来写代码大概是这样的:
$('#app-list li').on('click', function (event) {
// 显示/隐藏详情
$(this).toggleClass('active');
});
$('#app-list .download-button').on('click', function (event) {
// 下载通过超链进行
// 这时为了不让详情展开,需要阻止事件冒泡
event.stopPropagation();
});
假如列表里有20个选项,那么这样就会添加40个侦听器。在PC浏览器里这样做问题不大,但是移动设备内存比较少的话可能会引发问题。另外,如果我们还引入了“上拉读取更多”和“下拉刷新”的功能,那么就要为内容的更新添加更多的代码,以避免内存泄露。所以这时,就应当将事件托管到ul去处理。( 关于jQuery事件托管可以参考其文档(http://api.jquery.com/delegate/)。)
$('#app-list').on('click', 'li', function (event) {
$(this).toggleClass('active');
});
$('#app-list').on('click', '.download-button', function (event) {
event.stopPropagation();
});
可以看到,我没有修改事件处理函数。这样做,我们只添加了2个侦听器,并且不管#app-list里的内容如何变化,都不需要重新注册侦听器。这给代码减了不少负。
不过接下来我发现,点击按钮后,详情仍然会被展开收起,似乎阻止冒泡的代码没有生效。仔细一想,对了,我已经把事件注册到#app-list上了,所有的事件其实都是冒泡上来的,所以点击按钮,冒泡必然经过上层节点。于是继续修改代码,改变事件处理函数的逻辑:
$('#app-list').on('click', 'li', function (event) {
// 如果事件始于下载按钮,则退出
if ($(event.target).is('.download-button')) {
return;
}
$(this).toggleClass('active');
});
这样便万事大吉了。
不支持命名空间一直是JS开发里比较严重的问题。不过大家想出了各种手段来绕过这个坎,比如YUI的namespace。可惜的是jQuery尚未提供一个合适的解决方案,不过这并不难,可以人肉给它添加这个方法。稍加搜索,找到两个地址介绍此方法,附在最后。
jq用的很多,有天闲来无事在jq官方网站上闲逛,偶然发现他们还做了一套自己的组件库,并且提供多种不同的皮肤,甚至支持自行搭配输出特定组合的组件库。于是赶忙试用,发现效果非常不错。
jqui继承了jq一贯的简单实用,涵盖绝大部分可能用到的功能,比如拖拽、排序、缩放、各种效果;并且提供各种功能的demo,使用的时候看一遍demo找到想要的功能然后直接查看源码,简单方便。比如我想让某个窗体可以通过顶部进行拖动,只需要$(‘#window).dragable(‘.titlebar’);即可。
不过resizable就必须容器有ui-widget-content这个class才行。