12.6 高级属性操作

现在,相信读者对取得和设置DOM元素的值已经非常熟悉了。我们可以使用.attr().prop().css()等简单的方法,以及.addClass().css().val()等方便的快捷方法,还可以使用像.animate()这样封装了复杂行为的方法。不过,即便是简单的方法都在后台帮我们完成了很多工作。如果能够理解这些方法都在后台做了什么,那一定能够更好地利用它们。

12.6.1 简捷地创建元素

我们在jQuery代码中创建元素时经常会把HTML字符串传递给$()函数,或者传递给其他DOM插入函数。例如,为了创建多个DOM元素,我们在代码清单12-9中就创建了一个相当大的HTML片段。这种方法既快速又简洁。但有时候,这种方式也不是最理想的。比如,我们有时候需要在使用文本之前先转义其中包含的特殊字符,或者根据浏览器不同为它们应用不同的样式规则。在这些情况下,需要创建相应的元素然后连缀其他jQuery方法对它进行修改。这种技术前面我们已经用过好多次了。不过,除了这种标准的技术之外,$()函数还提供了一种很有吸引力的语法。

假设我们要在文档中的每个表格前面都加上一个标题。可以使用.each()循环每一个表格,然后为每个表格创建适当的标题,参见代码清单12-14。

代码清单12-14

  1. $(document).ready(function() {
  2. $('table').each(function(index) {
  3. var $table = $(this);
  4. $('<h3></h3>', {
  5. id: 'table-title-' + index,
  6. 'class': 'table-title',
  7. text: 'Table ' + (index + 1),
  8. data: {'index': index},
  9. click: function(event) {
  10. event.preventDefault();
  11. $table.fadeToggle();
  12. },
  13. css: {glowColor: '#00ff00'}
  14. }).insertBefore($table);
  15. });
  16. });

$()函数传递选项对象作为第二个参数,与先创建元素再将该对象传递给.attr()方法的结果是一样的。大家都知道,.attr()方法的作用是设置DOM属性,比如元素的id等。

不过,我们例子中的其他选项看起来可能会让人有点迷惑。我们在这里指定了:

  • 标题的文本内容;

  • 额外的数据;

  • 一个click处理程序;

  • 一个包含CSS属性的对象。

虽然这些并不是DOM属性,但同样可以一起设置。简写的$()语法之所以可以处理这些,是因为它首先检查是否存在给定名字的jQuery方法,如果是就会调用相应的方法,而不是设置相应的属性。

 鉴于jQuery为方法赋予了比属性名更高的优先级,因此我们必须自己注意那些容易存在歧义的情况。比如,<input>元素的size属性就不能以这种方式来设置,因为还有一个.size()方法存在。

简写的$()函数以及.attr()方法通过使用挂钩(hook),还能够处理很多额外的DOM属性。

12.6.2 DOM创建挂钩

通过定义适当的挂钩,可以扩展很多取得和设置属性的jQuery方法,从而满足某些特殊情况下的需要。这些挂钩实际上是jQuery命名空间中的数组,比如$.cssHooks$.attrHooks。一般来说,挂钩是保存着getset方法的对象,前者用于取得请求的值,后者的作用则是提供新值。

以下是其他几种挂钩。

挂钩类型修改的方法示例用法
$.attrHooks.attr()阻止元素的type属性被修改
$.cssHooks.css()Internet Explorer中的opacity进行特殊处理
$.propHooks.prop()纠正Safariselected属性的行为
$.valHooks.val()支持单选按钮和复选框跨浏览器报告一致的值

通常,这些挂钩所做的工作对我们而言是完全不可见的,我们不必知道它们都做了什么就可以利用它们提供的便利。但有时候,确实也需要添加我们自己的挂钩,从而扩展jQuery方法的行为。

编写CSS挂钩

代码清单12-14向页面中注入了一个名为glowColor的CSS属性。但此时的页面没有什么反应,因为这个属性根本不存在。不过,我们马上要扩展$.cssHooks,以便支持这个新造的属性。换句话说,我们要在某个元素设置了glowColor属性时,使用CSS3的text-shadow属性为该元素中的文本应用柔和发光效果。因为Internet Explorer不支持text-shadow,所以我们要使用微软专有的filter属性来实现同样的效果,参见代码清单12-15。

代码清单12-15

  1. (function($) {
  2. var div = document.createElement('div');
  3. $.support.textShadow = div.style.textShadow === '';
  4. $.support.filter = div.style.filter === '';
  5. div = null;
  6. if ($.support.textShadow) {
  7. $.cssHooks.glowColor = {
  8. set: function(elem, value) {
  9. if (value == 'none') {
  10. elem.style.textShadow = '';
  11. }
  12. else {
  13. elem.style.textShadow = '0 0 2px ' + value;
  14. }
  15. }
  16. };
  17. }
  18. else {
  19. $.cssHooks.glowColor = {
  20. set: function(elem, value) {
  21. if (value == 'none') {
  22. elem.style.filter = '';
  23. }
  24. else {
  25. elem.style.zoom = 1;
  26. elem.style.filter =
  27. 'progid:DXImageTransform.Microsoft' +
  28. '.Glow(Strength=2, Color=' + value + ');';
  29. }
  30. }
  31. };
  32. }
  33. })(jQuery);

一个挂钩由针对元素的get方法和set方法构成。为了保持我们的例子尽量简单,这里只定义了set方法。在定义挂钩之前,代码先行测试了某些属性是否能得到浏览器的支持。如果浏览器支持text-shadow,则使用该属性来定义挂钩。如果不支持,则检查它是否支持DirectX滤镜,并在支持的情况下使用相应的滤镜。如果浏览器这两种属性都不支持,那就不定义挂钩,因而glowColor也就不起任何作用了。

定义了这个挂钩之后,标题文本就有了2像素宽的绿色的发光效果,如图12-7所示。

12.6 高级属性操作 - 图1

图 12-7

虽然这个新挂钩让我们如愿以偿,但它仍然缺少很多应有的属性。下面列出了现在这个挂钩的几个不足。

  • 不能自定义发光效果的大小。

  • 这个效果只能使用text-shadowfilter实现,排斥其他方案。

  • 没有实现get方法,因此不能测试属性的当前值。

  • 不能基于这个属性实现动画效果。

再多做些工作,多写些代码,就可以解决上述这些问题。但在实际开发当中,其实并不经常需要定义自己的挂钩;有很多经验老到的插件开发人员已经创建了能够满足各种需要的挂钩,包括大多数CSS3属性。

 查找挂钩

插件的开发可谓日新月异,随时都可能有新的挂钩出现,因此我们不可能列出所有优秀的插件来。因此,我们这里仅向读者推荐Brandon Aaron开发的CSS挂钩:https://github.com/brandonaaron/jquery-cssHooks