YUI在IE浏览器里DOM元素加载很快的时候window.onload执行的要比domready快。这个执行顺序的问题应该算是一个bug,但是在jQuery我做个类似的实验,发现jQuery里没有类似的问题。

对这个问题确实比较好奇,看了看YUI2和jQuery关于DOM ready实现的部分源码。在IE实现DOM Ready基本都是用Diego Perini提出的方法:http://javascript.nwbox.com/IEContentLoaded/

但是jQuery的开发者已经意识到IE浏览器有时存在onload执行的比DOM Ready快的问题,因为这样确实会出现风险。jQuery是这么解决的,我节选了部分解决这个问题的jQuery代码(版本-1.4.2):

DOMContentLoaded = function() {

if ( document.readyState === “complete” ) {

document.detachEvent( “onreadystatechange”, DOMContentLoaded );

jQuery.ready();

}

};

document.attachEvent(“onreadystatechange”, DOMContentLoaded);

YUI没有这样做,我估计是因为效率问题,上面的代码虽然让domready执行的比window.onload快,但是因为绑定了onreadystatechange事件,效率会低一点。

而jQuery采用了更加安全的策略,慢就慢一点,安全一点更重要。如果在使用YUI2的时候确实遇到了这个安全问题,我们也可以牺牲一点效率,修改一下YUI的源码。

终于搞清楚了,又是一个需要权衡的问题。

但是我也抛出一个我没有想明白的问题,YUI2里面为什么不去尝试

document.documentElement.doScroll(‘left’);来判断domready,而是先要在超空间先创造一个p节点,然后再doScroll,domready以后再把这个p节点清空掉,这样做有什么好呢?为什么不采用jQuery和Diego Perini的做法呢?个人觉得创造一个p节点,再释放掉效率更低呀。

JavaScript框架比较:实用函数 [zt]

Posted April 27th, 2010. Filed under JavaScript

实用函数

许多JavaScript框架都带有大量的实用函数,这些函数使得应用JavaScript开发应用程序更加容易。这篇文章有太多内容需要补充,所以我将讨论大多数框架中更为引人注目的函数中的一个。

如果你曾经使用过JavaScript数组,你可能对使用循环来迭代数组操作其值非常熟悉。例如,想想清单2的代码:

清单2:迭代JavaScript数组的传统方法

var fruit = ['apple', 'banana', 'orange'];
for(var i = 0; i < fruit.length; i++) {
alert(fruit[i]);
}

清单2中的代码没错,但有点麻烦。大多数JavaScript框架包括each功能,它为数组中的每一个元素调用一个特定的函数。使用MooTools,用清单3中的代码可以完成清单2中相同的操作。

清单3:使用MooTools的each函数

['apple', 'banana', 'orange'].each(function(item) {
alert(item);
});

清单3中在语法上与Prototype和jQuery是相同的,YUI 和 ExtJS.略微不同。但是,当应用到hash或对象时,不同的框架语法是不同的。例如,在MooTools中,你可以使用下面清单中的代码:

清单4:对键/值对的各个对象使用MooTools的each函数

var hash = new Hash({name: "Joe Lennon", email: "<a href="mailto:joe@joelennon.ie">joe@joelennon.ie</a>"});
hash.each(function(value, key) {
alert(key + ": " + value);
});

但是,使用Prototype库,这看起来就像清单5的代码:

清单5:对键/值对的各个对象使用Prototype的each函数

var hash = $H({name: "Joe Lennon", email: "<a href="mailto:joe@joelennon.ie">joe@joelennon.ie</a>"});
hash.each(function(pair) {
alert(pair.key + ": " + pair.value);
});

每个框架包含了许多更实用的函数,通常分为String函数、 Number函数、Array函数、Hash函数、 Date函数等等。要了解更多信息,请参阅相关JavaScript框架的API手册。

JavaScript框架比较:DOM操作 [zt]

Posted April 27th, 2010. Filed under JavaScript

DOM操作

在此之前,你已经看到JavaScript框架使用选择器和DOM遍历可以很容易的获得特定的元素。但是,为了改变网页上特定元素的内容和外观,你需要操作DOM并应用改变。使用纯粹的JavaScript将是一件繁重的工作,但幸运的是,大多数JavaScript框架提供有用的函数,可以很容易地做到这些。

假设你有一个ID为the-box的盒子。

<div id="the-box">Message goes here</div>

使用jQuery将其文本改变为“Message goes here”,可以很简单的这样使用:

$('#the-box').html('This is the new message!');

事实上,你可以在函数中使用HTML代码,它能被浏览器解析,例如:

$('#the-box').html('This is the &lt;strong&gt;new&lt;/strong&gt; message!');

在本例中,DIV元素中的内容看起来像这样:

<div id="the-box">This is the <strong>new</strong> message!</div>

当然,在实例中你需要使用大于或小于等特殊字符,而不是指定特殊的HTML实体代码。你可以使用jQuery的text函数来代替:

$('#the-box').text('300 &gt;200');

div元素更新后代码如下:

<div id="the-box">300 &gt; 200</div>

在上面的例子中,现有的内容被替换为新的内容。如果你只想给文本附加一些信息该怎么办?幸运的是,jQuery提供append函数达到此目的。

$('#the-box').append(', here goes message');

对原始的div作如上操作后,div元素里的内容看起来是这样的:

<div id="the-box">Message goes here, here goes message</div>

除了追加,你可以在前面追加内容,将其插入到现存内容的前面而不是后面。此外,jQuery提供的函数可以在给定元素内插入内容,要么在前要么在后。还有函数替换内容、清空内容、移除元素、克隆元素等等。

除了DOM操作函数外,JavaScript框架通常还包含几个函数操作元素的样式和class。例如,你有一个表格,当鼠标经过时高亮显示某行。你可以创建一个特殊的类名hover,你可以将该类动态的添加到某行。利用YUI你可以使用下面的代码判断该行是否拥有hover类名,有则免之,无则加之。

if(row.hasClass('hover')) row.removeClass('hover'); else row.addClass('hover');

同样,大多数JavaScript框架都拥有操作CSS的内置函数。

JavaScript框架比较:DOM遍历 [zt]

Posted April 27th, 2010. Filed under JavaScript

DOM遍历

基于ID、元素类型、类名查找元素非常有用,但是如果你想基于它在DOM树中的位置来查找元素该怎么办?换句话说,你有一个给定的元素,你想查找它的父元素、子元素中的一个、它的上一个或下一个节点兄弟节点。例如,采用下面这段零碎的HTML代码:

清单1:HTML碎片(一个table)

<table>
<thead>
<tr>
<th>Name</th>
<th>Email Address</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr id="row-001">
<td>Joe Lennon</td>
<td>joe@joelennon.ie</td>
<td><a href="#">Edit</a>
                <a href="#">Delete</a></td>
</tr>
<tr id="row-002">
<td>Jill Mac Sweeney</td>
<td>jill@example.com</td>
<td><a href="#">Edit</a>
                <a href="#">Delete</a></td>
</tr>
</tbody>
</table>

tml”>
清单1使用缩进来说明其中每个元素节点在DOM树中的位置。在这个实例中,table元素是根元素,有两个子节点thead和tbody。thead元素有一个tr子节点,tr有三个孩子--所有的th元素。tbody元素有两个tr子节点,每个tr节点有三个孩子。在上述每一行的第三个节点中进一步包含子节点,都是两个链接标记。

正如你知道的那样,你可以使用一个JavaScript框架的选择函数通过ID很轻松的选择一个元素。在这个实例中,有两个元素拥有ID,它们是ID分别为row-001和row-002的tr元素。使用Prototype库选择第一个tr,可以使用下面的代码:

var theRow = $('row-001');

在上一章,你还了解到,基于元素的类型或class使用选择器来获取元素。在这个实例中,你可以使用下面的语法来得到所有的td元素。

var allCells = $$('td');

改代码的主要问题在于它返回了每一个td 元素。但是,如果你只想得到ID为row-001的tr的所有td元素该怎么办?这正是DOM遍历函数发挥作用的地方。首先,让我们使用原型来选择ID为row-001的tr的所有的子级。

var firstRowCells = theRow.childElements();

这将返回theRow变量(你最初设置的ID为row-001的tr)所有子元素的数组。

接下来,我们假设你只想得到该行的第一个子元素。在本例中,即包含“Joe Lennon”文本的td元素。要做到这一点,使用下面的语句:

var firstRowFirstCell = theRow.down();

真简单!这个特定的使用方法等价于:

var firstRowFirstCell = theRow.childElements()[0];

也可以这样表示:

var firstRowFirstCell = theRow.down(0);

JavaScript的索引从零开始,所以上面的语句主要告知JavaScript来选择第一个子元素。要选择第二个子元素(单元格包含电子邮件地址joe@joelennon.ie),你可以这样用:

var firstRowSecondCell = theRow.down(1);

或者,你可以在兄弟节点之间浏览DOM。本例中,第二个单元格是第一个单元格的下一个兄弟节点。因此,你可以使用下面的语句:

var firstRowSecondCell = firstRowFirstCell.next();

与down()函数工作一样,选择第三个单元格可以这样使用。

var firstRowThirdCell = firstRowFirstCell.next(1);

除了使用索引来查找特定节点外,Prototype库还可以使用CSS选择器语法。在清单1中,我们要找到第二个包含 Jill Mac Sweeney’ 详细信息的链接(“删除”链接)。

var secondRowSecondLink = $('row-002').down('a', 1);

在本例中,使用$函数来查找ID为row-002的那一行,向下遍历到第二个后代a元素(锚点)。

一些框架还允许“菊花链式”的遍历功能,这意味着你可以彼此连接遍历命令。上面的例子中,Prototype库的另一种表达方式是这样的:

var secondRowSecondLink = $('row-002').down('a').next();

看看下面的例子:

var domTraversal = $('row-001').down().up().next().previous();

正如你所见,菊花链允许你连接多个DOM遍历语句。事实上,上述例子实际上最终选择ID为row-001的tr元素,所以菊花链又回到了开始的地方。

javascript 实现1000阶乘算法

Posted April 22nd, 2010. Filed under JavaScript

<html>
 <head>
 </head>
 <body>
  <div id=”show”></div>
 <script>
  function ride(x, y){
   var re = /(\d{4})/g,
     x1 = x.toString(),
     y1 = y.toString(),
     s  = ”,
     sl = ”,
     ln = 0,
     tl = 0,
     tx = [];
     
   x1 = x1.replace(re, ‘$1,’);
   x1 = x1.replace(/\,$/, ”);
   
   tx = x1.split(‘,’);
   ln = tx[tx.length - 1].length;
   
   
   //分段乘法运算, 转换成整型
   for( var i = 0, l = tx.length; i < l; i++ ){
    tx[i]= tx[i]*y1;
   }

   s  = tx[tx.length - 1].toString();
   if( tx.length > 1 && s.length > ln ){
    tx[tx.length-2] += ( s.substring(0, s.length – ln) * 1); 
    tx[tx.length-1] = s.toString().substring(s.length-ln);
   }

   //进位运算
   for(var i = tx.length – 2; i >0; i–){
    if(tx[i] >= 10000){
     tx[i-1] += Math.floor(tx[i]/10000);
     tx[i]   = tx[i]%10000;
    }
   }

   //补零运算
   for( var i = tx.length – 2; i > 0; i– ){
    if( tx[i] < 1000 ){
     for(var k1 = 0, k2 = 4 – tx[i].toString().length; k1 < k2; k1++ ){
      tx[i] = ‘0′ + tx[i];
     }
    }
   }

   return tx.join(”);
  }

  function lev(n){
   var s = 1, r= ”;

   for( var i =1; i <= n; i++ ){
    s = s.toString().replace(/(0*)$/,”);
    r += RegExp.$1;
    s=ride(s, i);
   }

   s+=r;
   return s;
  }
  
  var t1 = new Date().getTime();
  document.getElementById(’show’).innerHTML = ‘1000阶乘:<br />’ + lev(1000);
  document.getElementById(’show’).innerHTML += ‘<br /><br />总耗时= ‘ + (new Date().getTime() – t1) + ‘ ms’;

 </script>

</body>
</html>