Front-end web developer——[to be a better man]
文章字体大小Font Size文章字体大小:12px, 14px

Archive for 八月, 2008

26

Steve has write an article about faster javascript trim . He had collected many implementations of trim in javascript, and take a test to find the most efficient approach. At last, he wrote a new implementation and it is the fastest!

This article it’s great . And I found this is a very interesting subject. I was stuck on it. But Steve didn’t show up the testing codes, so I build one, with the codes here.

My Testing Page:

In this page, you’ll see three textarea at the top of page. Those are Template String list. The methods are all from faster javascript trim.

About Template String:

The string there is including the same leading whitespace and the same trailing whitespace. and these whitespace is including several kinds of characters like \s,\t,\n,\u3000.

In Firefox and opera, these whitespace are all match by \s, but not in IE. In IE, It is different from \u3000 and \s , So I replace all the \u3000 to \s in IE in order to make all the trim methods can work fine.

You can see the details of the temlate strings by making a simple test. Just double on the method or string list to start , or the start button too.

From the detail column of the result table, you’ll see something like this:

[\s28][有限状态机[...]平稳流畅。][\s61].length(898)

What does this mean? From the left to right, they are the length of leading whitespace, the trimed string, the length of trailing whitespace and the total length of the string before triming.

About the String List:

By the name of the string, you will see what the main different they are. And they are all from the template string area, so you can change them too. For example, the _shortStr and _longStr is from the first template string textarea. The different is, the _shortStr is just one time of the template string, but the _longStr 100 times of it.

Notic: the _bigWhiteSpaceStr string is real a big white leading and trailing space, and the length are 28,028 and 61,061!

Thank you.

This is a javascript practice for me,you can right click and view the page resrource any time. And I am still learning how to make codes better and better, please leave a reply if any suggestions, Thank you!

Popularity: 68% [?]

26

CSS3的强大,让人惊叹,人们在惊喜之余,又不得不为其艰难的道路感到可惜:好的标准只有得到行业浏览器的良好支持才算得上“标准”。CSS3标准已提出数年,但是目前能实现她的浏览器并不多,虽然部分浏览器能实现部分规范,但这又有什么用呢?面对更多的兼容性问题,CSSer们只有望洋轻叹。虽然如此,但有前瞻性的我们,又怎能停步不前呢?今天我们就来“前瞻”一下CSS3的一个伪类选择器“:nth-child()”

语法:

:nth-child(an+b)

为什么选择她,因为我认为,这个选择器是最多学问的一个了。很可惜,据我所测,目前能较好地支持她的只有Opera9+和Safari3+。

描述:

伪类:nth-child()的参数是an+b,如果按照w3.org上的描述,写成中文,很可能会让人头晕,再加上笔者的文笔水平有限,所以我决定避开an+b的说法,把它拆分成5种写法共5部分来说明。

第一种:简单数字序号写法

:nth-child(number)

直接匹配第number个元素。参数number必须为大于0的整数。 阅读全文(Read the rest of this entry) »

Popularity: 61% [?]

16

Iframs很多时候,我们会需要改变一个iframe的地址(src属性),或者使用表单(form)的target在指定的iframe进行提交后,在iframe加载完毕(onload)时立即响应某个操作,以提高WEB应用程序的价值。本文讨论了跨浏览器的iframe onload事件的监听方法。

如果你没时间去阅读全文,可以看解决方案的内容概要:

  1. 同域的页面嵌套,最好的是让内嵌的页面调用父页面的函数,如 window.parent.callparentFunctoin()。
  2. 如果是异域,或者子页面已存在且无法修改,那么:在Firefox/Opera/Safari中,可以直接使用iframe onload事件;而在IE中,可以通过定时器测定子页面的document.readyState,或者使用iframe onreadystatechange事件计算该事件的响应次数。

以上内容基于参考文档: Q239638Q188763.

如果你对这个话题很感兴趣,请一定要继续阅读哦。。。

注[1]:为了使问题更集中,本文所述的<iframe>均直接写在父页面中,对使用document.createElement(“iframe”)或者其它方式建立的iframe不作讨论,因为这样会使问题在IE下变得更加复杂,但只要使用本文的结论,无论何方式下建立的iframe,问题仍然会得到解决。

一个简单的包含iframe的父页面将是如下样子的:

<!DOCTYPE ...>
<html xmlns="...">
  <head>
  <meta ... />
  <title>Iframe</title>
  <body>
    <iframe name="iframe1"  id="iframe1" width="300" height="50" src="#" ></iframe>
    <script type="text/javascript">//codes here</script>
  </body>
</html>

开始:

让我们从一种简单的情形和解决方法开始:

1.window.parent 对象

1.1 调用父页面对象

<!–This is an inner page in the iframe–>
<script type=”text/javascript”>
window.onload=function{ window.parent.iframeCall();}
</script>

在网上找到的方法中,最令人开心的一个,莫过于在能子页面中调用父页面的对象了:

window.parent.callFunciton()。

不过我想:可能这点全地球人都已经知道了。只是这个方法有一个缺点,那就是子父页面必须在同域中。

还有一点,就是前端工程师们需对子页面有修改权;或者,可以请负责此子页面的同事为我们添加一段代码:

<script type=”text/javascript”>
if(window.parent!=window) window.parent.iframeCall();
</script>

把它放到window.onlad中,或者直接放在</body>之前。

注[2]:在对iframe或其它窗口性质的前端编程中,同域名是最完美的先天条件。只要在同一域名中,各个窗口间的对象是共享的,我们完全可以自由发挥,在不同的窗口间来回驾驭。总之,只有想不到,没有做不到。

1.2 异域

在不同域名的页面,浏览器出于安全考虑,几乎完全封锁了页面间的对象来往,这里没有鹊桥,牛郎和织女只能远远想望。当然,用iframe嵌套页面还是可以的,毕竟还可以思念。

面对家族的封锁,罗密欧还是很想见朱丽叶,他在夜里架起梯子抓到朱丽叶的窗前与她见面;在异域的页面嵌套中,子页面总是可以直接改变父窗口的location以防止被嵌套,但父页面对这个一点办法也没有。

当然,子页面除了仅仅永恒地拥有父窗口.location的修改权外,也没有其它了。例如,在IE下,子页面只能直接修改父页面的.location为另一个源:

<script tyle=”text/javascript”>parent.location=”http://anotherPage.com/”;</script>

但无法访问其它对象,如window.name,document等,连location.href等location的子属性就无法访问。当然,在防止嵌套方面,使用top.location会更强大。

但Firefox中,似乎还可以为top.location添加一些东西,但这是在我不严谨的测试中出现过的情况,未经找到相应的权威文档哦。

2. iframe onload 事件

在Firefox/Opera/Safari中,直接使用frame元素的onload事件即可:
document.getElementById(“iframe1”).onload=function(){
//your codes here.
};
只可惜它在IE下经常无效,因为在IE下它最多只能被激活一次,而且无论你有多少个iframe,被激活的也只能是最后一个的。更详细的描述请看:Q239638Q188763

原因
这些事件是在IFRAME内的文档对象模型中激活的,而不是父页面的。在IFRAME加载完毕的时候,这个事件就被激活了,而且ReadyState已经是“完成”状态。所以你无法通过这个事件来查检一个IFRAME是否加载完毕。

为了得到更好的表现,我们再稍稍研究一个问题:IFRAME递归。

3.IFRAME 递归

在处理IFRAME时,浏览器应该有一个基本规则,那就是防止递归,防止页面无限的自我加载,使客户端设备崩溃。事实上,文中出现的几个浏览器均做到这点,只是不同的浏览器有不同的处理方式。请分别尝试以下代码:
<iframe src=”” onload=”finish()” name=”iframe1”></iframe>
<iframe src=”#hashonly” onload=”finish()” name=”iframe2”></iframe>
<iframe src=”?search” onload=”finish()” name=”iframe3”></iframe>
<iframe src=”http://anotherPage.com” onload=”finish()” name=”iframe4”></iframe>
执行的结果是,在父页面加载时,上面的iframe onload函数在IE/Opera/Safari中均会被激活,Firefox对第二个没有反应。这主要因为他们在防止递归方面的处理是不同的。
对于#hashonly和?search这样的URL,浏览器会解释为页面本身。但hash和search的不同之处是,改变 search可以组成新的源,而改变hash不会。通常地,浏览器一遇到同源的iframe内页即会停止加载,但Safari却会加载多一次。
假如把finish()函数写成如下:
var finsh=function(){alert(”onload from :”+this.src);}
运行时分别弹出的消息弹出框的次数如下:

ifm/brw:    IE    |    Firefox    |    Opera    |    Safari
iframe1:    1     |       1       |      1      |      0
iframe2:    1     |       0       |      1      |      1
iframe3:    2     |       1       |      2      |      2
iframe4:    1     |       1       |      1      |      1

再结合页面所呈现的内容,可得看出这些浏览器在处理递归问题上的一些细则:

  • Firefox 不会在iframe中加载任何东西和激活onload事件(可能是任何事件)
  • IE和Opera不会在iframe中加载页面,但会激活onload事件。
  • Safari(windows版本)会在iframe中加载页面一次且仅仅一次,并会激活onlaod事件且仅激活依附在父页面上那个iframe的onload事件。

关于本节,如果仅把iframe用于页面嵌套,那意义不大;如果用于动态加载/呈现内页,或者用于良好用户体验的form target表单提交处理(不是Ajax),并且要求较高的浏览器兼容性时,作用才会显示出来。根据本节结果,为了提高兼容性,最好事先把iframe指向一个空页面——blank.html,因为它在4种浏览器中的表现是一样的。如果不想事先加载页面,那就得花多点心思去判断浏览器类型了。

4.代码实现

4.1Firefox/Opera/Safari,直接使用iframe onload事件

document.getElementById(“iframe1”).onload=function(){
    //your codes here.
};

4.2在IE下,定时器测document.readyState或者注册iframe onreadystatechange事件

4.2.1定时器以及document.readyState

var fm1=window.frames["iframe1"];
var fmState=function(){
  var state=null;
  if(document.readyState){
    try{
      state=fm1.document.readyState;
    }catch(e){state=null;}
    if(state=="complete" || !state){//loading,interactive,complete
      //onComplete();
      return;
    }
    window.setTimeout(fmState,10);
  }
};
//在改变src或者通过form target提交表单时,执行语句:
if(fmState.TimeoutInt) window.clearTimeout(fmState.timeoutInt);
fmState.timeoutInt = window.setTimeout(fmState,400);

为什么要延时400毫秒?因为javascript对DOM的操作是异步的,我们必须等待脚本对DOM落实执行后才开始下一步。400秒这个数取决与客户端的设备和浏览器的响应速度,好的设备的响应速度能在10毫秒以内甚至更快,但100毫秒左右可能比较大众化,400毫秒应该是十分保守的了。总之,较大的毫秒数能适合更多的用户设备状况,并能减少了客户端设备的工作量。

至于document.readyState,指的是iframe内子页的docuent.readyState,而不是父页面的。只要允许,即在同域情况下,document.readyState会返回5个状态:

uninitialized 对象未初始化.
loading 对象正在加载数据.
loaded 对象已加载完数据.
interactive 在这个状态下,用户可以参与互动,即使在对象未加载完毕也可以
complete 对象已完成初始化.

为什么使用try和 catch?因为在异域的情况下,当iframe的子页到达interactive状态时,父页面就会失去访问权,所以最多只能返回到loaded这一步,因此IE出一个未知错误——其实就是没有权限,所以try和catch,让这个错误沉默下去。

幸好这个方法只针对IE(目前我能使用到的版本:IE6/7),否则麻烦大了:Opera不等页面加载完就开始交互了,而IE会等页面加载完毕才进行交互,所以感觉用Opera打开网页的速度相对比IE快。

4.2.2.onreadystatechange 事件三步曲

var stateID={};
var fmStChange=function(){
  if(ifFirstLoad) return;
  stateID[this.id]=stateID[this.id] ? stateID[this.id]+1:1;
  switch (stateID[this.id]){
    case 1:
      //state loading
      //onComplete(STEP1);
      break;
    case 2:
      //state interactive
      //onComplete(STEP2);
      break;
    case 3:
      //state complete
      //onComplete(LASTSTEP);
      break;
  }
  if(stateID[this.id]&gt;=3) stateID[this.id]=null;
};
$("iframe1").onreadystatechange=fmStChange;
//if you want to ignore the parent page load
//add the following two line
var ifFirstLoad=true;
$("iframe1").onload=function(){ifFirstLoad=false;}

每当iframe加载页面,过程内会激活onreadystatechange事件三次,相应的状态分别是loading,interactive和complete,而最后一次才是complete,所以我们得计算一下,直到第三次才算是完成。

注意:这个方案中的stateID在状态判断时非常重要,要进行必要的修正和保护,如在每次应用iframe时,把stateID[iframe_id]复位为null,或者在第三次响应完成之前,不要对iframe进行新轮页面加载,或者在新一轮的页面加载前消除之前的事件并复位。

Popularity: 77% [?]

12

http://flickr.com/photos/andallthatmalarkey/301121794/

关于CSS选择器优先级,目前国内已有很多人进行过解释,但感觉不如人意,特别对于初学者,更是难以理解。这里我把W3C上所描述的规范以我的理解再解释一下,希望能给大家提供到帮助。

Calculating a selector’s specificity上的原文摘选如下:
(相信很多人更喜欢看原文)

A selector’s specificity is calculated as follows:

  • count 1 if the declaration is from is a ’style’ attribute rather than a rule with a selector, 0 otherwise (= a) (In HTML, values of an element’s “style” attribute are style sheet rules. These rules have no selectors, so a=1, b=0, c=0, and d=0.)
  • count the number of ID attributes in the selector (= b)
  • count the number of other attributes and pseudo-classes in the selector (= c)
  • count the number of element names and pseudo-elements in the selector (= d)

The specificity is based only on the form of the selector. In particular, a selector of the form “[id=p33]” is counted as an attribute selector (a=0, b=0, c=1, d=0), even if the id attribute is defined as an “ID” in the source document’s DTD.

Concatenating the four numbers a-b-c-d (in a number system with a large base) gives the specificity.

Example(s):

Some examples:

 *             {}  /* a=0 b=0 c=0 d=0 -> specificity = 0,0,0,0 */
 li            {}  /* a=0 b=0 c=0 d=1 -> specificity = 0,0,0,1 */
 li:first-line {}  /* a=0 b=0 c=0 d=2 -> specificity = 0,0,0,2 */
 ul li         {}  /* a=0 b=0 c=0 d=2 -> specificity = 0,0,0,2 */
 ul ol+li      {}  /* a=0 b=0 c=0 d=3 -> specificity = 0,0,0,3 */
 h1 + *[rel=up]{}  /* a=0 b=0 c=1 d=1 -> specificity = 0,0,1,1 */
 ul ol li.red  {}  /* a=0 b=0 c=1 d=3 -> specificity = 0,0,1,3 */
 li.red.level  {}  /* a=0 b=0 c=2 d=1 -> specificity = 0,0,2,1 */
 #x34y         {}  /* a=0 b=1 c=0 d=0 -> specificity = 0,1,0,0 */
 style=""          /* a=1 b=0 c=0 d=0 -> specificity = 1,0,0,0 */

============

CSS优先级的读法

这里先更正一些错误的读法。通过百度搜索到的内容中,通常出现这样的写法:(1,0,0,0),但有部分文章对它的解释不全面,有的甚至有误。

其中最大的一个错误就是把结果加:(1,0,0,0)=1000,(0,0,2,2)=22,更有甚者:(0,1,0,1)=0+1+0+1=2!虽然这些理解在很简单的情况下看上去是正确的,但本质上却是个重大的错误。

另外有部分文章把它理解为4个级别,也相近,但不能把条理分清楚,理解起来也难。

“CSS优先级包含四个级别(文内选择符,ID选择符,Class选择符,元素选择符)以及各级别出现的次数。根据这四个级别出现的次数计算得到CSS的优先”级。

这句话总结得很好,但对初学者来说,在理解方面就有点难度了,“四个级别”,太容易混淆,其实应该是“四组级别”。

我认为,对优先级的读法,应该是以“组”来分,这个组之间相互独立,从左到右进行对比。它们成组出现,以逗号分隔。

  selector( a , b , c , d )
   compare: ↑ , ↑ , ↑ , ↑
  selector( a , b , c , d )

正如w3c.org中原文所示,分为a,b,c,d四组,全为正整娄,默认为0,对应于不同的选择器结构和组成形式。在选择器之间的优先级进行对比时,从左到右1对1对比,当比出有大者时即可停止比较。

 li.red.level  {}  /* a=0 b=0 c=2 d=1 -> specificity = 0 , 0 , 2 , 1  */
       /*compare                                       ↑ , ↑ , √      */
 h1 + *[rel=up]{}  /* a=0 b=0 c=1 d=1 -> specificity = 0 , 0 , 1 , 1  */
       /*compare                                       ↑ , ↑ , ↑ , √  */
 ul ol li.red  {}  /* a=0 b=0 c=1 d=3 -> specificity = 0 , 0 , 1 , 3  */
       /*compare                                       ↑ , ↑ , √      */
 #x34y         {}  /* a=0 b=1 c=0 d=0 -> specificity = 0 , 1 , 0 , 0  */
       /*compare                                       ↑ , √          */
 style=""          /* a=1 b=0 c=0 d=0 -> specificity = 1 , 0 , 0 , 0  */

(上表中,表示还要进行比较,表示从此处已得到了结果)

其实这里就像个奥运金牌榜,到我修改文章为止(2008-08-12),我国以13金领先,详细如下:

1 中国 13 3 4
2 美国 7 6 8
3 韩国 5 6 1
4 意大利 3 4 2

.

再有,只要正确书写,仅从优先级中大概知道选择器结构形式了,如:

1,0,0,0表示是元素内的style;

0,2,1,1表示是一个由两个ID选择器,1个类或伪类或属性选择器,以及一个元素选择器组成的选择器。

CSS优先级规则的细节:

在纠正读法后,才能开始讲详细的规则:

  • a组数值只有把CSS写进style属性时才会为1,否则为0.写进style的样式声明其实不算是个选择器,所以这里面的b,c,d组值均为0,只有真正的选择器才会有b,c,d组值。
  • b组数值决定于ID选择器#ID,有多少个ID选择器,并会进行此组数值累加;
  • c组数值决定于类、伪类和属性选择符,并会进行该组数值累加;
  • d组数值决定于元素名,即元素选择器,并会进行该组数值累加;

注意,这四组数值分别对应于不同类型的选择器,互不影响,根据读法法则进行比较。

(这里没有讨论到!important,就近原则和继承,也没有实例代码,欢迎大家共同讨论!)

参考:

[1] CSS优先级问题

[2]Calculating a selector’s specificity

Popularity: 49% [?]