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)
