写一个更好的Javascript DOM库

389 查看

目前,jQuery是事实上的操作文档对象模型(DOM)的库。它可以与流行的客户端MV*框架结合使用,并且拥有大量的插件与大型的社区。开发者对于Javascript的兴趣与日俱增的同时,很多人开始好奇,原生的API是如何工作的,以及我们何时应该直接使用它们而不是引用一个额外的库。

最近,我开始发现越来越多的jQuery的问题,至少是在我的使用中是这样的。其中的绝大多数涉及到jQuery的核心,在不取消向后兼容的情况下无法解决——而向后兼容又非常重要。与很多人一样,我继续使用了它一段时间,每天浏览所有讨厌的浏览器怪异模式。

后来, Daniel Buchner创造了SelectorListener,于是有了“live扩展(live extensions)”的概念。我开始考虑创造一系列的函数,使得我们可以使用比迄今为止用过的方法都更好的方式来创建非干扰性的DOM组件。目标是回顾已有的API与解决方案,并创造一个更干净、可测试且轻量级的库。

向库添加有用的特性

是live扩展的想法鼓励我开发了better-dom项目,不过,还有一些其他的有趣的特性使得它成为一个独特的库。我们快速地看一下:

  • live扩展
  • 原生的动画
  • 内置的微模板
  • 国际化的支持

live扩展

jQuery有一个叫做“live事件(live events)”的概念。借助事件代理,它使得开发者可以处理现有的以及未来的元素。但是许多情况会要求更大的灵活度。比如为了初始化一个部件而需要对DOM进行转换,事件代理就会力不从心。故而,live扩展。

目标是,只需定义一次扩展并使得所有未来的元素快速略过初始化函数,而无论部件的复杂度。这个很重要,因为它使得我们可以声明式地开发web页面,从而在AJAX应用中表现优异。

new-feature-with-jquery
Live扩展使得你无需调用初始化方法就可以操作未来的元素

我们来看一个简单的例子。假设我们的任务是实现一个完全自定义的提示框。:hover 伪类选择器并无帮助,因为提示框的位置随着鼠标移动而变化。事件代理也不是很合适;监听文档树中所有元素的mouseover 及mouseleave 事件代价很大。live扩展将拯救你!

我们可以在CSS中定义 .custom-title 元素的样式:

当你向页面中插入一个带title 属性的新元素时,最有趣的部分发生了。自定义的提示框无需调用任何初始化方法即可生效。

live扩展是独立的;这样它们并不需要为了使得未来的内容生效去调用一个初始化方法。因此它们可以与任何DOM库结合使用,将UI代码分割成许多小的独立的块,从而简化应用的逻辑。

最后,同样很重要的,一些关于Web组件的内容。规范的一部分,“装饰器” ,意在解决类似的问题。目前,它使用了一种基于标记的实现,通过特殊的语法,将事件监听者绑定到子元素上。但它仍只是早期的草案:

“装饰器,与Web组件的其它部分不同的是,它还没有一个规范。”

原生动画

多亏了 Apple, CSS现在拥有了对动画的良好支持。过去动画通常使用Javascript的setInterval 及setTimeout实现。这曾经是很酷的特性——但是现在看来,它更像是坏的实践。原生的动画总是更平滑:常常更快,开销更小,并且在浏览器不支持的情况下可以很好地降级。

better-dom中,没有animate方法:只有show, hide 以及toggle。库使用基于标准的aria-hidden属性来在CSS中获取一个隐藏元素的状态。

为了说明它是如何工作的,我们来为先前介绍的提示框添加一个简单的动画效果:

show() 以及hide() 在内部将 aria-hidden 属性值设置为false或true。这使得CSS可以处理动画与转换。

你可以在这个demo中看到更多使用了better-dom的动画。

内置的微模板

HTML字符串冗长而繁琐。寻找替代的过程中我发现了超棒的Emmet。如今Emmet已经是一个非常流行的文本编辑器插件,它拥有漂亮而简洁的语法。比如这段HTML:

与对应的微模板比较: