经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » JS/JS库/框架 » jQuery » 查看文章
jQuery 源码分析(十八) ready事件详解
来源:cnblogs  作者:大沙漠  时间:2019/11/1 8:48:21  对本文有异议

ready事件是当DOM文档树加载完成后执行一个函数(不包含图片,css等),因此它的触发要早于load事件。用法:

  • $(document).ready(fun)    ;fun是一个函数,这样当DOM树加载完毕后就会执行该匿名函数了

ready有一个简写,可以直接传入$(fun)即可,这是因为在jQuey内部也定义了一个$(document)的jQuery对象,和我们在上面的写法是一样的

ready事件和window的onload区别:

  • ready事件  ;等dom树载完毕后就可以执行
  • onload事件   ;等网页中所有的资源加载完毕后(包括图片,flash,音频,视频)才能执行   

onload事件还可以绑定在某个图片上面,举个例子:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Document</title>
  6. <script src="http://libs.baidu.com/jquery/1.11.1/jquery.min.js"></script>
  7. </head>
  8. <body>
  9. <img src="https://www.cnblogs.com/images/logo_small.gif" alt="">
  10. <script>
  11. $(()=>console.log('DOM树已加载完毕')) //ready事件
  12. $('img').on('load',()=>console.log('图片已加载完毕')) //图片的加载事件
  13. $(window).on('load',()=>console.log('资源已加载完毕')) //网页所有资源都加载完毕后的事件
  14. </script>
  15. </body>
  16. </html>

这里我们用了箭头函数来写,代码很简单了,我们在绑定了一个ready事件,一个图片上的onload事件和window上的onload事件,加载后输出如下:

 可以看到首先是ready事件的触发,然后是图片的onload事件,最后是window的onload事件的触发,此时所有资源都已经加载完了

 

源码分析


 jquery的ready事件就是在document上绑定了一个DOMContentLoaded事件对象,对他进行了一下封装,DOMContentLoaded事件的原理可以看看看这篇文章,介绍得挺详细的:https://www.cnblogs.com/caizhenbo/p/6679478.html

jQuery的ready事件是基于函数列表实现的,函数列表可以看这个连接:https://www.cnblogs.com/greatdesert/p/11433365.html

当我们调用$(fun)去执行一个ready事件的时候首先会执行入口模块里的逻辑,与ready相关的如下:

  1. init: function( selector, context, rootjQuery ) {
  2. var match, elem, ret, doc;
  3. // Handle $(""), $(null), or $(undefined)
  4. if ( !selector ) {
  5. return this;
  6. }
  7. // Handle $(DOMElement)
  8. if ( selector.nodeType ) {
  9. this.context = this[0] = selector;
  10. this.length = 1;
  11. return this;
  12. }
  13. // The body element only exists once, optimize finding it
  14. if ( selector === "body" && !context && document.body ) {
  15. this.context = document;
  16. this[0] = document.body;
  17. this.selector = selector;
  18. this.length = 1;
  19. return this;
  20. }
  21. // Handle HTML strings
  22. if ( typeof selector === "string" ) {
  23. /**/
  24. } else if ( jQuery.isFunction( selector ) ) { //如果参数selector是函数,则认为是绑定ready事件
  25. return rootjQuery.ready( selector ); //则执行rootjQuery.ready()方法,并把selector作为参数传入
  26. }
  27. /**/
  28. },

rootjQuery是jQuery内部定义的一个局部变量,是一个jQuery实例,如下:

  1. rootjQuery = jQuery(document);           //第917行,保存了document对象引用的jQuery实例

在入口模块引用rootjQuery.ready()也就是执行了rootjQuery实例对象上的ready方法(该方法是定义在原型上的),如下:

  1. jQuery.fn = jQuery.prototype = {
  2. ready: function( fn ) {
  3. // Attach the listeners
  4. jQuery.bindReady(); //先执行jQuery.bindReady()绑定ready事件(实际上绑定的是DOMContentLoaded或onreadystatechange事件)
  5.  
  6. // Add the callback
  7. readyList.add( fn ); //为函数列表readyList增加一个函数
  8.  
  9. return this;
  10. }
  11. }

jQuery.bindReady()是一个静态方法,用于绑定事件的,内部会初始化readyList为一个jQuery.Callbacks( "once memory" )函数列表对象

然后执行readyList.add( fn )将fn函数保存到函数列表readyList里面。

jQuery.bindReady()的实现如下:

  1. jQuery.extend({
  2. bindReady: function() { //初始化ready事件监听函数列表readyList,并为document对象绑定ready事件主监听函数DOMContentLoaded
  3. if ( readyList ) {
  4. return;
  5. }
  6. readyList = jQuery.Callbacks( "once memory" ); //调用jQuery.Callbacks(flags)ready事件监听函数列表readylist,同时传入once和memory标记。
  7.  
  8. // Catch cases where $(document).ready() is called after the
  9. // browser event has already occurred.
  10. if ( document.readyState === "complete" ) { //如果文档已经就绪,则调用jQuery.ready(wait)执行ready事件监听函数列表readyList
  11. // Handle it asynchronously to allow scripts the opportunity to delay ready
  12. return setTimeout( jQuery.ready, 1 ); //通过setTimeout()异步执行方法jQuery.ready(wait),以允许其他脚本延迟ready事件的触发。
  13. }
  14. // Mozilla, Opera and webkit nightlies currently support this event
  15. if ( document.addEventListener ) { //在IE9+及以上浏览器绑定DOMContentLoaded事件
  16. // Use the handy event callback
  17. document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); //把监听函数DOMContentLoaded绑定到document对象的DOMContentLoaded事件上
  18.  
  19. // A fallback to window.onload, that will always work
  20. window.addEventListener( "load", jQuery.ready, false );
  21. // If IE event model is used
  22. } else if ( document.attachEvent ) {
  23. // ensure firing before onload,
  24. // maybe late but safe also for iframes
  25. document.attachEvent( "onreadystatechange", DOMContentLoaded );
  26. // A fallback to window.onload, that will always work
  27. window.attachEvent( "onload", jQuery.ready );
  28. // If IE and not a frame
  29. // continually check to see if the document is ready
  30. var toplevel = false;
  31. try {
  32. toplevel = window.frameElement == null;
  33. } catch(e) {}
  34. if ( document.documentElement.doScroll && toplevel ) {
  35. doScrollCheck();
  36. }
  37. }
  38. },
  39. /**/
  40. })

这里我们调用document.addEventListener在document上绑定了一个DOMContentLoaded事件,这样当DOM树加载完后就会执行DOMContentLoaded函数了,DOMContentLoaded函数的定义如下:

  1. if ( document.addEventListener ) { //如果是IE9+和其他浏览器
  2. DOMContentLoaded = function() {
  3. document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); //先移除document的DOMContentLoaded事件
  4. jQuery.ready(); //再调用jQuery.ready()执行ready事件监听函数
  5. };
  6. } else if ( document.attachEvent ) {
  7. DOMContentLoaded = function() {
  8. // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
  9. if ( document.readyState === "complete" ) {
  10. document.detachEvent( "onreadystatechange", DOMContentLoaded );
  11. jQuery.ready();
  12. }
  13. };
  14. }

函数内首先会移除DOMContentLoaded事件,然后调用jQuery.ready()事件,这是DOM树触发后的事件了(我们在jQuery.fn.ready()内执行了readyList.add( fn )增加的函数都会依次触发),如下:

  1. jQuery.extend({
  2. isReady: false,
  3. ready: function( wait ) { //实际执行的函数 触发ready事件监听函数列表readyList和数据缓存对象中的ready事件监听函数。
  4. // Either a released hold or an DOMready/load event and not yet ready
  5. if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { //如果wait是true且jQuery.readyWait等于0 或者 wait不是true且jQuery.isReady是false 则执行 初始化jQuery.isReady为false的
  6. // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
  7. if ( !document.body ) {
  8. return setTimeout( jQuery.ready, 1 );
  9. }
  10. // Remember that the DOM is ready
  11. jQuery.isReady = true; //设置jQuery.inReady为true,表示ready事件已就绪。
  12.  
  13. // If a normal DOM Ready event fired, decrement, and wait if need be
  14. if ( wait !== true && --jQuery.readyWait > 0 ) {
  15. return;
  16. }
  17. // If there are functions bound, to execute
  18. readyList.fireWith( document, [ jQuery ] ); //执行ready事件监听函数readyList,上下文是document(即关键词this),[jQuery]是ready事件监听函数的参数。
  19.  
  20. // Trigger any bound ready events
  21. if ( jQuery.fn.trigger ) {
  22. jQuery( document ).trigger( "ready" ).off( "ready" );
  23. }
  24. }
  25. },
  26. /**/
  27. })

 writer by:大沙漠 QQ:22969969

最后调用readyList.fireWith()方法去触发回掉函数列表里的每个函数。

 

原文链接:http://www.cnblogs.com/greatdesert/p/11720567.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号