$ (tài liệu). đã tương đương mà không cần jQuery


2017

Tôi có một kịch bản sử dụng $(document).ready , nhưng nó không sử dụng bất cứ thứ gì khác từ jQuery. Tôi muốn làm sáng nó lên bằng cách loại bỏ phụ thuộc jQuery.

Làm cách nào tôi có thể thực hiện $(document).readychức năng của riêng mình mà không cần sử dụng jQuery? Tôi biết rằng việc sử dụng window.onloadsẽ không giống nhau, vì các window.onloadđám cháy sau khi tất cả các hình ảnh, khung hình, v.v. đã được tải.


296
... Và cũng chắc chắn không có chức năng tương tự.
Joel Mueller

40
Như câu trả lời này nêu rõ, nếu tất cả những gì bạn muốn từ jQuery là $(document).ready, bạn có thể giải quyết vấn đề đó một cách dễ dàng bằng cách chạy mã của bạn ở cuối trang thay vì ở trên cùng. HTML5Boilerplate sử dụng phương pháp chính xác này.
Blazemonger

3
Tại sao không chỉ sử dụng DOMContentLoaded? Đó là IE9 + caniuse.com/domcontentloaded developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded
Brock

Tôi đã thực hiện cuộc gọi của mình ở cuối tài liệu và điều đó giải quyết vấn đề của tôi. Khi chức năng được gọi, mọi thứ được tải.
IgniteCoders

Câu trả lời:


1440

Có một sự thay thế dựa trên tiêu chuẩn, DOMContentLoadedđược hỗ trợ bởi hơn 98% trình duyệt , mặc dù không phải IE8:

document.addEventListener("DOMContentLoaded", function(event) { 
  //do work
});

Hàm riêng của jQuery phức tạp hơn nhiều so với window.onload, như được mô tả dưới đây.

function bindReady(){
    if ( readyBound ) return;
    readyBound = true;

    // Mozilla, Opera and webkit nightlies currently support this event
    if ( document.addEventListener ) {
        // Use the handy event callback
        document.addEventListener( "DOMContentLoaded", function(){
            document.removeEventListener( "DOMContentLoaded", arguments.callee, false );
            jQuery.ready();
        }, false );

    // If IE event model is used
    } else if ( document.attachEvent ) {
        // ensure firing before onload,
        // maybe late but safe also for iframes
        document.attachEvent("onreadystatechange", function(){
            if ( document.readyState === "complete" ) {
                document.detachEvent( "onreadystatechange", arguments.callee );
                jQuery.ready();
            }
        });

        // If IE and not an iframe
        // continually check to see if the document is ready
        if ( document.documentElement.doScroll && window == window.top ) (function(){
            if ( jQuery.isReady ) return;

            try {
                // If IE is used, use the trick by Diego Perini
                // http://javascript.nwbox.com/IEContentLoaded/
                document.documentElement.doScroll("left");
            } catch( error ) {
                setTimeout( arguments.callee, 0 );
                return;
            }

            // and execute any waiting functions
            jQuery.ready();
        })();
    }

    // A fallback to window.onload, that will always work
    jQuery.event.add( window, "load", jQuery.ready );
}

19
Một triển khai javascript đơn giản thực sự hoạt động ở đây nếu ai đó muốn mã, họ chỉ cần đăng nhập: stackoverflow.com/questions/9899372/
Kẻ

4
Mã sẵn sàng của jQuery DOM dường như được đơn giản hóa: github.com/jquery/jquery/blob/master/src/core/ yet.js
Jose Nobile

2
@JoseNobile vì họ đã bỏ hỗ trợ trình duyệt cũ hơn
huysentbeanw

16
Tôi nghĩ rằng tất cả chúng ta đã sẵn sàng để chuyển từ IE8 ...;). Cảm ơn vì liên kết, @JoseNobile.
Con Antonakos

13
DOMContentLoaded sẽ không hoạt động nếu tập lệnh được tải sau đó. Tài liệu JQuery sẵn sàng thực thi luôn.
Jared Insel

343

Biên tập:

Đây là một sự thay thế khả thi cho jQuery đã sẵn sàng

function ready(callback){
    // in case the document is already rendered
    if (document.readyState!='loading') callback();
    // modern browsers
    else if (document.addEventListener) document.addEventListener('DOMContentLoaded', callback);
    // IE <= 8
    else document.attachEvent('onreadystatechange', function(){
        if (document.readyState=='complete') callback();
    });
}

ready(function(){
    // do something
});

Được lấy từ https://plainjs.com/javascript/events/rucky-code-when-the-document-is- yet-15 /

Một chức năng domReady tốt ở đây được lấy từ https://stackoverflow.com/a/9899701/175071


Vì câu trả lời được chấp nhận rất xa, tôi đã ghép một hàm "sẵn sàng" như jQuery.ready() dựa trên nguồn jQuery 1.6.2:

var ready = (function(){

    var readyList,
        DOMContentLoaded,
        class2type = {};
        class2type["[object Boolean]"] = "boolean";
        class2type["[object Number]"] = "number";
        class2type["[object String]"] = "string";
        class2type["[object Function]"] = "function";
        class2type["[object Array]"] = "array";
        class2type["[object Date]"] = "date";
        class2type["[object RegExp]"] = "regexp";
        class2type["[object Object]"] = "object";

    var ReadyObj = {
        // Is the DOM ready to be used? Set to true once it occurs.
        isReady: false,
        // A counter to track how many items to wait for before
        // the ready event fires. See #6781
        readyWait: 1,
        // Hold (or release) the ready event
        holdReady: function( hold ) {
            if ( hold ) {
                ReadyObj.readyWait++;
            } else {
                ReadyObj.ready( true );
            }
        },
        // Handle when the DOM is ready
        ready: function( wait ) {
            // Either a released hold or an DOMready/load event and not yet ready
            if ( (wait === true && !--ReadyObj.readyWait) || (wait !== true && !ReadyObj.isReady) ) {
                // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
                if ( !document.body ) {
                    return setTimeout( ReadyObj.ready, 1 );
                }

                // Remember that the DOM is ready
                ReadyObj.isReady = true;
                // If a normal DOM Ready event fired, decrement, and wait if need be
                if ( wait !== true && --ReadyObj.readyWait > 0 ) {
                    return;
                }
                // If there are functions bound, to execute
                readyList.resolveWith( document, [ ReadyObj ] );

                // Trigger any bound ready events
                //if ( ReadyObj.fn.trigger ) {
                //    ReadyObj( document ).trigger( "ready" ).unbind( "ready" );
                //}
            }
        },
        bindReady: function() {
            if ( readyList ) {
                return;
            }
            readyList = ReadyObj._Deferred();

            // Catch cases where $(document).ready() is called after the
            // browser event has already occurred.
            if ( document.readyState === "complete" ) {
                // Handle it asynchronously to allow scripts the opportunity to delay ready
                return setTimeout( ReadyObj.ready, 1 );
            }

            // Mozilla, Opera and webkit nightlies currently support this event
            if ( document.addEventListener ) {
                // Use the handy event callback
                document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
                // A fallback to window.onload, that will always work
                window.addEventListener( "load", ReadyObj.ready, false );

            // If IE event model is used
            } else if ( document.attachEvent ) {
                // ensure firing before onload,
                // maybe late but safe also for iframes
                document.attachEvent( "onreadystatechange", DOMContentLoaded );

                // A fallback to window.onload, that will always work
                window.attachEvent( "onload", ReadyObj.ready );

                // If IE and not a frame
                // continually check to see if the document is ready
                var toplevel = false;

                try {
                    toplevel = window.frameElement == null;
                } catch(e) {}

                if ( document.documentElement.doScroll && toplevel ) {
                    doScrollCheck();
                }
            }
        },
        _Deferred: function() {
            var // callbacks list
                callbacks = [],
                // stored [ context , args ]
                fired,
                // to avoid firing when already doing so
                firing,
                // flag to know if the deferred has been cancelled
                cancelled,
                // the deferred itself
                deferred  = {

                    // done( f1, f2, ...)
                    done: function() {
                        if ( !cancelled ) {
                            var args = arguments,
                                i,
                                length,
                                elem,
                                type,
                                _fired;
                            if ( fired ) {
                                _fired = fired;
                                fired = 0;
                            }
                            for ( i = 0, length = args.length; i < length; i++ ) {
                                elem = args[ i ];
                                type = ReadyObj.type( elem );
                                if ( type === "array" ) {
                                    deferred.done.apply( deferred, elem );
                                } else if ( type === "function" ) {
                                    callbacks.push( elem );
                                }
                            }
                            if ( _fired ) {
                                deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] );
                            }
                        }
                        return this;
                    },

                    // resolve with given context and args
                    resolveWith: function( context, args ) {
                        if ( !cancelled && !fired && !firing ) {
                            // make sure args are available (#8421)
                            args = args || [];
                            firing = 1;
                            try {
                                while( callbacks[ 0 ] ) {
                                    callbacks.shift().apply( context, args );//shifts a callback, and applies it to document
                                }
                            }
                            finally {
                                fired = [ context, args ];
                                firing = 0;
                            }
                        }
                        return this;
                    },

                    // resolve with this as context and given arguments
                    resolve: function() {
                        deferred.resolveWith( this, arguments );
                        return this;
                    },

                    // Has this deferred been resolved?
                    isResolved: function() {
                        return !!( firing || fired );
                    },

                    // Cancel
                    cancel: function() {
                        cancelled = 1;
                        callbacks = [];
                        return this;
                    }
                };

            return deferred;
        },
        type: function( obj ) {
            return obj == null ?
                String( obj ) :
                class2type[ Object.prototype.toString.call(obj) ] || "object";
        }
    }
    // The DOM ready check for Internet Explorer
    function doScrollCheck() {
        if ( ReadyObj.isReady ) {
            return;
        }

        try {
            // If IE is used, use the trick by Diego Perini
            // http://javascript.nwbox.com/IEContentLoaded/
            document.documentElement.doScroll("left");
        } catch(e) {
            setTimeout( doScrollCheck, 1 );
            return;
        }

        // and execute any waiting functions
        ReadyObj.ready();
    }
    // Cleanup functions for the document ready method
    if ( document.addEventListener ) {
        DOMContentLoaded = function() {
            document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
            ReadyObj.ready();
        };

    } else if ( document.attachEvent ) {
        DOMContentLoaded = function() {
            // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
            if ( document.readyState === "complete" ) {
                document.detachEvent( "onreadystatechange", DOMContentLoaded );
                ReadyObj.ready();
            }
        };
    }
    function ready( fn ) {
        // Attach the listeners
        ReadyObj.bindReady();

        var type = ReadyObj.type( fn );

        // Add the callback
        readyList.done( fn );//readyList is result of _Deferred()
    }
    return ready;
})();

Cách sử dụng:

<script>
    ready(function(){
        alert('It works!');
    });
    ready(function(){
        alert('Also works!');
    });
</script>

Tôi không chắc mã này có chức năng như thế nào, nhưng nó hoạt động tốt với các thử nghiệm hời hợt của tôi. Điều này mất khá nhiều thời gian, vì vậy tôi hy vọng bạn và những người khác có thể hưởng lợi từ nó.

PS.: Tôi đề nghị biên dịch nó.

Hoặc bạn có thể sử dụng http://dustindiaz.com/smallest-dompered-ever :

function r(f){/in/.test(document.readyState)?setTimeout(r,9,f):f()}
r(function(){/*code to run*/});

hoặc chức năng gốc nếu bạn chỉ cần hỗ trợ các trình duyệt mới (Không giống như jQuery đã sẵn sàng, điều này sẽ không chạy nếu bạn thêm chức năng này sau khi trang được tải)

document.addEventListener('DOMContentLoaded',function(){/*fun code to run*/})

14
Các lựa chọn thay thế @TimoHuovinen: Zepto.js (9.1 kb), Snack.js (8.1 kb), $ dom (2.3 kb) và 140 Medley (0.5 kb). Chỉnh sửa: Bạn cũng có thể xem Ender.
Frederik Krautwald

2
@FrederikKrautwald $ dom nghe có vẻ như những gì tôi muốn, nhưng không chắc nó có phù hợp với hóa đơn không. Zepto cũng có vẻ rất hứa hẹn, cảm ơn bạn đã chia sẻ!
Timo Huovinen

@TimoHuovinen Nếu bạn chưa xem Ender, bạn chắc chắn nên xem qua, enderjs.com .
Frederik Krautwald

2
@Timo Huovinen: Câu hỏi của bạn thực sự, thực sự rộng! Khi jQuery được tạo, nó đã giải quyết rất nhiều vấn đề về trình duyệt chéo được tạo bởi các trình duyệt ngày nay ít quan trọng hơn. Ngày nay, "chỉ javascript" dễ dàng hơn nó. Tại thời điểm này, tạo ra một "nén 20kb lớn, chứa tất cả" chắc chắn là một ý tưởng tốt vì rất nhiều lý do tôi không muốn liệt kê tất cả.
dotpush

1
Tôi không thích điều này. Nếu mọi người thích câu trả lời này, hãy tự hỏi tại sao bạn muốn bỏ jQuery ở vị trí đầu tiên. Sẽ hơi vô nghĩa nếu bạn chỉ trích xuất chính xác chức năng tương tự với tất cả các dự phòng trình duyệt đó trở lại vào gói của bạn. Không phải đó là toàn bộ vấn đề tránh jQuery ở nơi đầu tiên sao?
Phil

208

Ba lựa chọn:

  1. Nếu script là thẻ cuối cùng của phần thân, DOM sẽ sẵn sàng trước khi thẻ script thực thi
  2. Khi DOM đã sẵn sàng, "readyState" sẽ thay đổi thành "hoàn thành"
  3. Đặt mọi thứ trong trình nghe sự kiện 'DOMContentLoaded'

onreadystatechange

  document.onreadystatechange = function () {
     if (document.readyState == "complete") {
     // document is ready. Do your stuff here
   }
 }

Nguồn: MDN

DOMContentLoaded

document.addEventListener('DOMContentLoaded', function() {
   console.log('document is ready. I can sleep now');
});

Quan tâm đến các trình duyệt thời kỳ đồ đá: Chuyển đến mã nguồn jQuery và sử dụngreadyhàm. Trong trường hợp đó, bạn không phân tích cú pháp + thực thi toàn bộ thư viện, bạn chỉ đang thực hiện một phần rất nhỏ trong đó.


3
Ví dụ thứ hai này thanh lịch và cô đọng hơn nhiều so với các câu trả lời được đánh dấu. Tại sao cái này không được đánh dấu là đúng?
0112

2
Vẫn +1 cho điều DOMContentLoaded, nó đã làm chính xác những gì tôi muốn.
tripleee

1
onreadystatechange đã thực hiện thủ thuật cho tôi ... cần thiết để chạy một số tập lệnh sau khi tải asqu jquery.
Abram

2
Cũng như một FYI, # 1 không hoàn toàn đúng. Tập lệnh ở cuối trang có thể tải trước khi hoàn thành DOM. Đó là lý do tại sao người nghe là vượt trội. Họ lắng nghe khi trình duyệt được hoàn thành. Đặt nó ở cuối là vượt qua các ngón tay của bạn rằng tải tập lệnh chậm hơn trình duyệt có thể kết xuất.
Machavity

1
biến thể này cũng sẽ hoạt động khi tài liệu đã tải xong, vui lòng cập nhật câu trả lời (tốt nhất) của bạn nếu bạn có thể: if (document. yetState == 'Complete') {init (); } other {document.onreadystatechange = function () {if (document. yetState == 'Complete') {init (); }}}
ZPiDER

87

Đặt <script>/*JavaScript code*/</script>quyền của bạn trước khi đóng cửa </body> thẻ .

Phải thừa nhận rằng điều này có thể không phù hợp với mục đích của mọi người vì nó yêu cầu thay đổi tệp HTML thay vì chỉ làm một cái gì đó trong tệp JavaScript document.ready, nhưng vẫn ...


Dường như với tôi có vấn đề tương thích, như, vì trang chưa sẵn sàng, bạn không thể làm điều này hoặc điều đó trong những trình duyệt này và những trình duyệt đó. Thật không may, tôi không thể nhớ rõ hơn. Tuy nhiên +1 cho một cách đủ gần trong 99% tất cả các trường hợp (và được đề xuất bởi Yahoo!).
Boldewyn

7
Trên thực tế, đặt một yếu tố kịch bản ở dưới cùng của trang là một giải pháp gần như hoàn hảo. Nó hoạt động trên nhiều trình duyệt và mô phỏng tài liệu. Đã hoàn hảo. Nhược điểm duy nhất là nó gây khó chịu hơn một chút so với sử dụng một số mã thông minh, bạn sẽ phải yêu cầu người dùng tập lệnh bạn đang tạo để thêm một đoạn mã bổ sung để gọi hàm sẵn sàng hoặc init của bạn.
Stijn de Witt

@StijndeWitt - Ý bạn là gì khi phải gọi hàm init? Một tập lệnh sử dụng document. Yet không cần mã khách hàng khác để gọi nó, nó là độc lập và tương đương với đoạn mã được bao gồm ở cuối phần thân cũng có thể được khép kín và không yêu cầu mã khác để gọi nó.
nnnnnn

1
Tại sao không đặt tập lệnh sau thẻ đóng và trước </html>thẻ đóng ?
Charles Holbrow

1
@CharlesHolbrow Mặc dù tất cả các trình duyệt sẽ diễn giải chính xác, nhưng nếu bạn muốn nó là html hợp lệ, htmlthẻ chỉ nên chứa headbody.
Alvaro Montoro

66

Giải pháp của người nghèo:

var checkLoad = function() {   
    document.readyState !== "complete" ? setTimeout(checkLoad, 11) : alert("loaded!");   
};  

checkLoad();  

Xem Fiddle

Tôi đã thêm cái này, tốt hơn một chút, tôi đoán, phạm vi riêng và không đệ quy

(function(){
    var tId = setInterval(function() {
        if (document.readyState == "complete") onComplete()
    }, 11);
    function onComplete(){
        clearInterval(tId);    
        alert("loaded!");    
    };
})()

Xem Fiddle


8
@PhilipLangford Hoặc chỉ cần đặt nó vào trong a setIntervalvà loại bỏ hoàn toàn đệ quy.
Alex W

1
@Raveren, hmm bạn nói đúng, tôi khá chắc chắn rằng tôi đã kiểm tra nó khi tôi đăng nó. Dù sao, nó chỉ trở nên đơn giản hơn, bây giờ chức năng chỉ được gọi, không có gói.
Jakob Sternberg

24
Đây không phải là gợi cảm. Không xin lỗi. Sử dụng bộ định thời / khoảng thời gian để phát hiện công cụ có thể "hoạt động" nhưng nếu bạn tiếp tục lập trình như thế này thì bất kỳ dự án lớn nào cũng đáng để muối của nó sẽ lao vào. Đừng hack những thứ như thế này. Làm đúng Xin vui lòng. Loại mã này làm tổn thương hệ sinh thái phát triển vì có một giải pháp tốt hơn và bạn BIẾT nó.
dudewad

1
Tôi nghĩ rằng câu trả lời này gần gũi hơn với Dustindiaz.com/smallest-dom yet -ever Vì vậy, tôi đã cải thiện tập lệnh: jsfiddle.net/iegik/PT7x9
iegik

1
@ReidBlomquist Vâng, và đây là một cách "sai", và đó là những gì tôi đang chỉ ra (mặc dù một chút kiên quyết, tôi biết). Bạn có thể nói rằng bằng cách làm sai, bằng cách nào đó nó đã "giúp" hệ sinh thái, nhưng vấn đề là ở chỗ số lượng mã xấu ngoài kia mà mọi người lấy mã "tốt" vì họ không có kinh nghiệm để biết rõ hơn KHÔNG giúp ích cho hệ sinh thái, bởi vì sau đó họ sẽ lấy mã xấu đó và triển khai nó thành một giải pháp kiến ​​trúc sản xuất thực tế. Vì vậy, tôi đoán, chúng ta sẽ phải khác biệt về quan điểm về "ngụy biện" này.
dudewad

34

Tôi sử dụng cái này:

document.addEventListener("DOMContentLoaded", function(event) { 
    //Do work
});

Lưu ý: Điều này có lẽ chỉ hoạt động với các trình duyệt mới hơn, đặc biệt là các trình duyệt này: http://caniuse.com/#feat=domcontentloaded


13
IE9 trở lên thực sự
Pascalius

Điều này cũng hoạt động rất tốt trong các tập lệnh nội dung của Tiện ích mở rộng Chrome nếu bạn đang nối sự kiện document_start hoặc document_idle.
Volomike

21

Thực sự, nếu bạn chỉ quan tâm đến Internet Explorer 9+ , mã này sẽ đủ để thay thế jQuery.ready:

    document.addEventListener("DOMContentLoaded", callback);

Nếu bạn lo lắng về Internet Explorer 6 và một số trình duyệt thực sự lạ và hiếm, điều này sẽ hoạt động:

domReady: function (callback) {
    // Mozilla, Opera and WebKit
    if (document.addEventListener) {
        document.addEventListener("DOMContentLoaded", callback, false);
        // If Internet Explorer, the event model is used
    } else if (document.attachEvent) {
        document.attachEvent("onreadystatechange", function() {
            if (document.readyState === "complete" ) {
                callback();
            }
        });
        // A fallback to window.onload, that will always work
    } else {
        var oldOnload = window.onload;
        window.onload = function () {
            oldOnload && oldOnload();
            callback();
        }
    }
},

18

Câu hỏi này đã được hỏi khá lâu rồi. Đối với bất cứ ai chỉ nhìn thấy câu hỏi này, bây giờ có một trang web gọi là "bạn có thể không cần jquery" bị hỏng - theo cấp độ hỗ trợ IE cần thiết - tất cả các chức năng của jquery và cung cấp một số thư viện nhỏ hơn, thay thế.

Theo kịch bản IE8, bạn có thể không cần jquery

function ready(fn) {
    if (document.readyState != 'loading')
        fn();
    else if (document.addEventListener)
        document.addEventListener('DOMContentLoaded', fn);
    else
        document.attachEvent('onreadystatechange', function() {
            if (document.readyState != 'loading')
                fn();
        });
}

Tôi tự hỏi tại sao điều đó lại 'onreadystatechange'cần thiết hơn làdocument.attachEvent('onload', fn);
Lu-ca

13

Gần đây tôi đã sử dụng điều này cho một trang web di động. Đây là phiên bản đơn giản hóa của John Resig từ "Kỹ thuật JavaScript chuyên nghiệp". Nó phụ thuộc vào addEvent.

var ready = ( function () {
  function ready( f ) {
    if( ready.done ) return f();

    if( ready.timer ) {
      ready.ready.push(f);
    } else {
      addEvent( window, "load", isDOMReady );
      ready.ready = [ f ];
      ready.timer = setInterval(isDOMReady, 13);
    }
  };

  function isDOMReady() {
    if( ready.done ) return false;

    if( document && document.getElementsByTagName && document.getElementById && document.body ) {
      clearInterval( ready.timer );
      ready.timer = null;
      for( var i = 0; i < ready.ready.length; i++ ) {
        ready.ready[i]();
      }
      ready.ready = null;
      ready.done = true;
    }
  }

  return ready;
})();

13
Hãy cẩn thận với mã này. Nó KHÔNG tương đương với $ (tài liệu). Đã có. Mã này kích hoạt cuộc gọi lại khi document.body đã sẵn sàng mà không đảm bảo DOM được tải đầy đủ.
Karolis

12

Trình duyệt chéo (trình duyệt cũ cũng vậy) và một giải pháp đơn giản:

var docLoaded = setInterval(function () {
    if(document.readyState !== "complete") return;
    clearInterval(docLoaded);

    /*
        Your code goes here i.e. init()
    */
}, 30);

Hiển thị cảnh báo trong jsfiddle


Ngoại trừ nếu phải mất hơn 30ms để tải DOM, mã của bạn sẽ không chạy.
Quelklef

1
@Quelklef đó là setInterval không setTimeout
Pawel

11

Câu trả lời của jQuery khá hữu ích với tôi. Với một chút phản ứng, nó phù hợp với nhu cầu của tôi. Tôi hy vọng nó sẽ giúp bất cứ ai khác.

function onReady ( callback ){
    var addListener = document.addEventListener || document.attachEvent,
        removeListener =  document.removeEventListener || document.detachEvent
        eventName = document.addEventListener ? "DOMContentLoaded" : "onreadystatechange"

    addListener.call(document, eventName, function(){
        removeListener( eventName, arguments.callee, false )
        callback()
    }, false )
}

trên một số trình duyệt, removeListenersẽ cần phải được gọi với tài liệu là bối cảnh, nghĩa là. removeListener.call(document, ...
Ron

9

Đây là đoạn mã nhỏ nhất để kiểm tra DOM sẵn sàng hoạt động trên tất cả các trình duyệt (ngay cả IE 8):

r(function(){
    alert('DOM Ready!');
});
function r(f){/in/.test(document.readyState)?setTimeout('r('+f+')',9):f()}

Xem câu trả lời này .


6

Chỉ cần thêm phần này vào cuối trang HTML của bạn ...

<script>
    Your_Function();
</script>

Bởi vì, các tài liệu HTML được phân tích cú pháp từ trên xuống dưới.


7
Làm thế nào để bạn biết rằng DOM được xây dựng khi mã này được thực thi? Bao gồm CSS được tải và phân tích cú pháp? API trình duyệt DOMContentLoaded được thiết kế cho điều đó.
Dan

Nó thực sự phụ thuộc vào những gì anh ấy muốn làm với js. Nếu anh ta thực sự cần phải thực hiện một cái gì đó khi trang đã kết thúc hay không.
davefrassoni

5

Rất đáng để tìm kiếm trong Rock Solid addEvent ()http://www.braksator.com/how-to-make-your-own-jquery .

Đây là mã trong trường hợp trang web bị sập

function addEvent(obj, type, fn) {
    if (obj.addEventListener) {
        obj.addEventListener(type, fn, false);
        EventCache.add(obj, type, fn);
    }
    else if (obj.attachEvent) {
        obj["e"+type+fn] = fn;
        obj[type+fn] = function() { obj["e"+type+fn]( window.event ); }
        obj.attachEvent( "on"+type, obj[type+fn] );
        EventCache.add(obj, type, fn);
    }
    else {
        obj["on"+type] = obj["e"+type+fn];
    }
}

var EventCache = function(){
    var listEvents = [];
    return {
        listEvents : listEvents,
        add : function(node, sEventName, fHandler){
            listEvents.push(arguments);
        },
        flush : function(){
            var i, item;
            for(i = listEvents.length - 1; i >= 0; i = i - 1){
                item = listEvents[i];
                if(item[0].removeEventListener){
                    item[0].removeEventListener(item[1], item[2], item[3]);
                };
                if(item[1].substring(0, 2) != "on"){
                    item[1] = "on" + item[1];
                };
                if(item[0].detachEvent){
                    item[0].detachEvent(item[1], item[2]);
                };
                item[0][item[1]] = null;
            };
        }
    };
}();

// Usage
addEvent(window, 'unload', EventCache.flush);
addEvent(window, 'load', function(){alert("I'm ready");});

Liên kết thứ hai bị hỏng.
Peter Mortensen


4

Mã trình duyệt chéo này sẽ gọi một hàm khi DOM đã sẵn sàng:

var domReady=function(func){
    var scriptText='('+func+')();';
    var scriptElement=document.createElement('script');
    scriptElement.innerText=scriptText;
    document.body.appendChild(scriptElement);
};

Đây là cách nó hoạt động:

  1. Dòng đầu tiên domReadygọi toStringphương thức của hàm để có một chuỗi đại diện cho hàm bạn truyền vào và gói nó trong một biểu thức gọi hàm ngay lập tức.
  2. Phần còn lại của việc domReadytạo một phần tử script với biểu thức và nối nó vào phần bodycủa tài liệu.
  3. Trình duyệt chạy các thẻ script được nối vào bodysau khi DOM sẵn sàng.

Ví dụ: nếu bạn làm điều này : domReady(function(){alert();});, phần sau sẽ được thêm vào bodyphần tử:

 <script>(function (){alert();})();</script>

Lưu ý rằng điều này chỉ hoạt động cho các chức năng do người dùng xác định. Sau đây sẽ không hoạt động:domReady(alert);



3

Làm thế nào về giải pháp này?

// other onload attached earlier
window.onload=function() {
   alert('test');
};

tmpPreviousFunction=window.onload ? window.onload : null;

// our onload function
window.onload=function() {
   alert('another message');

   // execute previous one
   if (tmpPreviousFunction) tmpPreviousFunction();
};

3
Bạn có thể sử dụng addEventListener trên cửa sổ với "load". Người nghe được thực hiện từng cái một và không cần xâu chuỗi bằng tay.
Zaffy

1
Nhưng tải khác với sẵn sàng. 'Tải' thậm chí xảy ra trước khi tài liệu 'sẵn sàng'. Một tài liệu đã sẵn sàng có DOM được tải, một cửa sổ được tải không nhất thiết phải có sẵn DOM. Câu trả lời hay mặc dù
Mzn

1
@Mzn: Tôi nghĩ đó là ngược. Tôi nghĩ rằng tài liệu đã sẵn sàng xảy ra trước sự kiện tải cửa sổ. "Nói chung, không cần phải đợi tất cả các hình ảnh được tải đầy đủ. Nếu mã có thể được thực thi sớm hơn, tốt nhất là đặt nó trong một trình xử lý được gửi đến phương thức." (). " ( api.jquery.com/load-event )
Tyler Rick

điều này sẽ ghi đè phần còn lại của window.onload các sự kiện trên trang và sẽ gây ra sự cố. nó nên thêm sự kiện trên đầu trang hiện có.
Teoman shipahi

Sự kiện tải có thể xảy ra quá muộn. Thật đau đớn khi sử dụng nó khi phụ thuộc vào js / hình ảnh bên ngoài của bên thứ ba ... Một máy chủ không phản hồi mà bạn không kiểm soát và mọi thứ đều thất bại. Sử dụng DOMContentLoaded không chỉ là tối ưu hóa, nó còn an toàn hơn!
dotpush

3

Luôn luôn tốt khi sử dụng các mã JavaScript tương đương so với jQuery. Một lý do là một thư viện ít phụ thuộc hơn và chúng nhanh hơn nhiều so với các tương đương jQuery.

Một tài liệu tham khảo tuyệt vời cho tương đương jQuery là http://youmightnotneedjquery.com/ .

Theo như câu hỏi của bạn, tôi đã lấy đoạn mã dưới đây từ liên kết trên :) Chỉ có một lời cảnh báo là nó chỉ hoạt động với Internet Explorer 9 trở lên.

function ready(fn) {
    if (document.readyState != 'loading') {
        fn();
    }
    else {
        document.addEventListener('DOMContentLoaded', fn);
    }
}

3

Tối thiểu và làm việc 100%

Tôi đã chọn câu trả lời từ PlainJS và nó hoạt động tốt với tôi. Nó mở rộng DOMContentLoadedđể nó có thể được chấp nhận ở tất cả các trình duyệt.


Hàm này tương đương với $(document).ready()phương thức của jQuery :

document.addEventListener('DOMContentLoaded', function(){
    // do something
});

Tuy nhiên, trái ngược với jQuery, mã này sẽ chỉ chạy đúng trong các trình duyệt hiện đại (IE> 8) và nó sẽ không trong trường hợp tài liệu đã được hiển thị tại thời điểm tập lệnh này được chèn (ví dụ: thông qua Ajax). Do đó, chúng ta cần mở rộng điều này một chút:

function run() {
    // do something
}

// in case the document is already rendered
if (document.readyState!='loading') run();
// modern browsers
else if (document.addEventListener) 
document.addEventListener('DOMContentLoaded', run);
// IE <= 8
else document.attachEvent('onreadystatechange', function(){
    if (document.readyState=='complete') run();
});

Điều này về cơ bản bao gồm tất cả các khả năng và là sự thay thế khả thi cho trình trợ giúp jQuery.


2

Chúng tôi đã tìm thấy một triển khai trình duyệt chéo nhanh và bẩn của chúng tôi có thể thực hiện thủ thuật cho hầu hết các trường hợp đơn giản với việc triển khai tối thiểu:

window.onReady = function onReady(fn){
    document.body ? fn() : setTimeout(function(){ onReady(fn);},50);
};

cái gì doc.body!
Nabi KAZ

2

Các giải pháp setTimeout / setInterval được trình bày ở đây sẽ chỉ hoạt động trong các trường hợp cụ thể.

Vấn đề xuất hiện đặc biệt là trong các phiên bản Internet Explorer cũ hơn lên đến 8.

Các biến ảnh hưởng đến sự thành công của các giải pháp setTimeout / setInterval này là:

1) dynamic or static HTML
2) cached or non cached requests
3) size of the complete HTML document
4) chunked or non chunked transfer encoding

mã gốc (Javascript gốc) giải quyết vấn đề cụ thể này có ở đây:

https://github.com/dperini/ContentLoaded
http://javascript.nwbox.com/ContentLoaded (test)

đây là mã mà nhóm jQuery đã xây dựng triển khai của họ.


1

Đây là những gì tôi sử dụng, nó nhanh và bao gồm tất cả các cơ sở tôi nghĩ; hoạt động cho mọi thứ trừ IE <9.

(() => { function fn() {
    // "On document ready" commands:
    console.log(document.readyState);
};  
  if (document.readyState != 'loading') {fn()}
  else {document.addEventListener('DOMContentLoaded', fn)}
})();

Điều này dường như để bắt tất cả các trường hợp:

  • kích hoạt ngay lập tức nếu DOM đã sẵn sàng (nếu DOM không "tải", nhưng "tương tác" hoặc "hoàn thành")
  • nếu DOM vẫn đang tải, nó sẽ thiết lập một trình lắng nghe sự kiện khi DOM khả dụng (tương tác).

Sự kiện DOMContentLoaded có sẵn trong IE9 và mọi thứ khác, vì vậy cá nhân tôi nghĩ rằng sử dụng nó là ổn. Viết lại khai báo hàm mũi tên thành một hàm ẩn danh thông thường nếu bạn không dịch mã từ ES2015 sang ES5.

Nếu bạn muốn đợi cho đến khi tất cả các tài sản được tải, tất cả hình ảnh được hiển thị, v.v., sau đó sử dụng window.onload.


1

Nếu bạn không phải hỗ trợ các trình duyệt cũ, đây là một cách để làm điều đó ngay cả khi tập lệnh bên ngoài của bạn được tải với thuộc tính async :

HTMLDocument.prototype.ready = new Promise(function(resolve) {
   if(document.readyState != "loading")
      resolve();
   else
      document.addEventListener("DOMContentLoaded", function() {
         resolve();
      });
});

document.ready.then(function() {
   console.log("document.ready");
});

0

Dành cho IE9 +:

function ready(fn) {
  if (document.readyState != 'loading'){
    fn();
  } else {
    document.addEventListener('DOMContentLoaded', fn);
  }
}

0

Nếu bạn đang tải jQuery ở gần cuối BODY, nhưng gặp sự cố với mã ghi ra jQuery (<func>) hoặc jQuery (tài liệu). Đã (<func>), hãy xem jqShim trên Github.

Thay vì tạo lại chức năng sẵn sàng tài liệu của riêng mình, nó chỉ đơn giản giữ các chức năng cho đến khi jQuery có sẵn sau đó tiến hành với jQuery như mong đợi. Điểm di chuyển jQuery xuống dưới cùng của cơ thể là tăng tốc độ tải trang và bạn vẫn có thể hoàn thành nó bằng cách đặt nội dung jqShim.min.js vào đầu mẫu của bạn.

Cuối cùng tôi đã viết mã này để chuyển tất cả các tập lệnh trong WordPress sang chân trang và chỉ mã shim này hiện nằm ngay trong tiêu đề.


0

Thử cái này:

function ready(callback){
    if(typeof callback === "function"){
        document.addEventListener("DOMContentLoaded", callback);
        window.addEventListener("load", callback);
    }else{
        throw new Error("Sorry, I can not run this!");
    }
}
ready(function(){
    console.log("It worked!");
});

Bạn sẽ chạy cuộc gọi lại hai lần
Andrew

0
function onDocReady(fn){ 
    $d.readyState!=="loading" ? fn():document.addEventListener('DOMContentLoaded',fn);
}

function onWinLoad(fn){
    $d.readyState==="complete") ? fn(): window.addEventListener('load',fn);
} 

onDocReady cung cấp một cuộc gọi lại khi dom HTML sẵn sàng truy cập / phân tích / thao tác đầy đủ.

onWinLoad cung cấp một cuộc gọi lại khi mọi thứ đã được tải (hình ảnh, v.v.)

  • Các chức năng này có thể được gọi bất cứ khi nào bạn muốn.
  • Hỗ trợ nhiều "người nghe".
  • Sẽ hoạt động trong mọi trình duyệt.

0
(function(f){
  if(document.readyState != "loading") f();
  else document.addEventListener("DOMContentLoaded", f);
})(function(){
  console.log("The Document is ready");
});

Điều này thêm gì mà các câu trả lời khác không?
dwjohnston

Nó sử dụng một bao đóng khép kín (không điền vào phạm vi "cửa sổ" toàn cầu), nó hoạt động trên tất cả các trình duyệt và rất nhỏ gọn. Tôi không thấy bất kỳ câu trả lời khác như nó.
Dustin Poissant

Nó cũng hoạt động ngay cả sau khi DOM đã được tải (như jQuery. Đã làm), điều mà hầu hết các câu trả lời này không thực hiện được.
Dustin Poissant

0

Hầu hết các hàm vanilla JS Ready KHÔNG xem xét kịch bản nơi DOMContentLoadedtrình xử lý được đặt sau khi tài liệu đã được tải - Điều đó có nghĩa là hàm sẽ không bao giờ chạy . Điều này có thể xảy ra nếu bạn tìm kiếm DOMContentLoadedtrong một asynctập lệnh bên ngoài ( <script async src="file.js"></script>).

Mã dưới đây chỉ kiểm tra DOMContentLoadednếu tài liệu readyStatechưa interactivehoặc complete.

var DOMReady = function(callback) {
  document.readyState === "interactive" || document.readyState === "complete" ? callback() : document.addEventListener("DOMContentLoaded", callback());
};
DOMReady(function() {
  //DOM ready!
});

Nếu bạn muốn hỗ trợ IE cũng như:

var DOMReady = function(callback) {
    if (document.readyState === "interactive" || document.readyState === "complete") {
        callback();
    } else if (document.addEventListener) {
        document.addEventListener('DOMContentLoaded', callback());
    } else if (document.attachEvent) {
        document.attachEvent('onreadystatechange', function() {
            if (document.readyState != 'loading') {
                callback();
            }
        });
    }
};

DOMReady(function() {
  // DOM ready!
});

0

Tôi chỉ đơn giản là sử dụng:

setTimeout(function(){
    //reference/manipulate DOM here
});

Và không giống document.addEventListener("DOMContentLoaded" //etcnhư trong câu trả lời hàng đầu, nó hoạt động xa như IE9 - http://caniuse.com/#search=DOMContentLoaded chỉ biểu thị gần đây như IE11.

Thật thú vị, tôi đã vấp phải setTimeoutgiải pháp này vào năm 2009: Có phải việc kiểm tra mức độ sẵn sàng của DOM quá mức không?, điều có lẽ có thể được diễn đạt tốt hơn một chút, vì ý tôi là "việc sử dụng các cách tiếp cận phức tạp hơn của các khung khác nhau để kiểm tra mức độ sẵn sàng của DOM" là quá mức cần thiết.

Giải thích tốt nhất của tôi về lý do tại sao kỹ thuật này hoạt động là, khi tập lệnh có setTimeout như vậy đã đạt được, DOM ở giữa bị phân tích cú pháp, do đó việc thực thi mã trong setTimeout bị hoãn lại cho đến khi hoạt động đó kết thúc.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.