Js框架设计之DomReady

一、在介绍DomReady之前,先了解下相关的知识

1、HTML是一种标记语言,告诉我们这页面里面有什么内容,但是行为交互则要通过DOM操作来实现,但是注意:不要把尖括号里面的内容看作是DOM!

2、HTML是要通过浏览器解析之后才会转换成为DOM节点

一般地,但我们向浏览器中输入一个地址,开始加载页面到我们看到页面的内容为止,这期间就有一个DOM节点构建的过程(浏览器将HTML标签转换为DOM节点)。

当前页面上的所有的HTML标签都转换成DOM节点,这就叫DOM树建完,简称为DOMReady.

3、浏览器是自上向下,从左往右,HTML字符串标签一个一个的读入,页面上会有很多的标签,响相应的会生成很多的对应的DOM,每种标签对应的规则不一样,有的标签下面可以添加任意的HTML标签,有的标签下面却只能加规定的标签,如<tr>标签下面就只能是<td>或者<th>如果你加其他的标签比如<span>,浏览器则不会解释这个标签,又比如<option>下面规定只能加文本。

4、一般的HTML标签的都转换成DOM节点的速度很快,但是有写却很慢,比如图片,外部脚本文件,外部css样式表,等的文件,当浏览器解释到这一类的标签,回去指定的路径加载对应的文件,

这里注意JS文件:浏览器下载完指定的脚本文件后,首先会执行当前脚本文件,等执行完道歉脚本文件后,才会解析下一个标签,当当前脚本文件非常大的时候,浏览器就会产生"堵塞"现象。

5、因为浏览器渲染引擎是单线程的,如果头部脚本文件过多过大,会产生"白屏"现象,所以为了防止这种情况,我们应该将所有的脚本文件都放到</body>标签之前,这一点在雅虎军规中也有提到。

6、此外, style标签与link标签,它们在加载样式文件时是不会堵塞,但它们一旦异步加载好,就立即开始渲染已经构建好的元素节点们, 这可能会引起reflow, 这也影响速度.

7、另一个影响DOM构建的标签是iframe,他不会堵塞Dom构建,但是它会在加载DOM时和其他标签争抢资源(因为iframe会发送http请求,但是http请求有限),们经常看到一些新闻网,上面会挂许多iframe广告, 这些页面一开始加载时就很卡,也是这缘故.

总结:上面的种种原因都会影响到DOM的构建,所以我们贸然的使用getElementById,ByTageName等等方法获取页面的元素时,很可能页面上的HTML标签还没有转换成为DOM节点,所以就会报null的错误

二、使用DomReady机制解决因DOM解析未完成前使用document.getElementById获取报null错误的问题

1、在早期的浏览器中,提供了一个window.onload方法,这个方法会在浏览器加载完所有的文件(包括图片、脚本文件、样式文件),且HTML标签都转换成为DOM节点是,会被触发,但是这个方法在执行时间上有点晚,如果图片很多,那么你懂得额!!!!!

2、在标签浏览器, W3C终于绅士地提供了一个DOMContentLoaded事件;在旧式IE下,也可以勉强使用onreadystatechange事件模拟, 直接某一天,有个外国大牛发掘出doScroll这个伟大的hack, 它让我们在IE下更接近DOMContentLoaded的效果

<script>
    /**
     *方法作用:DomReady其实是一种名为"DomContentLoaded"事件的名称,不过由于框架的需要,
     它与真正的DomContentLoaded有区别,在旧的JS书籍中m都会让我们把Js函数写到window.onload函数中,
     防止Dom树还没有建好,就对节点进行操作,产生错误。而对框架来说,越早介入对Dom的干涉越好,
     如果要进行特征侦测之类的。DomReady还可以满足用户提前绑定事件的需求,因为有时页面图片资源过多,
     window.onload迟迟不能触发,这时若还没有绑定事件,用户点哪个按钮都没有反应。因此主流框架都引入domready机制,
     并且废了很大的劲兼容很多的浏览器

     readyState 属性返回当前文档的状态(载入中……)。
     该属性返回以下值:
     uninitialized - 还未开始载入
     loading - 载入中
     interactive - 已加载,文档与用户可以开始交互
     complete - 载入完成

     逻辑:
     1、首先通过document.readyState判断DOM节点的加载情况,如果文档加载完成(HTML标签转换成DOM节点)document.readyState=complete
     那么直接执行Dom.beforeReady()方法
     2、如果文档没有加载完成,且浏览器是不是IE,那么
     */




    var Dom = [];
    Dom.isReady = false;//用于判断页面是否加在完毕
    Dom.domReady = function (fn) {
        if (Dom.isReady)
            fn();
        else
            Dom.push(fn);
    }

    //页面加载完毕(readyState="complete")立即执行当前函数
    Dom.beforeReady = function () {
        //通过isReady属性,控制beforeReady只执行一次
        //通过判断document.body,确认文档是否加在完毕,否则循环每隔16ms,吊用自己
        //上面的判断都通过后,循环执行Dom数组中的方法
        if(!Dom.isReady){
            if(!document.body){
                setTimeout(arguments.callee,16);
            }
            Dom.isReady=true;
            for(var i=0,fn;fn=Dom[i];i++){
                fn();//虽然不太合理,但是在Javascript中这是可行的
            }
        }
    }

    /**
     * 开始初始化domReady函数,判定页面加载在情况    start
     */
    if (!document.readyState) {
        //处理在firefox3.6之前,不存在readyState属性的bug   http://www.cnblogs.com/rubylouvre/archive/2012/12/18/2822912.html
        var readyState = document.readyState = document.body ? "complete" : "loading";
    }
    if (document.readyState === "complete") {
        Dom.beforeReady();
    }
    else if (-[1,]) {//如果浏览器不是IE,那么给document绑定DOMContentLoaded事件
        //addEventListener() 方法用于向指定元素添加事件句柄。
        //提示: 使用 removeEventListener() 方法来移除 addEventListener() 方法添加的事件句柄
        //注意: Internet Explorer 8 及更早IE版本不支持 addEventListener() 方法,,Opera 7.0 及 Opera 更早版本也不支持。
        // 但是,对于这些不支持该函数的浏览器,你可以使用 attachEvent() 方法来添加事件句柄 (查看 "更多实例" 了解跨浏览器的解决方案)。
        //removeEventListener(event,function,useCapture)
        //event 必须。字符串,指定事件名。
        //function    必须。指定要事件触发时执行的函数。
        //useCapture 可选。布尔值,指定事件是否在捕获或冒泡阶段执行。 true - 事件句柄在捕获阶段执行 false- false- 默认。事件句柄在冒泡阶段执行
        document.addEventListener("DOMContentLoaded", function () {
            document.removeEventListener("DOMContentLoaded",arguments.callee, false);
            Dom.beforeReady();
        });
    }
    else {//IE的情况

        //在IE下,使Dom.domReady先于window.onload执行
        //1、在老版本IE中onreadystatechange事件会触发在window.onload之后
        //2、当页面包含图片时,onreadystatechange事件会触发在window.onload之后(换言之,它只能正确地执行于页面不包含二进制资源或非常少或者被缓存时)
        document.attachEvent("onreadystatechange", function() {
            if ( document.readyState == "complete" ) {
                document.detachEvent("onreadystatechange", arguments.callee );
                Dom.beforeReady();
            }
        });
        (function () {
            // DOM树未创建完之前调用doScroll会抛出错误
            var node = new Image();
            try {
                node.doScroll();
                node = null;//防止IE内存泄漏
            }
            catch (e) {
                //javascrpt最短时钟间隔为16ms,这里取64  http://blog.csdn.net/aimingoo/article/details/1451556
                setTimeout(arguments.callee, 64);
                return;
            }
            Dom.beforeReady();
        })();
    }
    /**
     * 开始初始化domReady函数,判定页面加载在情况    end
     */

    window.onload = function(){
        var p = document.createElement("p")
        p.innerHTML = "window.onload"
        document.body.appendChild(p);
    };
    Dom.domReady(function(){
        var p = document.createElement("p")
        p.innerHTML = "domReady1"
        document.body.appendChild(p);
    });
    Dom.domReady(function(){
        var p = document.createElement("p")
        p.innerHTML = "domReady2"
        document.body.appendChild(p);
    });
</script>

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏编程语言

Python:pygame的初步使用

4.创建窗口,pygame.display.set_mode(resolution=(0,0),flags=0,depth=0),resolution窗口大小,...

8900
来自专栏从零开始学 Web 前端

从零开始学 Web 之 DOM(七)事件冒泡

事件冒泡:当有多个元素嵌套,并且这些元素绑定了相同的事件,这时候如果里面的元素事件触发了,那么外面的事件会自动触发。

10130
来自专栏Flutter知识集

Flutter实现雨滴动画

写了几个Flutter的demo,但是对Flutter的自定义view和动画都不太了解,看到一个类似效果在android的实现,就尝试用Flutter做一下。同...

1.2K50
来自专栏MasiMaro 的技术博文

windows编程学习笔记(三)ListBox的使用方法

ListBox是Windows中的一种控件,一般被当做子窗口使用,Windows中所有子窗口都是通过发送一个通知码到父窗口父窗口通过WM_COMMAND消息接收...

12220
来自专栏QQ音乐前端团队专栏

前端水印生成方案

安全问题不能大意,对于一些比较敏感的内容,我们可以通过组合使用上述的水印方案,这样才能最大程度给浏览者警示的作用,减少泄密的情况,即使泄密了,也有可能追踪到泄密...

1.9K40
来自专栏大前端_Web

Vue与React的异同-组件(二)

版权声明:本文为吴孔云博客原创文章,转载请注明出处并带上链接,谢谢。 https://blog.csdn.net/wkyseo/articl...

15520
来自专栏吴裕超

一次关于js事件出发机制反常的解决记录

起因:正常情况下我点击s2时是先弹出我是children,再弹出我是father,但是却出现了先弹出我是father,后弹出我是children的情况,这种情况...

30250
来自专栏前端说吧

Vue-自定义事件之—— 子组件修改父组件的值

37050
来自专栏葡萄城控件技术团队

Spread for Windows Forms高级主题(6)---数据绑定管理

自定义列和区域的数据绑定 当表单被绑定到一个数据集时,表单中的列就会相继的被分配到数据集的区域上。例如,第一个数据域分配给列A,第二个数据区域分配给列B,等等。...

222100
来自专栏林德熙的博客

win10 UWP 圆形等待

使用 RectangleStyle1 在 Rectangle 使用 style="{StaticResource RectangleStyle1}"

9920

扫码关注云+社区

领取腾讯云代金券