ค้นหาเว็บไซต์

javascript - Userscript เทคนิคในการรอให้หน้าเว็บโหลดเสร็จก่อนรันโค้ด?


ฉันกำลังเขียนสคริปต์ผู้ใช้ Greasemonkey และต้องการโค้ดเฉพาะเพื่อให้ทำงานเมื่อหน้าเว็บโหลดเสร็จสมบูรณ์ เนื่องจากมันส่งคืนจำนวน div ที่ฉันต้องการให้แสดง

ปัญหาคือ หน้าหน้านี้บางครั้งใช้เวลาสักครู่ก่อนที่ทุกอย่างจะโหลดเสร็จ

ฉันได้ลองใช้ตัวห่อเอกสาร $ (function() { }); และ $ (window).load(function(){ }); แล้ว อย่างไรก็ตาม ไม่มีตัวไหนที่ดูเหมือนจะใช้ได้สำหรับฉัน ถึงแม้ว่าฉันอาจจะใช้มันผิดวิธี

สิ่งที่ฉันทำได้ดีที่สุดคือใช้ setTimeout(function() { }, 600); ซึ่งสามารถใช้งานได้ แม้ว่าจะไม่เสมอไปที่เชื่อถือได้

เทคนิคที่ดีที่สุดในการใช้ใน Greasemonkey เพื่อให้แน่ใจว่ารหัสเฉพาะจะทำงานเมื่อหน้าสิ้นสุดการโหลดคืออะไร?

คำตอบ #1

Greasemonkey (โดยทั่วไป) มักจะไม่มี jQuery ดังนั้นแนวทางที่ใช้กันทั่วไปคือการใช้

window.addEventListener('load', function() {
    // your code here
}, false);

ภายในสคริปต์ผู้ใช้ของคุณ

คำตอบ #2

นี่เป็นปัญหาที่พบบ่อย และตามที่คุณได้กล่าวไว้ การรอให้หน้าเว็บโหลดนั้นไม่เพียงพอ -- เนื่องจาก AJAX สามารถและก็เปลี่ยนแปลงสิ่งต่าง ๆ หลังจากนั้นเป็นเวลานาน

มียูทิลิตี้ที่แข็งแกร่งแบบมาตรฐาน(ประมาณ) สำหรับสถานการณ์เหล่านี้ มันคือยูทิลิตี้ waitForKeyElements().

ใช้มันแบบนี้:

// ==UserScript==
// @name     _Wait for delayed or AJAX page load
// @include  http://YOUR_SERVER.COM/YOUR_PATH/*
// @require  https://raw.githubusercontent.com/CoeJoder/waitForKeyElements.js/refs/heads/master/waitForKeyElements.js
// @grant    GM_addStyle
// ==/UserScript==
/*- The @grant directive is needed to work around a major design
    change introduced in GM 1.0. It restores the sandbox.

    If in Tampermonkey, use "// @unwrap" to enable sandbox instead.
*/

waitForKeyElements ("YOUR_jQUERY_SELECTOR", actionFunction);

function actionFunction (jNode) {
    //-- DO WHAT YOU WANT TO THE TARGETED ELEMENTS HERE.
    jNode.css ("background", "yellow"); // example
}

ให้รายละเอียดที่แน่นอนของหน้าที่คุณต้องการเพื่อเป็นตัวอย่างที่เฉพาะเจาะจงมากขึ้น

คำตอบ #3

ฉันอยากจะเสนอวิธีแก้ปัญหา AJAX อีกวิธีหนึ่งที่ทันสมัยและสง่างามมากขึ้น

สคริปต์ของ Brock เหมือนกับโซลูชันส่วนใหญ่ ใช้ setInterval() หรือ setTimeout() เป็นแกนหลักในการตรวจสอบองค์ประกอบเป็นระยะ ดังนั้นจึงไม่สามารถตอบสนองได้ทันทีและมักมีความล่าช้าบ้าง โซลูชันอื่น ๆ ใช้เหตุการณ์ onload ซึ่งมักจะทำงานเร็วกว่าที่คุณต้องการในหน้าที่มีการเปลี่ยนแปลงแบบไดนามิก

วิธีแก้ปัญหา: ใช้ MutationObserver() เพื่อติดตามการเปลี่ยนแปลงของ DOM โดยตรงเพื่อตอบสนองทันทีหลังจากที่มีการแทรกองค์ประกอบ

(new MutationObserver(check)).observe(document, {childList: true, subtree: true});

function check(changes, observer) {
    if(document.querySelector('#mySelector')) {
        observer.disconnect();
        // actions to perform after #mySelector is found
    }
}

ฟังก์ชัน check จะทำงานทันทีหลังจากการเปลี่ยนแปลง DOM ทุกครั้ง ซึ่งช่วยให้คุณสามารถระบุเงื่อนไขตัวกระตุ้นได้ตามต้องการ เพื่อให้คุณรอจนกว่าเพจจะอยู่ในสถานะที่ต้องการก่อนที่คุณจะรันโค้ดของคุณเอง

โปรดทราบว่า นี่อาจช้าได้หาก DOM มีการเปลี่ยนแปลงบ่อยมากหรือเงื่อนไขของคุณใช้เวลานานในการประเมิน ดังนั้นแทนที่จะสังเกต document ลองจำกัดขอบเขตโดยสังเกตส่วนย่อยของ DOM ที่เล็กที่สุดเท่าที่จะทำได้

วิธีนี้เป็นวิธีทั่วไปมากและสามารถนำไปใช้กับหลายสถานการณ์ได้ ในการตอบหลายครั้ง เพียงแค่ไม่ตัดการเชื่อมต่อผู้สังเกตเมื่อถูกกระตุ้น

กรณีการใช้งานอีกอย่างคือหากคุณไม่ได้มองหาองค์ประกอบเฉพาะใด ๆ แต่เพียงแค่รอให้หน้าหยุดเปลี่ยนแปลง คุณสามารถรวมสิ่งนี้กับตัวจับเวลา idle ที่จะรีเซ็ตเมื่อหน้าเปลี่ยนแปลงได้

var observer = new MutationObserver(resetTimer);
var timer = setTimeout(action, 3000, observer); // wait for the page to stay still for 3 seconds
observer.observe(document, {childList: true, subtree: true});

// reset timer every time something changes
function resetTimer(changes, observer) {
    clearTimeout(timer);
    timer = setTimeout(action, 3000, observer);
}

function action(observer) {
    observer.disconnect();
    // code
}

คุณสามารถฟังการเปลี่ยนแปลงของแอตทริบิวต์และข้อความได้เช่นกัน แค่ตั้งค่า attributes และ characterData เป็น true ในตัวเลือก

observer.observe(document, {childList: true, attributes: true, characterData: true, subtree: true});

และถ้าคุณต้องการใช้มันในรูปแบบ async/await คุณสามารถทำบางอย่างได้แบบนี้

function wait_element(root, selector) {
  return new Promise((resolve, reject) => {
    (new MutationObserver(check)).observe(root, {childList: true, subtree: true});
    function check(changes, observer) {
      let element = root.querySelector(selector);
      if(element) {
        observer.disconnect();
        resolve(element);
      }
    }
  });
}

let node = await wait_element(document, '#mySelector');

คำตอบ #4

ตั้งแต่ Greasemonkey 3.6 (20 พฤศจิกายน 2015) คีย์เมทาดาต้า @run-at รองรับค่าชนิดใหม่ document-idle เพียงใส่สิ่งนี้ลงในบล็อกเมทาดาต้าของสคริปต์ Greasemonkey ของคุณ:

// @run-at      document-idle

เอกสารอธิบายเกี่ยวกับมันดังนี้:

สคริปต์จะทำงานหลังจากที่หน้าเว็บและทรัพยากรทั้งหมด (รูปภาพ, แผ่นสไตล์, ฯลฯ) ถูกโหลดและสคริปต์ของหน้าเว็บได้ทำงานแล้ว

คำตอบ #5

การห่อสคริปต์ของฉันใน $ (window).load(function(){ }) ไม่เคยล้มเหลวสำหรับฉัน

บางทีหน้าเพจของคุณอาจโหลดเสร็จแล้ว แต่ยังมีเนื้อหา Ajax บางส่วนที่กำลังโหลดอยู่

:

ฉันมักจะใช้มันเพื่อตรวจสอบองค์ประกอบที่ปรากฏบน postback

ใช้มันแบบนี้: waitForKeyElements("elementtowaitfor", functiontocall)

บทความที่เกี่ยวข้อง