首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网站开发 > Web前端 >

yui3上的load事件触发

2012-11-07 
yui3下的load事件触发以前的一些总结:页面load 与 资源load ,这次提出来一个window的load事件触发问题以及

yui3下的load事件触发

以前的一些总结:页面load 与 资源load ,这次提出来一个window的load事件触发问题以及解释一下在 yui3 中问题的解决。


问题:


异步脚本对页面的影响:


我们知道 window 的load事件只会在页面载入完毕后触发一次且仅一次,如果你没有在页面载入前listen这个事件,则以后都没机会了。(为了简便不使用addlistener了)


例如下面代码:

?

<script>setTimeout(function(){   window.onload=function(){alert("i will not trigger,sigh !");   };},1000);</script>

?

使用了yui3的异步加载脚本后,同样原理:

?

<script type="text/javascript" src="http://yui.yahooapis.com/3.1.0/build/yui/yui-min.js"></script><script>YUI({filter:"DEBUG"}).use("event",function(Y){window.onload=function(){alert("i will not trigger,sigh !");};});

?

onload是不会触发了,但是如果你真的需要这个事件,比如整体页面图片监控等应用(yui3脚本载入时间与页面load完毕时间大小不定),yui3提供了 Y.on("load")可供你使用,下文分析一下yui3对这个问题的考虑,而正是因为这点,造成了event源码中的 if 特殊判断,影响了代码的完美性。



原理:


这部分依赖于于对yui3事件机制的理解。既然不能等用户来绑定 onload ,yui为了解决上述问题,实际上不管用户是否需要这个load事件,都预先监听了。


1.在一开始的种子脚本 yui-min 中就listen了load,并设置全局变量代表load是否完毕:

?

add(window, 'load', handleLoad);handleLoad    = function() {                            YUI.Env.windowLoaded = true;                            YUI.Env.DOMReady = true;                            if (hasWin) {                                remove(window, 'load', handleLoad);                            }                        };

?

2.在动态加载的even模块中如果页面尚未载完也进行过了监听,不过这部分实际上主要是domready的fallback处理。



3.那么在 Y.on("load")时就开始了 yui3 的事件监听处理,但是正是由于 load 的特殊处理,导致了这段代码的不一致性:


? 3.1 如果是load事件,且window已经load完毕(windowLoaded==true),标志马上触发

?

?

if (el == Y.config.win && type == "load") {                // if the load is complete, fire immediately.                // all subscribers, including the current one                // will be notified.                if (YUI.Env.windowLoaded) {                    fireNow = true;                }            }

?

? 但是没有做的更彻底,为了能够和 window 尚未 load完毕的情况稍微统一一点,仍然创建了 cewrapper(如果load尚未完毕就照常规监听)。

?

ret = cewrapper._on(fn, context, (args.length > 4) ? args.slice(4) : null);            if (fireNow) {                cewrapper.fire();            }
?

?? 3.2 多监听器下的 fire


?? 如下列代码:

?

<script type="text/javascript" src="http://yui.yahooapis.com/3.1.0/build/yui/yui-min.js"></script><script>YUI({filter:"DEBUG"}).use("event",function(Y){window.onload=function(){alert("i will not trigger,sigh !");};Y.on("load",function(){alert(1);},window);Y.on("load",function(){alert(2);},window);});</script>
?

如果绑定了 多个 load 监听器,按照常规的 cewrapper.fire(),则弹出 1 1 2,因为到第二次 on load 的话,实际上 cewrapper 的 subscribers 有两个了,一下子 fire 就会弹出 1,2 了.


? 而 fire 为了避免这点采取了3点:


3.2.1.一旦触发事件,则该事件的 fired=true ,标记事件是已经 fire 了:

?

fire :function(){//.....this.fired = true;}

?

3.2.2.为 load 事件特殊标记,load只会真正fire一次:

?

if (el == Y.config.win && type == "load") {                    // window load happens once                    cewrapper.fireOnce = true;                    _windowLoadKey = key;                }
?

3.2.3.如果遇到 fired 以及 fireOnce ,则 fire 直接返回,真正的触发在 on 的时候就开始了,只对当前的一个subscriber触发

?

_on: function(fn, context, args, when) {//....        if (this.fireOnce && this.fired)                 setTimeout(Y.bind(this._notify, this, s, this.firedWith), 0);

?

fire: function() {        if (this.fireOnce && this.fired) {                return true;}//.....

?

?

总结

?

这样的话,尽可能的在普通事件监听的框架在解决了异步 load 的问题,虽然仍存在点 if ,但毕竟什么都没有完美的, 对于标准浏览器下的domready判断同理,但是对于ie就不一样了以后再写

?

1 楼 frankiehuang 2012-09-12   YUI({filter:"DEBUG"}).use("event",function(Y){ 
         
        window.onload=function(){ 
            alert("i will not trigger,sigh !"); 
        }; 
});

這個代碼會trigger呀!

热点排行