【问题标题】:Javascript bind element events as soon as element is loaded加载元素后立即绑定元素事件
【发布时间】:2011-08-01 16:38:58
【问题描述】:

我是 javascript 的新手,所以这可能是众所周知的/愚蠢的/无用的,但我想在 DOM 元素加载后立即使用它们(在本网站或谷歌上搜索时找不到任何东西,但它很难用几句话来解释)。例如,当一个大页面正在加载时,我想隐藏/添加 onlick 事件/等。一旦元素出现在用户屏幕上而不是 $(document).ready() 上,就立即将其发送给元素。我写了一个简单的课程(仅用于培训,闭包对我来说是新的,所以可能会有很多错误),它可以满足我的需求,但我想将更好的东西用于商业用途(在我正在帮助开发的网站上)。这是我的源代码 - 也许它会比这篇文章更好地解释我想要什么:我也是英语新手(:

function MY_loader() {
    function container() {
        this.add_event = function(new_event,obj_selector,settings) {
            if(typeof(settings)!='object') {
                settings={};
            }
            if(typeof(settings.event_id)!='string') {
                settings.event_id=gen_new_event_id();
            }
            settings=$.extend({},default_settings,settings);
            settings.obj_selector=obj_selector;
            settings.event=new_event;
            events[settings.event_id]=settings;
        }

        this.execute_events = function(if_force) {
            if(typeof(if_force)=='undefined') {
                if_force=false;
            }
            if(html_is_loaded&&!if_force) {
                return;
            }
            var temp_obj;
            for(var event_name in events) {
                temp_obj=$(events[event_name].obj_selector);
                if(temp_obj.length || (html_is_loaded && events[event_name].if_force)) {
                    temp_obj.each(function() {
                        if(events[event_name].expect_multiple) {
                            if($(this).data('my_loader_'+events[event_name].event_id+'_executed')) {

                                return;
                            }
                        }
                        if(events[event_name].event_type!='func') {
                            $(this).bind(events[event_name].event_type+'.'+events[event_name].event_id,events[event_name].event);
                        }
                        else {
                            events[event_name].event($(this));
                        }
                        if(events[event_name].expect_multiple) {
                            alert('here');
                            $(this).data('my_loader_'+events[event_name].event_id+'_executed',1);
                        }
                    });
                       //alert(events[event_name].obj_selector+' '+events[event_name].event_type);
                    if(!events[event_name].expect_multiple) {
                        delete events[event_name];
                    }
                }
            }
            if(!html_is_loaded) {
               var cur_time=new Date().getTime();
               setTimeout('MY_loader().execute_events();',Math.max(Math.min(tick_time-(cur_time-last_tick_time),tick_time),0,min_tick_diff));
               last_tick_time=cur_time;
            }
        }

        this.html_is_loaded_set=function(if_html_is_loaded) {
            html_is_loaded=if_html_is_loaded?true:false;
        };

        this.html_is_loaded_get=function() {
            return html_is_loaded?true:false;
        };

        return this;
    }
    function instance(if_strat) {
        if(typeof(class_is_loaded)=='undefined'||!class_is_loaded) {
            load_class();
        }
        return container(if_strat);
    }

    var load_class=function() {
        this.class_is_loaded=true;
        this.events = {};
        this.allowed_event_id_chars='abcdefghijklmnopqrstuvwxyz0123456789';
        this.default_settings={
            'event_type':'click',
            'if_force':false,
            'expect_multiple':false
        };
        this.tick_time=500;
        this.min_tick_diff=100;
        this.last_tick_time=0;
        this.html_is_loaded=false;
        MY_loader().execute_events();
        $(document).ready(function(){
            MY_loader().html_is_loaded_set(true);
            MY_loader().execute_events(true);
        });
    }

    var gen_new_event_id=function() {
        for(var new_id=gen_random_id();typeof(events[new_id])!='undefined';new_id=gen_random_id());
        return new_id;
    }

    var gen_random_id=function() {
        var allowed_event_id_chars_size=allowed_event_id_chars.length;
        var new_id='';
        for(var i=0;i<10;i++) {
            new_id+=allowed_event_id_chars[get_random_int(0,allowed_event_id_chars_size-1)];
        }
        return new_id;
    }

    function get_random_int(min, max)
    {
        return Math.floor(Math.random() * (max - min + 1)) + min;
    }

    return new instance();
}
//Add click event to #some_selector (once and dont check after it)
MY_loader().add_event(function() {
    alert($(this).val());
}, '#some_selector');
//Hide elements as soon as they are loaded.
//We expect multiple elements with this selector, so it will
//check for this elements untill document is loaded, but this function
//will be applied only one time for each element.
MY_loader().add_event(function(obj) {
    obj.hide();
    alert('This should happen before DOM is completely loaded!');
}, '.some_other_selector',{'event_type':'func','expect_multiple':true});
//This alert should be outputted the last
$(document).ready(function(){
    alert('Document is fully loaded!');
});

提前谢谢大家!

UPD:为了让这个问题变得更有趣,因为它看起来太具体了,我必须添加:大多数浏览器在页面完全加载之前开始渲染(由于某种原因,这似乎并不为人所知),在这里有几个链接:

  1. http://en.wikipedia.org/wiki/Incremental_rendering
  2. When do browsers start to render partially transmitted HTML?
  3. http://www.vbulletin.org/forum/showthread.php?t=161099

所以,我的问题应该更广为人知,因为这种增量页面加载给开发人员增加了很多问题:用户可以在页面加载之前点击非工作按钮,加载时被 javascript 隐藏的一些东西可能会显示出来,它们可能很丑,等等(这是我的问题的例子)。其他开发人员会忽略这个问题吗?如果我错了,请纠正我。

【问题讨论】:

  • 您是否正在使用一些在构建 DOM 之前实际呈现页面的浏览器?我不知道有任何浏览器会这样做。
  • @kinakuta:几乎每个浏览器都这样做:例如 firefox(100% 测试)。阅读 cmets 以获取:php.net/manual/ru/function.flush.php,但这并不是唯一发生的情况(即使启用了 gzip)。
  • 您可能已经知道这一点,但 document.ready() 与 body onload 不同。 onload 等待所有资产(图像/css/等)被加载,但 document.ready() 没有。除非您拥有庞大的 DOM 结构,否则用户似乎不太可能在 .ready() 触发之前选择任何内容?
  • @Steve Claridge:嗯,是的,我有一些非常庞大的页面(白名单/黑名单等) - 我知道我应该更改它们,但我目前没有时间这样做。我只是添加了输出刷新来临时解决问题,但后来出现了这个问题。我记得当我在网上冲浪时,有时我也会首先看到页面的一部分(头部和一些主体),然后加载页面的其余部分(我怀疑它是 ajax),所以可能一些大网站使用类似的东西这也是,但也许这只是我的想象(希望不是):)
  • 如果你渲染的元素引用了另一个尚未渲染的元素怎么办?会导致操作中断吗?

标签: javascript jquery javascript-events


【解决方案1】:

如果您担心不希望用户在最终页面之前看到该页面,您可以直接进行 DOM 修改,例如:

<a href="#" id="test">Test</a>
<script type="text/javascript" src="enhancePage.js"></script>

由于在解析脚本之前,DOM 中存在问题节点,因此您可以使用它。

【讨论】:

  • 我也想过这个问题,但我不想将 html 与 javascript 混为一谈——维护起来要困难得多(完整的 javascript 文件更容易阅读),而且我当然希望缓存所有的 javascript .
  • 然后确保在脚本可能关心的所有节点都写完之后包含脚本。
  • 它与 $(document).ready() 相同,因为某些节点位于页面末尾。
猜你喜欢
  • 2013-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-18
  • 1970-01-01
  • 2012-04-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多