基于DOMContentLoaded实现文档加载完成后执行的方法

我们有时可能需要一些在页面加载完成之后执行的方法,其实js原生就提供了onload方法,所以我们最简单的办法就是直接给onload赋值一个函数,在页面加载完成之后就会自动执行

widnow.onload = function(e) {
  // do some things  
}

或者我们也可以使用addEventListener,来监听多个load事件,此处我们先暂时不考虑低版本的ie

document.addEventListener("load", function(e) {
   // do some things 
}, false);

这个时候,我们考虑到,明显jq的ready方法更好使用,而且简单很多,所以我们也可以通过切片编程的方法来实现一个onload方法

// after切片,可以在方法之后增加after,顺序执行
Function.prototype.after = function(func) {
    var _self = this;
    // 返回一个新的可执行方法
    return function() {
        var ret = _self.apply(this, arguments);
        // 当上一个方法返回false,则不会执行下一个after
    if(ret === false) {
        return false;
    }
    func.apply(this, arguments);
    return ret;
    }
}

$ = function(func) {
    window.onload = (window.onload || function() {}).after(func);
}

// 使用
$(function() {});    $(function() {});

当然,感觉可能实现还不如无限次的调用addEventListener,虽然这个方法可以保证执行顺序

而实际上,你在使用该方法的时候,会发现这个方法始终会在jq的ready之后执行,是因为jq的ready实现,是监听了DOMContentLoaded,这个事件是在文档加载完成之后就会触发,而不必等待所有的资源包括异步资源加载完成。所以我们最后的实现可以这样

var $ = (function() {
    var funcs = [];    // 保存所有需要执行的方法
    var ready = false;    // 页面准备完毕之后,修改为true

    // 当文档处理完毕,调用事件处理程序
    function handler(e) {
        // 如果执行过了,直接返回
        if(ready) {
            return;
        }

        // 如果发生过readysyayechange事件,但是状态不为complete,那么文档没有准备好
        if(e.type === "readystatechange" && document.readyState !== "complete") {
            return;
        }

        // 运行所有注册函数
        for(var i = 0; i < funcs.length; i++) {
            funcs[i].call(document);
        }

        // 设置ready为true,并移除所有方法
        ready = true;
        funcs = null;
    }

    // 为接收到的任何事件注册处理程序
    if(document.addEventListener) {
        document.addEventListener("DOMContentLoaded", handler, false);
        document.addEventListener("readystatechange", handler, false);
        document.addEventListener("load", handler, false);
    } else if(document.attachEvent) {    // 处理ie兼容
        document.attachEvent("onreadystatechange", handler);
        document.attachEvent("onload", handler);
    }

    // 返回__whenReady函数
    return function __whenReady(f) {
        if(ready) {
            f.call(document);
        } else {
            funcs.push(f);
        }
    }
}());

核心就是在判断几个加载事件执行的时候,文档是否准备好,如果没有准备好,则将需要执行的函数按照顺序缓存起来,然后在监听到文档准备好之后依次执行。

原文地址:https://www.cnblogs.com/timmer/p/10185006.html