it-swarm.asia

مكافئ جافا سكريبت خالص jQuery's $ .ready () - كيفية استدعاء دالة عندما تكون الصفحة/DOM جاهزة لها

حسنًا ، قد يكون هذا مجرد سؤال سخيف ، على الرغم من أنني متأكد من أن هناك الكثير من الأشخاص الذين يسألون نفس السؤال من وقت لآخر. أنا فقط أريد أن أتأكد 100 ٪ من ذلك في كلتا الحالتين. مع jQuery نعلم جميعا رائعة

$('document').ready(function(){});

ومع ذلك ، دعنا نقول أنني أريد تشغيل وظيفة مكتوبة بلغة جافا سكريبت قياسية دون وجود مكتبة تدعمها ، وأريد تشغيل وظيفة بمجرد أن تصبح الصفحة جاهزة للتعامل معها. ما هي الطريقة الصحيحة للتعامل مع هذا؟

أعلم أنني أستطيع أن أفعل:

window.onload="myFunction()";

... أو يمكنني استخدام العلامة body:

<body onload="myFunction()">

... أو يمكنني حتى أن أحاول في أسفل الصفحة بعد كل شيء ، ولكن علامة body أو html في نهاية الصفحة مثل:

<script type="text/javascript">
   myFunction();
</script>

ما الطريقة المتوافقة مع المستعرضات (القديمة/الجديدة) لإصدار وظيفة واحدة أو أكثر بطريقة مثل وظيفة jQuery $.ready()؟

1100
chris

إن أبسط شيء يمكن القيام به في حالة عدم وجود إطار عمل يقوم بتوافق جميع المستعرضات هو أن تقوم بإجراء مكالمة على الكود في نهاية النص. يعد هذا التنفيذ أسرع من معالج onload لأن هذا ينتظر فقط أن يكون DOM جاهزًا ، وليس لتحميل جميع الصور. وهذا يعمل في كل متصفح.

<html>
<head>
</head>
<body>
Your HTML here

<script>
// self executing function here
(function() {
   // your page initialization code here
   // the DOM will be available here

})();
</script>
</body>
</html>

إذا كنت لا تريد فعل ذلك بهذه الطريقة وتحتاج إلى توافق عبر المستعرض ولا تريد انتظار window.onload ، فربما يجب عليك إلقاء نظرة على كيفية تنفيذ إطار مثل jQuery لطريقة $(document).ready() الخاصة به. انها تشارك إلى حد ما اعتمادا على قدرات المتصفح.

لإعطائك فكرة صغيرة عما يفعله jQuery (والذي سيعمل أينما وضعت علامة البرنامج النصي).

إذا كان مدعومًا ، فإنه يحاول المعيار:

document.addEventListener('DOMContentLoaded', fn, false);

مع عودة إلى:

window.addEventListener('load', fn, false )

أو للإصدارات الأقدم من IE ، فإنه يستخدم:

document.attachEvent("onreadystatechange", fn);

مع عودة إلى:

window.attachEvent("onload", fn);

وهناك بعض الحلول في مسار الكود IE الذي لا أتبعه تمامًا ، لكن يبدو أن له علاقة بالإطارات.


هنا بديل كامل عن jQuery's .ready() المكتوب بلغة جافا سكريبت العادية:

(function(funcName, baseObj) {
    // The public function name defaults to window.docReady
    // but you can pass in your own object and own function name and those will be used
    // if you want to put them in a different namespace
    funcName = funcName || "docReady";
    baseObj = baseObj || window;
    var readyList = [];
    var readyFired = false;
    var readyEventHandlersInstalled = false;

    // call this when the document is ready
    // this function protects itself against being called more than once
    function ready() {
        if (!readyFired) {
            // this must be set to true before we start calling callbacks
            readyFired = true;
            for (var i = 0; i < readyList.length; i++) {
                // if a callback here happens to add new ready handlers,
                // the docReady() function will see that it already fired
                // and will schedule the callback to run right after
                // this event loop finishes so all handlers will still execute
                // in order and no new ones will be added to the readyList
                // while we are processing the list
                readyList[i].fn.call(window, readyList[i].ctx);
            }
            // allow any closures held by these functions to free
            readyList = [];
        }
    }

    function readyStateChange() {
        if ( document.readyState === "complete" ) {
            ready();
        }
    }

    // This is the one public interface
    // docReady(fn, context);
    // the context argument is optional - if present, it will be passed
    // as an argument to the callback
    baseObj[funcName] = function(callback, context) {
        if (typeof callback !== "function") {
            throw new TypeError("callback for docReady(fn) must be a function");
        }
        // if ready has already fired, then just schedule the callback
        // to fire asynchronously, but right away
        if (readyFired) {
            setTimeout(function() {callback(context);}, 1);
            return;
        } else {
            // add the function and context to the list
            readyList.Push({fn: callback, ctx: context});
        }
        // if document already ready to go, schedule the ready function to run
        if (document.readyState === "complete") {
            setTimeout(ready, 1);
        } else if (!readyEventHandlersInstalled) {
            // otherwise if we don't have event handlers installed, install them
            if (document.addEventListener) {
                // first choice is DOMContentLoaded event
                document.addEventListener("DOMContentLoaded", ready, false);
                // backup is window load event
                window.addEventListener("load", ready, false);
            } else {
                // must be IE
                document.attachEvent("onreadystatechange", readyStateChange);
                window.attachEvent("onload", ready);
            }
            readyEventHandlersInstalled = true;
        }
    }
})("docReady", window);

تتم مشاركة أحدث إصدار من الشفرة بشكل عام على GitHub على https://github.com/jfriend00/docReady

الاستعمال:

// pass a function reference
docReady(fn);

// use an anonymous function
docReady(function() {
    // code here
});

// pass a function reference and a context
// the context will be passed to the function as the first argument
docReady(fn, context);

// use an anonymous function with a context
docReady(function(context) {
    // code here that can use the context argument that was passed to docReady
}, ctx);

تم اختبار هذا في:

IE6 and up
Firefox 3.6 and up
Chrome 14 and up
Safari 5.1 and up
Opera 11.6 and up
Multiple iOS devices
Multiple Android devices

تنفيذ العمل واختبار السرير: http://jsfiddle.net/jfriend00/YfD3C/


فيما يلي ملخص لكيفية عمله:

  1. قم بإنشاء IIFE (تعبير دالة تم استدعاؤه على الفور) حتى نتمكن من الحصول على متغيرات حالة غير عامة.
  2. أعلن وظيفة عامة docReady(fn, context)
  3. عند استدعاء docReady(fn, context) ، تحقق مما إذا كان المعالج الجاهز قد أطلق بالفعل. إذا كان الأمر كذلك ، فكل ما عليك هو جدولة رد الاتصال الذي تمت إضافته حديثًا لإطلاقه مباشرة بعد انتهاء مؤشر ترابط JS هذا بـ setTimeout(fn, 1).
  4. إذا لم يتم تشغيل معالج الاستعداد بالفعل ، فقم بإضافة رد الاتصال الجديد هذا إلى قائمة عمليات رد الاتصال التي سيتم الاتصال بها لاحقًا.
  5. تحقق مما إذا كان المستند جاهزًا بالفعل. إذا كان الأمر كذلك ، فقم بتنفيذ جميع معالجات جاهزة.
  6. إذا لم نقم بتثبيت مستمعي الأحداث حتى الآن لمعرفة متى يصبح المستند جاهزًا ، فقم بتثبيته الآن.
  7. إذا كان document.addEventListener موجودًا ، فقم بتثبيت معالجات الأحداث باستخدام .addEventListener() لكل من أحداث "DOMContentLoaded" و "load". يعد "الحمل" حدثًا احتياطيًا للسلامة ويجب عدم الحاجة إليه.
  8. إذا لم يكن هناك document.addEventListener ، فقم بتثبيت معالجات الأحداث باستخدام .attachEvent() لأحداث "onreadystatechange" و "onload".
  9. في الحدث onreadystatechange ، تحقق لمعرفة ما إذا كان document.readyState === "complete" وإذا كان الأمر كذلك ، فاتصل بوظيفة لإطلاق جميع المعالجات الجاهزة.
  10. في جميع معالجات الأحداث الأخرى ، استدعاء دالة لإطلاق جميع معالجات جاهزة.
  11. في وظيفة استدعاء جميع المعالجات الجاهزة ، تحقق من متغير الحالة لمعرفة ما إذا كنا قد أطلقناها بالفعل. إذا كان لدينا ، لا تفعل شيئا. إذا لم يتم الاتصال بنا حتى الآن ، فقم بإجراء حلقة من مجموعة الوظائف الجاهزة واستدعاء كل واحدة بالترتيب الذي تمت إضافتها به. قم بتعيين إشارة للإشارة إلى أنه تم استدعاء جميعها حتى لا يتم تنفيذها أكثر من مرة.
  12. امسح صفيف الوظائف بحيث يمكن تحرير أي عمليات إغلاق قد تستخدمها.

نضمن أن يتم تشغيل معالجات التسجيل بـ docReady() بالترتيب الذي تم تسجيلهم فيه.

إذا قمت بالاتصال بـ docReady(fn) بعد إعداد المستند بالفعل ، فسيتم جدولة رد الاتصال للتنفيذ بمجرد اكتمال سلسلة عمليات التنفيذ الحالية باستخدام setTimeout(fn, 1). يسمح هذا لرمز الاتصال دائمًا بافتراض أنها عمليات رد اتصال غير متزامنة سيتم استدعاؤها لاحقًا ، حتى لو كان ذلك لاحقًا بمجرد انتهاء سلسلة الرسائل الحالية من JS والحفاظ على ترتيب الاتصال.

1593
jfriend00

أود أن أذكر بعض الطرق الممكنة هنا مع خدعة جافا سكريبت الخالصة التي تعمل في جميع المتصفحات :

// with jQuery 
$(document).ready(function(){ /* ... */ });

// shorter jQuery version 
$(function(){ /* ... */ });

// without jQuery (doesn't work in older IEs)
document.addEventListener('DOMContentLoaded', function(){ 
    // your code goes here
}, false);

// and here's the trick (works everywhere)
function r(f){/in/.test(document.readyState)?setTimeout('r('+f+')',9):f()}
// use like
r(function(){
    alert('DOM Ready!');
});

الخدعة هنا ، كما أوضحها المؤلف المؤلف الأصلي ، هي أننا نقوم بفحص document.readyState property. إذا كان يحتوي على السلسلة in (كما هو الحال في uninitialized و loading ، أول حالتين جاهزتين لـ DOM من 5) ، فسنقوم بتعيين مهلة والتحقق مرة أخرى. خلاف ذلك ، نقوم بتنفيذ وظيفة مرت.

وإليك jsFiddle للخدعة التي تعمل عبر جميع المتصفحات.

بفضل Tutorialzine لإدراج هذا في كتابهم.

134
Ram Patra

إذا كنت تقوم Vanilla plain JavaScript بدون jQuery ، فيجب عليك استخدام (Internet Explorer 9 أو إصدار أحدث):

document.addEventListener("DOMContentLoaded", function(event) {
    // Your code to run since DOM is loaded and ready
});

أعلاه مكافئ jQuery .ready:

$(document).ready(function() {
    console.log("Ready!");
});

أيهما يمكن أيضًا كتابة SHORTHAND مثل هذا ، والذي سيتم تشغيل jQuery بعده جاهز حتى { يحدث .

$(function() {
    console.log("ready!");
});

يجب عدم الخلط بينك وبين BELOW (ليس المقصود منه أن يكون جاهزًا لـ DOM):

لا تستخدم (_ iife _ مثل هذا الذي يتم تنفيذه ذاتيا:

 Example:

(function() {
   // Your page initialization code here  - WRONG
   // The DOM will be available here   - WRONG
})();

هذا IIFE لن ينتظر DOM الخاص بك لتحميل. (أنا أتحدث عن أحدث إصدار من متصفح Chrome!)

113
Tom Stickel

تم اختباره في IE9 وأحدث فايرفوكس وكروم وأيضًا دعمهما في IE8.

document.onreadystatechange = function () {
  var state = document.readyState;
  if (state == 'interactive') {
      init();
  } else if (state == 'complete') {
      initOnCompleteLoad();
  }
}​;

مثال: http://jsfiddle.net/electricvisions/Jacck/

تحديث - نسخة قابلة لإعادة الاستخدام

لقد وضعت للتو ما يلي. إنه مكافئ بسيط إلى حد ما لمسج أو جاهز دوم دون التوافق مع الإصدارات السابقة. ربما يحتاج إلى مزيد من الصقل. تم اختباره في أحدث إصدارات Chrome و Firefox و IE (10/11) ويجب أن يعمل في المتصفحات القديمة كما علق عليها. سوف أقوم بتحديث إذا وجدت أي مشاكل.

window.readyHandlers = [];
window.ready = function ready(handler) {
  window.readyHandlers.Push(handler);
  handleState();
};

window.handleState = function handleState () {
  if (['interactive', 'complete'].indexOf(document.readyState) > -1) {
    while(window.readyHandlers.length > 0) {
      (window.readyHandlers.shift())();
    }
  }
};

document.onreadystatechange = window.handleState;

الاستعمال:

ready(function () {
  // your code here
});

إنه مكتوب للتعامل مع التحميل غير المتزامن لـ JS ولكن قد ترغب في مزامنة تحميل هذا البرنامج النصي أولاً إلا إذا كنت تقوم بالتصغير. لقد وجدت أنه من المفيد في التنمية.

تدعم المتصفحات الحديثة أيضًا تحميل البرامج النصية غير المتزامن مما يعزز التجربة. يعني دعم المزامنة أنه يمكن تنزيل برامج نصية متعددة في وقت واحد ، مع الاستمرار في عرض الصفحة. فقط انتبه عند الاعتماد على البرامج النصية الأخرى التي يتم تحميلها بشكل غير متزامن أو استخدام مصغر أو ما يشبه المتصفح لتصفح التبعيات.

75
PhilT

الأشخاص الجيدون في HubSpot لديهم مورد حيث يمكنك العثور على منهجيات جافا سكريبت الخالصة لتحقيق الكثير من الصلاحيات الرائعة - بما في ذلك ready

http://youmightnotneedjquery.com/#ready

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();
    });
  }
}

مثال استخدام مضمّن:

ready(function() { alert('hello'); });
17
Lorcan O'Neill

طريقتك (وضع البرنامج النصي قبل علامة نص الإغلاق)

<script>
   myFunction()
</script>
</body>
</html>

هي طريقة موثوقة لدعم المتصفحات القديمة والجديدة.

7
Kernel James

لست متأكدًا مما تطلبه ، لكن ربما يساعد ذلك:

window.onload = function(){
    // Code. . .

}

أو:

window.onload = main;

function main(){
    // Code. . .

}
4
Zak The Hat

جاهز

function ready(fn){var d=document;(d.readyState=='loading')?d.addEventListener('DOMContentLoaded',fn):fn();}

استخدام مثل

ready(function(){
    //some code
});

لاستدعاء رمز النفس

(function(fn){var d=document;(d.readyState=='loading')?d.addEventListener('DOMContentLoaded',fn):fn();})(function(){

    //Some Code here
    //DOM is avaliable
    //var h1s = document.querySelector("h1");

});

الدعم: IE9 +

4
Vitim.us

فيما يلي نسخة تنظيف/غير مستخدمة من Ram-swaroop's "يعمل في جميع المتصفحات" - يعمل في جميع المتصفحات!

function onReady(yourMethod) {
  var readyStateCheckInterval = setInterval(function() {
    if (document && document.readyState === 'complete') { // Or 'interactive'
      clearInterval(readyStateCheckInterval);
      yourMethod();
    }
  }, 10);
}
// use like
onReady(function() { alert('hello'); } );

لا ينتظر تشغيل 10 مللي ثانية إضافية ، ومع ذلك ، إليك طريقة أكثر تعقيدًا لا ينبغي:

function onReady(yourMethod) {
  if (document.readyState === 'complete') { // Or also compare to 'interactive'
    setTimeout(yourMethod, 1); // Schedule to run immediately
  }
  else {
    readyStateCheckInterval = setInterval(function() {
      if (document.readyState === 'complete') { // Or also compare to 'interactive'
        clearInterval(readyStateCheckInterval);
        yourMethod();
      }
    }, 10);
  }
}

// Use like
onReady(function() { alert('hello'); } );

// Or
onReady(functionName);

راجع أيضًاكيفية التحقق مما إذا كان DOM جاهزًا بدون إطار عمل؟.

3
rogerdpack

document.ondomcontentready=function(){} يجب أن تقوم بالخدعة ، لكن ليس لديها توافق متصفح كامل.

يبدو أنك يجب أن تستخدم فقط مسج دقيقة

2
maxhud