jQuery中有关DOM加载的代码

DOM加载有关的扩展

  • isReady: DOM是否加载完(内部使用)
  • readyWait: 等待多少文件的计数器(内部使用)
  • holdReady(): 推迟DOM触发
  • ready(): 准备DOM触发。
  • jQuery.ready.promise=function(){}; 监听DOM的异步操作(内部使用)

$(function(){})和原生window.onload的关系

执行时机
  • 页面加载,先加载节点,再加载文件,比如img文件,flash等。
  • $(function(){})DOM加载完执行。可能DOM元素关联的东西并没有加载完。
  • window.onload等节点和文件都加载完执行。
  • 对应的事件监听
  • jQuery用的是DOMContentLoaded事件 — 原生DOM加载事件,这个事件触发代表DOM加载完了。
  • onload对应的是load事件
个数
  • window.onload不能写多个,后面的会覆盖前面的。
  • $(function(){})可以写多个。都会执行 。
简化写法
  • $(function(){})$(document) .ready(function(){});的简化写法。
  • window.onload没有简化写法。

jQuery如何实现DOM ready的

jQuery直接调用DOMContentLoaded来实现DOMready。但是DOMContentLoadedonLoad一样,浏览器只执行一次,jQuery用什么判断是否已经执行过呢?

document.readyState就是判断这个的依据。
readyStatedocument的属性,总共有3个值:

  • loading:文档正在加载中
  • interactive:文档已经加载完成,正在进行css和图片等资源的加载
  • complete:文档的所以资源加载完成

判断完之后如何回调呢?就是用PromisejQuery通过new一个$.Deferred(promise)对象来实现对DOMready的回调,在DOMContentLoaded中将这个promiseresolve[readyList.resolveWith( document, [ jQuery ] );]掉,这样就执行了之前注册的回调函数[jQuery.ready.promise().done( function(){} );],同时后面新注册的回调也会立刻执行[因为返回的是同一个promise,每次都会执行jQuery.ready.promise().done( function(){} );,同时readyList.resolveWith( document, [ jQuery ] );在DOM加载完毕之后已经执行过了,之后所有的done的context都是document,args都是jQuery]。

但是在调用promise之前,jQuery执行了一次setTimeout,因为jQuery.Promise是不会产生异步的,这和标准的promise规范是不一样的,所有jQuery自己又手动做了一次setTimeout来实现异步。这样使得无论使用在DOM的ready之前注册的回调还是之后注册的回调都会在异步中执行。

$(function(){}); 的加载过程

当页面DOM树加载完毕之后触发。注意的是它是dom树加载完毕,并不是页面所有资源加载完毕,例如图片,音视频等还没加载前触发。
window.onload是js原生的页面所有资源加载完毕才会触发。

$(function(){});相当于
$(document).ready(function(){});相当于
jQuery.ready.promise().done( function(){} );

ready: function( fn ) {
  jQuery.ready.promise().done( fn );
  return this;
}
所以下面来解释jQuery.ready.promise()的含义
// 在开头有定义
// The deferred used on DOM ready
var readyList

// 监听DOM的异步操作(内部使用)
jQuery.ready.promise = function( obj ) {
  //第一次readyList为空可以进来,后续就进不来if了,只执行一次
  if ( !readyList ) {
    // 先创建一个延迟对象
    // 延迟对象的状态有完成,未完成等其它的状态,这些状态在外部是可以被修改的,但promise是不可以被修改的,所以返回promise
    readyList = jQuery.Deferred();
    // DOM已经加载好的标志就是document.readyState === "complete"
    if ( document.readyState === "complete" ) {
      // 加定时器是为了兼容IE
      setTimeout( jQuery.ready );
    } else {
      // 当纯HTML被完全加载以及解析时,DOMContentLoaded 事件会被触发,而不必等待样式表,图片或者子框架完成加载。
      // window.onload() 方法用于在网页加载完毕后立刻执行的操作,即当 HTML 文档加载完毕后,立刻执行某个方法
      // 回调函数,调用completed
      // 为什么既要监测DOM,又要检测load,DOM加载要高于loader,有些浏览器会缓存load这个事件,如果缓存了这个事件,就有可能会先触发这个事件
      // 因为火狐浏览器会缓存load事件,为了第一时间相应所以对load也监听了
      document.addEventListener( "DOMContentLoaded", completed, false );
      window.addEventListener( "load", completed, false );
    }
  }
  // deferred.promise() 函数返回 Deferred(延迟)的 Promise 对象。
  
  return readyList.promise( obj );
};
监听器后面又调用了completed
// 在最开始定义过completed函数
// The ready event handler and self cleanup method
completed = function() {
  // 移除监听器
  document.removeEventListener( "DOMContentLoaded", completed, false );
  window.removeEventListener( "load", completed, false );
  jQuery.ready();
};
当DOM加载完毕之后都调用了jQuery.ready()
// 准备DOM触发
// jQuery.ready()
// 参数和holdReady有关
ready: function( wait ) {
  
  // Abort if there are pending holds or we're already ready
  if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
    return;
  }

  // Remember that the DOM is ready
  jQuery.isReady = true;

  // If a normal DOM Ready event fired, decrement, and wait if need be
  if ( wait !== true && --jQuery.readyWait > 0 ) {
    return;
  }

  // resolveWith改变状态的时候传参了,给done中方法fn传入了参数
  // document是fn的this指向,jQuery是参数
  // resolveWith(context [, args]):类似于resolve(args)方法的功能,只是激发done()方法添加的函数时将传入context和args参数。
  readyList.resolveWith( document, [ jQuery ] );

  // Trigger any bound ready events
  // 跟主动触发有关
  if ( jQuery.fn.trigger ) {
    jQuery( document ).trigger("ready").off("ready");
  }
}
测试this和arg
$(function(arg){
    alert(this); //[object HTMLDocument]
    alert(arg); //jQuery函数
})
推迟DOM触发
  • 示例:
    $.holdReady(true);
    $(function () {
        alert(123); //调用了holdReady并传参true,就不能弹出123了});
    
    // 可以推迟,也可以释放推迟,释放了以后就可以触发了。
    $.holdReady(true);
    $.holdReady(false);
    $(function () {
        alert(123); //释放了holdReady,就弹出123});
    
    // 引入外部文件的时候,都想等外部文件或者插件加载完,再去触发操作
    $.holdReady(true); //在这里先hold住
    $.getScript('js/a.js', function () {      
        // 先加载完,后弹出2
        $.holdReady(false); 
    })
    
    $(function () {
        alert(2);
    });
    
    // holdReady() 要针对的文件可能不止一个,有很多个,所以要等所有的文件都加载完再执行,所以源码中有一个计数的readyWait
    // 源码中定义了一个等待栈变量——readyWait,每次执行$.holdReady(true)都会增加压栈,而每次$.holdReady()执行都会弹栈,等空栈的时候就执行jQuery.ready函数,即将promise给resolve掉
    
  • 代码:
    holdReady: function( hold ) {
      if ( hold ) {
        // 储存需要等待完成的事件个数
        jQuery.readyWait++;
      } else {
        jQuery.ready( true );
      }
    }
    
    ready: function( wait ) {
      
      // 如果要执行ready函数,首先要检查--jQuery.readyWait
      // 默认为false,DOM加载完一次之后,isReady为true
      /**
       *  $.holdReady(true); //在这里先hold住 (readyWait = 2)
          $.getScript('js/a.js', function () {      
              // 先加载完,后弹出2
              $.holdReady(false); (readyWait = 1)
          })
    
          $(function () {
              alert(2); (readyWait = 0)
          });
       */
      if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
        return;
      }
    
      // Remember that the DOM is ready
      jQuery.isReady = true;
    
      // If a normal DOM Ready event fired, decrement, and wait if need be
      if ( wait !== true && --jQuery.readyWait > 0 ) {
        return;
      }
    
      // resolveWith改变状态的时候传参了,给done中方法fn传入了参数
      // document是fn的this指向,jQuery是参数
      readyList.resolveWith( document, [ jQuery ] );
    
      // Trigger any bound ready events
      // 跟主动触发有关
      if ( jQuery.fn.trigger ) {
        jQuery( document ).trigger("ready").off("ready");
      }
    }
    
主动触发ready事件
<script>$(document).on("ready",function(){
    alert(123); //123});</script>
// 跟主动触发有关
if ( jQuery.fn.trigger ) {
  jQuery( document ).trigger("ready").off("ready");
}
  • trigger方法
    // trigger() 方法触发被选元素上指定的事件以及事件的默认行为(比如表单提交)。
    $( "#old" ).click(function() {
      $( "input" ).trigger( "focus" );
    });
    
  • off方法
    // off() 方法通常用于移除通过 on() 方法添加的事件处理程序。
    $("button").click(function(){
        $("p").off("click");
    });
    
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值