十一月 26, 2006

很多时候我们讲window.onload事件上面挂接一个function,以为这样就万事大吉了,以为在页面加载完成之后我们的function被正确执行了。

其实以上经验只有一半是正确的,因为在某种情况下,onload函数执行的时机与我们料想的不一样,甚至会有很多偏差。

对于一个<img>标记过多的页面来说,其实onload函数会在所有img都加载完成之后才开始执行,不信就看看这个测试页面

正如测试页面的执行结果,我们的window.onload函数如果工作在<img>比较多,而图片加载比较缓慢的情况下时,效果是非常不理想的,因为在图片没有加载完成之前,可能页面上的所有功能都无法正确完成,这是个比较严重的问题。

还好,已经有聪明人想到合理的解决方案,就是 Andrea Giammarchi的OnContent函数。

具体的实用方法以及最终效果,在这个例子页面上面已经说的非常清楚了,我就不在多讲了。

这个方案确实不错,被这个问题困扰的我总算找到答案了,在找寻答案的途中,发现一些有趣的东西,大家也应该看看:

Technorati : , , ,

发现一个非常有用的javascript URL parser,只要传入一个符合规则的url链接,马上就能使用这个parser的对应方法,拿到相应的信息。

很有用的东西,大家可以试试,省的自己解析url里面的很多东西了,文档如下:

var p = new Poly9.URLParser(’http://user:password@poly9.com/pathname?arguments=1#fragment’);
p.getHost() == ‘poly9.com’;
p.getProtocol() == ‘http’;
p.getPathname() == ‘/pathname’;
p.getQuerystring() == ‘arguments=1′;
p.getFragment() == ‘fragment’;
p.getUsername() == ‘user’;
p.getPassword() == ‘password’;

p.setURL(’another.url.com’);
p.getHost() == ‘another.url.com’;
p.getProtocol() == ”;

p.setURL(’dsdsad’); // throws an exception

当然也不能忘了这个感谢这个东西的作者,大家应该去Poly9获得更多的信息。

Technorati : ,

十一月 23, 2006

以前写过一片post是讲js跨站点通讯的,自觉似乎没有整理清楚,接下来重新整理一下。

javascript 使用xmlhttp对象无法cross domain进行请求已经成了尝试,可是很多时候还是需要跨站点进行数据传输。比如google personal homepage的widget可以放在任意的外部站点上正常工作,看似神奇,其实也就是利用了ajax patterns 里面将的一种叫做 script ondemand的技术实现的,使用这种技术进行跨站点通讯的核心原理是:

  1. http://a.com/a.html中的javascript向当前页面的<head>标记里面写入一个<script>标记,这个标记的src属性指向需要进行数据请求的http://b.com/data.php页面,于是浏览器便会向该地址发送加载脚本的请求
  2. 此时b.com的data.php页面就返回一段包含了客户端js回调函数与返回数据的脚本,让该脚本执行原先在a.com的a.html种事先写好的回调函数,并将数据传给该函数

客户端javascript代码如下:

XSSRequest = { 

	stack_callback : {},

	request : function(url,callback){

		var cid = this._generateGuid();
		var func_cb = callback || function(){};
		url += ( url.match(/?/) ? '&' : '?')
			+ 'requestId=' + cid
			+ '&callback=XSSRequest.response;

		var stackObj_cb = {};
		stackObj_cb.requestId = cid;
		stackObj_cb.function_callback = func_cb;
		stackObj_cb.url = url;

		this.stack_callback[cid] = stackObj_cb;

		var s = document.createElement('script');
		s.type = 'text/javascript';
		s.src = url;
		document.getElementsByTagName('head')[0].appendChild(s);

	},

	response : function(requestId,responseObj){

		if(this.stack_callback[requestId]){

			(this.stack_callback[requestId].function_callback)(responseObj);
			delete this.stack_callback[requestId];
		}

	},

	_generateGuid : function(){
		var hex =
			new Array(
			'0','1','2','3','4','5','6','7','8', 				
                         '9','a','b','c','d','e','f');
		var outB = '{';
		for (count = 0; count < 32; count++){
			if ((count == 8) || (count == 12) || (count == 16) || (count == 20))
			outB += '-';
			outB += hex[ Math.floor(Math.random() * 16)];
		}
		return outB.toUpperCase() + '}';
	}

}

 

当调用XSSRequest.request(url,function(responseObj){})方法是,会产生一个形如http://b.com/data.php?requestId=xx-xx-xx&callback=XSSRequest.response的请求,之后服务器应该返回的字符串如下:

XSSRequest.response(’xx-xx-xx’,{});

后一个{}是返回数据的JSON对象。

如此一来,一个通用的cross domain 通讯框架就建立起来了,其次就是服务器端的支持了,这种简单的字符串输出相信任何一种语言都能胜任,不再赘述。

同时,大家可以比较一下,我构建的这个跨域通讯方案与这篇文档的方案哪个比较方便使用。

 

Technorati: , , ,

十一月 3, 2006

最近研究在Firefox下使用Media Player,发现一些问题,至今没有解决,不知道哪里能够找到合理的解释,大家提供一下。

在Firefox如果需要使用COM组件的话,需要下载一个Mozilla Active Plug-in,这个没有问题,但是在Firefox下使用Media Player需要处理PlayStateChange这个事件的话,着实费了一番周折,因为playerObj.addEventListener这样的写法,无法正确捕获事件,必须使用<script for=”playerObj” event=”PlayStateChange”>…</script>这样的方法,举个例子:

<![if !IE]>
  <script for=”wplayer” event=”PlayStateChange(newState)”>
  player._fireEvent(’onEngineStateChanged’,player.getState());
  </script>
<![endif]>

 这样写,是为了兼容Firefox的情况下,在IE下依旧使用attachEvent这样的原生解决方案来挂接事件.这样做以后,似乎我们已经可以正确的捕获事件了,可是问题才刚刚开始,因为在Firefox下面,每个PlayStateChange事件会重复触发4次,也就是说,我们在事件处理函数里面会重复4次得到同一个状态,这和IE是截然不同的。这就是在Firefox下处理ActiveX Object event的噩梦吗?

这样的问题出现在国内一个知名的网络音乐服务8Box中,使用Firefox听歌的时候,一首歌完成之后会向后跳4首歌,无法正确持续播放整个列表,原因是页面中的js相应PlayState code = 8(Media end)的时候接到连续4次event notification,正常的处理逻辑是Media end时向下跳一首歌,可是由于事件接受次数的异常,导致了这个原因,还有相同的问题也出现在每开始播放一首新歌的时候都会到服务器取4次歌曲的信息,呵呵,可能这个也是他们无法解决的问题吧。究竟怎样做才能雅观的解决这个问题呢?我可不想在响应每个状态的时候都使用一下计数器这种恶心的方法。

 

Technorati: , , , ,