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

javascript

Oct 11

我找到一个非常不错的水平滑动菜单的javascript特效:Horizontal JavaScript Accordion 1kb。我曾经把它应用到好些制作的页面上,但我的需求越来越多,所以情况也比Michael的样例复杂多了,而且,我需要更多的可选选项,就像这样的:

l found Horizontal JavaScript Accordion 1kb and it is very great! I have ever planted it in some pages. But my App is more complicated then the Michael’s demo. And it need to be more optional.
link this:

通过改变物件的宽度去实现像风琴一样的水平滑动是最常用的方法。不过我的是通过改变物件的left位置,并且提供了更多的可选选项,但脚本文件会大一点,达到了8.46kb。还有,我用面向对象的方式编写的,所以可以不用iframe,就可以实现一个页面中有多个风琴滑动效果菜单了。这就有一个简单的样例:

Making horizontal sliding with changing the width of each panel is the most normal way. But my one is by changing the left style of each panel, and it is more optional, but the file is a bit larger: 8.46kb. And it is programmed in OO way, we can have more instances in a page without iframe.Here is a simple demo:



The codes are:

<ul id="hslidemenu" >
<li><img src="images/1.gif" alt="" /></li>
<li><img src="images/2.gif" alt="" /></li>
<li><img src="images/3.gif" alt="" /></li>
<li><img src="images/4.gif" alt="" /></li>
</ul>

And the javascript:

HSlideMenu("hslidemenu").build();

下载:
Download:
hslidemenu.js
hslidemenu-plug.js
点击这里看完整的简介!
Click here to see the full introduce page!

Popularity: 31% [?]

Sep 01

rame onload event is not a good idea to listening child page loading state on Internet Explorer. Here are some solutions to make things better.

None-Cross-Domain

If the parent page and the child page is in the same domain, they can share the objects between the windows. For example: “window.parent.document.getElementById(’div_01′)” will be fine. So we can easily get things done. Just like this:

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

Cross-Domain

According to REFERENCES Q239638 and Q188763, there are two ways:

1.Timer & 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);
  }
};
window.setTimeout(fmState,400);//call this statement when iframe page start to change

A few microseconds is need, because DOM actions is asynchronous, we need to wait until the action has started.

2.onreadystatechange & counting state

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;}

The process will return three types of state: loading,interactive and complete. But don’t disturb the loading process untill one is finished, or else the stateID will not tell the correct state .

document.domain property

An article said document.domain property will be use to fix “Access Denied Error”:

The document.domain property can be set to ease the restriction somewhat.For example, if a document at www.example.com wants to communicate with a document at forums.example.com, the document.domain property could be set to example.com in both documents to allow JavaScript interaction between them.

I never try out, but I don’t think this will work.

None-IE

Iframe onload event is good for Firefox, Opera and Safari.

Popularity: 61% [?]

Aug 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: 62% [?]

Aug 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: 73% [?]

Jul 29

Javascript的每个Function对象中有一个apply方法:

function.apply([thisObj[,argArray]])

此外,还有另一个很极之相似方法:

function.call([thisObj[,arg1[, arg2[, [,.argN]]]]])

他们的共同之处是,都“可以用来代替另一个对象调用一个方法,将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。”——摘自JScript5.5 .chm

她们的不同之处是,apply最多只能有两个参数——新this对象和一个数组,如果给该方法传递多个参数,则把参数都写进这个数组里面,当然,即使只有一个参数,也要写进数组里面。而call则是直接的参数列表,对比如下: 阅读全文(Read the rest of this entry) »

Popularity: 64% [?]

Jul 22

在Javascript前端编程中,使用过Prototype.js的人,会知道,只要使用一个简单的语句:

$("msg").hide();

就可以把id为msg的元素隐藏;同样的,$("msg").show()则可以把隐藏的元素显示出来。像这种对元素的扩展,是怎样做出来的呢?

在说明这个问题之前,先问一个问题:为什么要这样做?

为什么要对DOM element进行扩展?

如果你在Javascript编辑中,不使用任何库,即祼编去实现一些说大不大说小不小应用时,相信你一定会事先$一下:

var $=function (s){
return typeof(s)=="string" ? document.getElementById(s) : s;
};

或者更简单的

function $(){return document.getElementById(s);}

这样一来可以加快你写代码的速度,二来可以为页面节省不少字节。

但如果我们还需要很多对DOM的操作,而且这些操作具有一定的复杂性重用,需要分离出来,如对属性className的操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
rmCls=function(el,_c){// the full name is removeClassName
    el=$(el);if(!el) return null;
    var c=el.className.split(" "),str="";
    for(var i in c){if(c[i]!=_c) str+=" "+c[i];}
    el.className=str;
    return el;
},
adCls=function(el,c){// the full name is addClassName
    el=$(el);if(!el) return null;
    this.rmCls(el,c).className+=" "+c;
    return el;
},
hasCls=function(el,_c){// the full name is hasClassName
    var el=$(el),c=(el.className || "").split(" "), l=c.length;
    while(l--){if(c[l]==_c) return true;};
    return false;
};

当然,我们也可以直接使用$(”msg”).className=”on”来操作,但这对存在多个类名的元素来说就不那么便利了。但现在也不太便利,因为我们要把元素也写到参数中:
adCls($("msg"),"on");
如果可以这样似乎会更清爽些:
$("msg").adCls("on");
阅读全文(Read the rest of this entry) »

Popularity: 64% [?]

Apr 30

A CION HAS TWO SIDES.

“一枚硬币有两个面。”

这句话通常用于说明事物有两面性。Javascript的闭包也一样。

所谓的闭包(Closure):

所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。

闭包是 ECMAScript (JavaScript)最强大的特性之一,但用好闭包的前提是必须理解闭包。闭包的创建相对容易,人们甚至会在不经意间创建闭包,但这些无意创建的闭包却存在潜在的危害,尤其是在比较常见的浏览器环境下。如果想要扬长避短地使用闭包这一特性,则必须了解它们的工作机制。而闭包工作机制的实现很大程度上有赖于标识符(或者说对象属性)解析过程中作用域的角色。 (From 《理解Javascript闭包》)

问题所在: 阅读全文(Read the rest of this entry) »

Popularity: 69% [?]

Apr 06

UPDATE:20080530最新修改
为了研究Currying in Javascript,翻阅了很多外文网站,为的是找一个比较好的Currying方案,找到的比较详细的有如下(文章内部链接可能包含更多的相关文章):

  1. Currying JavaScript Functions
  2. JavaScript Currying Redux
  3. JavaScript currying
  4. functional.js 介绍及源码分析

发现大多人都用了Array.prototype.slice.call(argments,0),一直不明白这句是干什么的。而昨天温习了slice()方法,再参考Function.call(thisArg[, arg1[, arg2[, ...]]]),还是不得而知(我脑筋转得慢:|)。上网查,第一时间查老外的Google.com in English也没解释,真到查找“Array.prototype.slice 用法”时,才得到数篇。虽然我很鄙视搞收集的人,搞得互联网文章像是天下一大抄似的,但现在却恨少,只得三篇(一模一样的三篇,责任编辑为admin或者超级管理员,作者是佚名。)

下面就我的理解,对Array.prototype.slice.call进行解说,菜鸟留下,大虾吐口水:
Update: 下面写的可能有点难懂,怕刚接触Javascript的人可能会看不懂,请大家看完后留个言,谢谢!

Array.prototype.slice.call(thisArg[, arg1[, arg2[, ...]]])

成员介绍:

Array [object]

Array对象(即数组对象)

prototype [property]

Javascript的原型,此prototype非Prototype.js,可以暂且理解为Java中的静态属性/方法。总之这个不好说,详细请看这里

slice [Function]

数组切分方法,很有用的一个方法,具体请看这里,或那里

call [Function]

神奇的方法,该方法是所有Function对象里的方法,所以slice就有这样一个方法。用于把Function对象里的this替换为目标对象。看这里

串起来就是: 阅读全文(Read the rest of this entry) »

Popularity: 95% [?]

Apr 05

为了研究Currying in Javascript,所以温习一下slice()方法。

Array.slice(begin[,end])

该slice方法返回数据的指定区段。该slice方法不会改变原始的数组,返回的是一个全新的数组拷贝,而不是原始数组引用,所以无论是改变原始数组还是新数组,双方均不受影响。该slice方法通过由零开始计算的数组下标来确定切割的部分,创建一个由下标begin开始,到下标end-1止的新数组(如果end未被指定,默认为最后一个元素)。如:
代码:

1
2
trees = ["oak", "ash", "beech", "maple", "sycamore"]
document.write(trees.slice(1,4))

输出:
ash,beech,maple
阅读全文(Read the rest of this entry) »

Popularity: 58% [?]

Apr 02

  很喜欢幻采版的鲜果订阅按钮,

会随着节日变换不同风格,而且还有节日倒计时,提醒你即将来临的快乐日子!

用下面的代码就可以实现“订阅到鲜果”功能(具体的代码生成方法请到这里):

<a target='_blank' title='订阅到鲜果 RSS阅读器' href='http://www.xianguo.com/subscribe.php?url=yourRSSAddress'><img src='http://www.xianguo.com/icon/sub.php?t=big' border='0' alt='鲜果阅读器订阅图标' /></a>

我有一个建议:为图片链接加上时间戳。

http://www.xianguo.com/icon/sub.php?t=big&date=YearMonthDay
  因为 阅读全文(Read the rest of this entry) »

Popularity: 64% [?]

Pages: 1 2 Next