<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>army8735 &#187; baidu</title>
	<atom:link href="http://army8735.org/tag/baidu/feed" rel="self" type="application/rss+xml" />
	<link>http://army8735.org</link>
	<description>我可以A，我也可以-A，我可以同时A和-A。</description>
	<lastBuildDate>Fri, 25 Nov 2011 04:07:52 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>百度global.js读后感 &amp; flash在ie6下的bug</title>
		<link>http://army8735.org/2009/05/15/54.html</link>
		<comments>http://army8735.org/2009/05/15/54.html#comments</comments>
		<pubDate>Fri, 15 May 2009 08:21:03 +0000</pubDate>
		<dc:creator>army8735</dc:creator>
				<category><![CDATA[前端开发]]></category>
		<category><![CDATA[baidu]]></category>

		<guid isPermaLink="false">http://army.512j.com/blog/?p=54</guid>
		<description><![CDATA[http://hi.baidu.com/ui/scripts/global.js
地址在上面，这里就不贴了，随后讲到哪里的话会贴下片段。可能以后baidu会变更，但也应该很容易找到。
这篇主要是我一时兴起写下的，达人级就不必看了。主要为了加深下印象，另外给公司的前端部门那几位瞅瞅。
&#8212;
/* declare  namespace */
(function(){
var namespaces = [ "System","BdElement",  "BdBrowser", "BdEvent", "BdUtil", "BdAjax","BdString"];
for(var i = 0, j = ...]]></description>
			<content:encoded><![CDATA[<p><a href="http://hi.baidu.com/ui/scripts/global.js" target="_blank">http://hi.baidu.com/ui/scripts/global.js</a></p>
<p>地址在上面，这里就不贴了，随后讲到哪里的话会贴下片段。可能以后baidu会变更，但也应该很容易找到。<br />
这篇主要是我一时兴起写下的，达人级就不必看了。主要为了加深下印象，另外给公司的前端部门那几位瞅瞅。<br />
&#8212;</p>
<pre class="brush:js">/* declare  namespace */
(function(){
var namespaces = [ "System","BdElement",  "BdBrowser", "BdEvent", "BdUtil", "BdAjax","BdString"];
for(var i = 0, j =  namespaces.length; i &lt; j; i ++){
if (window[ namespaces[ i ] ] !=  'object')
window[ namespaces[ i ] ] = {};
}
})();</pre>
<p>开头是baidu申明的命名空间，分为：System、Element、Browser、Event、Util、Ajax、BdString几个部分。其中Util我没细看，因为这玩意儿和网站耦合的比较紧，就懒得读了，其中还有个hi_tracker，猜想和百度hi相关。其它的东西倒是值得读一读的。<br />
接下来的/* attach methods */很长，还是分块儿来吧～</p>
<pre class="brush:js">/* BdBrowser scope */
var ua =  navigator.userAgent.toLowerCase();
var isStrict = document.compatMode ==  "CSS1Compat",
isOpera = ua.indexOf("opera") &gt; -1,
isSafari =  (/webkit|khtml/).test(ua),
isSafari3 = isSafari &amp;&amp;  ua.indexOf('webkit/5') != -1,
isIE = !isOpera &amp;&amp; ua.indexOf("msie")  &gt; -1,
isIE7 = !isOpera &amp;&amp; ua.indexOf("msie 7") &gt; -1,
isGecko = !isSafari &amp;&amp; ua.indexOf("gecko") &gt; -1,
isBorderBox  = isIE &amp;&amp; !isStrict,
isWindows = (ua.indexOf("windows") != -1 ||  ua.indexOf("win32") != -1),
isMac = (ua.indexOf("macintosh") != -1 ||  ua.indexOf("mac os x") != -1),
isAir = (ua.indexOf("adobeair") != -1),
isLinux = (ua.indexOf("linux") != -1),
isSecure =  window.location.href.toLowerCase().indexOf("https") === 0;
// remove css  image flicker
if(isIE &amp;&amp; !isIE7){
try{
document.execCommand("BackgroundImageCache", false, true);
}catch(e){}
}
var browsers = {
isOpera : isOpera,
isSafari :  isSafari,
isSafari3 : isSafari3,
isSafari2 : isSafari &amp;&amp;  !isSafari3,
isIE : isIE,
isIE6 : isIE &amp;&amp; !isIE7,
isIE7 :  isIE7,
isGecko : isGecko,
isBorderBox : isBorderBox,
isLinux :  isLinux,
isWindows : isWindows,
isMac : isMac,
isAir : isAir
};
for(var p in browsers){
BdBrowser[p] = browsers[p];
}</pre>
<p>这里主要是处理针对不同浏览器的操作的。可能有人眼熟了：这不是Ext嘛！没错，对于js这种宿主环境很多的语言来说，相互学习借鉴本身就是一种提倡的方法。其实不止于此，其它的不也都是么？<br />
上面这段主要讲判断浏览器以及https等放到BdBrowser下面。值得注意的是其中有个针对ie6的bug的修复——即ie6特殊情况下的图片闪烁bug，就是用document.execCommand(&#8220;BackgroundImageCache&#8221;,  false, true);搞定的。</p>
<pre class="brush:js">/* BdElement scope */
window.Bd$ = BdElement.check  = function(id){
return typeof id == 'string' ?  document.getElementById(id) : id;
}
BdElement.removeNode = isIE  ? function(){
var d;
return function(node){
if(node &amp;&amp; node.tagName != 'BODY'){
d = d || document.createElement('DIV');
d.appendChild(node);
d.innerHTML = '';
}
}
}() : function(node){
if(node &amp;&amp; node.parentNode &amp;&amp; node.tagName !=  'BODY'){
node.parentNode.removeChild(node);
}
}</pre>
<p>百度自己的getElementById和removeChild。前者实现为全局的Bd$，用jquery的用户可能很熟悉$(&#8220;#id&#8221;)，就是这种形式；后者添加在BdElement上，方法为removeNode，和IE特有的方法同名。<br />
由于IE的removeChild存在内存泄漏，所以现在基本上用的都是这种方法：将要移出的node放在一个div中，然后讲div的innerHTML清空。也有人提出outHTML等多种改进方案，但通用性稳定性等尚无法确保，所以主流方案还是这样。</p>
<pre class="brush:js">/* BdEvent scope */
BdEvent.addEvent = function(el, fn, handler){
if(isIE){
el.attachEvent("on" + fn, handler);
}else{
el.addEventListener(fn, handler, false);
}
}
BdEvent.removeEvent = function(el, fn, handler){
if(isIE){
el.detachEvent("on" + fn, handler);
}else{
el.removeEventListener(fn, handler, false);
}
}</pre>
<p>两个添加事件侦听方法，仅需区别是否IE即可，无需过多解释。</p>
<pre class="brush:js">BdEvent.addDOMLoadEvent = (function(){
// create event function  stack
var load_events = [],
load_timer,
script,
done,
exec,
old_onload,
init = function () {
done = true;
// kill the timer
clearInterval(load_timer);
// execute  each function in the stack in the order they were added
while (exec = load_events.shift())
setTimeout(exec, 10);
if (script)  script.onreadystatechange = '';
};
return  function (func) {
// if the init function was already ran,  just run this function now and stop
if (done) return func();

if (!load_events[0]) {
// for  Mozilla/Opera9
if (document.addEventListener)
document.addEventListener("DOMContentLoaded", init,  false);
// for Internet Explorer
/*@cc_on @*/
/*@if (@_win32)
document.write("&lt;script id=__ie_onload defer  src=//0&gt;&lt;\/scr"+"ipt&gt;");
script =  document.getElementById("__ie_onload");
script.onreadystatechange = function() {
if (this.readyState == "complete")
init(); // call the onload handler
};
/*@end @*/

// for Safari
if  (/WebKit/i.test(navigator.userAgent)) { // sniff
load_timer = setInterval(function() {
if (/loaded|complete/.test(document.readyState))
init(); // call the onload handler
}, 10);
}
// for other browsers set the window.onload, but also  execute the old window.onload
old_onload =  window.onload;
window.onload = function() {
init();
if (old_onload)  old_onload();
};
}
load_events.push(func);
}
})();</pre>
<p>addDOMLoadEvent是个值得细看的方法，其中主要的是“DOMContentLoaded”侦听，这个是大部分情况下替代window.onload的方案。由于window.onload是等候页面所有内容加载完成才执行，所以图片等大资源会造成严重的延迟问题，而DOMContentLoaded则是在DOM树建成之后出发，这才是我们想要的。可惜的是，ff、opera等浏览器对此标准都有了良好的支持，但是即使是IE8，也没看到丝毫“悔改”的念头，最后注意代码中注释掉的部分，这是以前曾经流行过的IE方法，原理是创建空的有defer属性的script标签，根据其onreadystatechange来判断是否DomReady。但这主要有2个缺点：https需要特殊判断；页面中有iframe时须得iframe加载完。<br />
所以代码中用的方法是：dom标准浏览器用DOMContentLoaded，safari不断侦听document.readyState，其它浏览器继续用window.onload()。这虽然解决了不少问题，但并不完美。ie还是需要特殊待遇——doScroll。这里并没有doScroll，其主要原理是IE下只有当DOM树构建完成后才能doScroll，所以便可建立一个侦听，不断地地document.body.doScroll(&#8216;left&#8217;);，成功的话说明DOM加载完毕。注意这句需要放在try里面，这样出错的话便可继续触发侦听，直到成功（页面DOM加载完）为止。</p>
<pre class="brush:js">/* BdAjax scope */
BdAjax.getXHR = function(){
var xhr =  null;
try{
return (xhr = new XMLHttpRequest());
}catch(e){}
for(var i = 0, a =  ['MSXML3','MSXML2','Microsoft']; i &lt; a.length; i ++){
try{
xhr = new ActiveXObject(a[i]+'.XMLHTTP');
break;
}catch(e){}
}
return xhr;
}</pre>
<p>BdAjax创建xhr的工具，倒是省写了些代码，可以借来用用。不过似乎xhr的设计意图没让开发人员直接使用，而是下面的request。</p>
<pre class="brush:js">BdAjax.request = function(url, json){
var xhr = this.getXHR();
if(!xhr){
throw new Error("cant't initialize xhr  instance.");
}
var options={};
options.method    =  (json.method || 'get').toLowerCase();
options.asyn      = true;
options.onSuccess = json.onSuccess || function(){};
options.onFailure = json.onFailure || function(){ new Image().src =  "/sys/statlog/1.gif?m=ajax-request&amp;v=" + encodeURIComponent(url) + "&amp;t="  + new Date().getTime();};

options.postData =  json.postData || null;
xhr.open(options.method, url, options.asyn);
if("post" == options.method.toLowerCase()){
xhr.setRequestHeader("Content-Type",  "application/x-www-form-urlencoded");
}
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
if(xhr.status == 0  || xhr.status == 200){
options.onSuccess(xhr);
}else{
options.onFailure(xhr);
}
}
}
xhr.send(options.postData);
}</pre>
<p>request首先创建一个xhr，第一个参数url无须解释，第二个json倒是有点小复杂，这个名字容易使人误解，以为是传回的数据。其实是要ajax的一些参数，叫params倒是更好。不过从格式来看baidu的ajax请求默认就是json，所以有这个名字倒也不为怪。整体方法理解起来并不难，咱不多说了，这种风格倒是值得借鉴的。</p>
<pre class="brush:js">BdAjax.loadJS=(function()
{
var head ;
return  function(jsUrl){
head = head || document.getElementsByTagName("head")[0];
var s=document.createElement("script");
s.type="text/javascript";
s.src=jsUrl;
head.appendChild(s);
}
})();</pre>
<p>loadJS，就是把script标签append到head上。我想不通多判断一下head有何意义……</p>
<pre class="brush:js">BdString.trim=function(str)
{
return  str.replace(/(^[\s\t\xa0\u3000]+)|([\u3000\xa0\s\t]+$)/g, "");
}
BdString.byteLength = function(str){
return  str.replace(/[^\x00-\xFF]/g, "ly").length;
}
BdString.subByte =  function(s, n){
if(this.byteLength(s)&lt;=n)
return s;
for(var i=Math.floor((n=n-2)/2),l=s.length; i&lt;l; i++)
if(this.byteLength(s.substr(0,i))&gt;=n)
return s.substr(0,i) +"\u2026";
return s;
}</pre>
<p>三个关于String的方法：trim去除两边空白；byteLength将双字节字符替换成两个英文字母再计算长度；subByte有点特殊，截取几个字节的字符串。奇特的是，它首先将最后增加的\u2026——也就是半个省略号算上，所以你要截取2个字节的字符串，只会返回\u2026，只有当截取的字符串大于2个时，它才会真正起作用。</p>
<p>另外今天遇到一个ie6的flash的bug，查了半天终于在别人的空间里找到了，真郁闷！<br />
“FLASH在IE6下Error  2032错的处理<br />
被这个问题折腾了2天。<br />
Flash在IE6中POST数据时会出现ioerror Error #2032<br />
这个错误是Gzip和no-cache同时出现造成的。<br />
解决方法是在返回的页面里增加HTTP头，</p>
<pre class="brush:php">Response.AppendHeader("Cache-Control", "no-cache, no-store, must-revalidate,  max-age=-1");</pre>
<p>总结：为什么昨天突然爆发呢?服务器没做任何修改，难道是MS搞的鬼？？？”</p>
]]></content:encoded>
			<wfw:commentRss>http://army8735.org/2009/05/15/54.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

