جاوااسکریپت - اسکریپت کاربری برای انتظار بارگذاری صفحه قبل از اجرای تکنیکهای کد؟


من در حال نوشتن یک اسکریپت کاربری Greasemonkey هستم و میcخواهم یک کد خاص زمانی که صفحه به طور کامل بارگذاری شد اجرا شود زیرا تعداد divcهایی را که میcخواهم نمایش دهم را برمیcگرداند.

مشکل این است که این صفحه خاص گاهی کمی طول میکشد تا همه چیز بارگذاری شود.

من تلاش کردهام، مستند $ (function() { }); و $ (window).load(function(){ }); بستهبندیها. با این حال، به نظر میرسد هیچکدام برای من کار نمیکنند، هرچند ممکن است آنها را به اشتباه اعمال کرده باشم.

بهترین کاری که میتوانم انجام دهم استفاده از setTimeout(function() { }, 600); است که کار میکند، اگرچه همیشه قابل اعتماد نیست.

بهترین تکنیک برای استفاده در Greasemonkey چیست تا اطمینان حاصل شود که کد مشخص وقتی صفحه بارگذاری شد اجرا خواهد شد؟

پاسخ شماره ۱

گرِیزمانکی (معمولاً) جیکوئری ندارد. بنابراین روش معمول استفاده از

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

درون اسکریپت کاربران شما

پاسخ شماره ۲

این یک مشکل رایج است و همانطور که گفتهاید، صبر کردن برای بارگذاری صفحه کافی نیست -- زیرا 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
}

جزئیات دقیق صفحه هدف خود را برای یک مثال مشخصتر ارائه دهید.

پاسخ شماره ۳

میخواهم یک راه حل دیگر برای مشکل AJAX ارائه دهم که مدرنتر و شیکتر باشد.

اسکریپت بروک، مانند اکثر راهحلها، در هسته خود از 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 که تا حد ممکن کوچک است محدوده را محدود کنید.

این روش بسیار عمومی است و میتواند در شرایط زیادی اعمال شود. برای پاسخدهی چندباره، فقط کافی است هنگام فعال شدن ناظر را قطع نکنید.

یک مورد استفاده دیگر این است که اگر به دنبال هیچ عنصر خاصی نیستید، اما فقط منتظر هستید که صفحه دیگر تغییر نکند، میتوانید این را با یک تایمر بیکاری که هنگام تغییر صفحه دوباره تنظیم میشود، ترکیب کنید.

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');

پاسخ شماره ۴

از نسخهی Greasemonkey 3.6 (۲۰ نوامبر ۲۰۱۵) کلید متادیتا @run-at از مقدار جدید document-idle پشتیبانی میکند. به سادگی این را در بلوک متادیتای اسکریپت Greasemonkey خود قرار دهید:

// @run-at      document-idle

مستندات آن را به صورت زیر توصیف میکند:

این اسکریپت پس از بارگذاری صفحه و همه منابع آن (تصاویر، برگههای سبک و غیره) و اجرای اسکریپتهای صفحه اجرا خواهد شد.

پاسخ شماره ۵

پیچاندن اسکریپتهایم در $ (window).load(function(){ }) هرگز برای من شکست نخورد.

ممکن است صفحه شما تمام شده باشد، اما هنوز برخی محتوای ایجکس در حال بارگذاری است.

:

من معمولاً از آن برای نظارت بر عناصری که در postback ظاهر میشوند استفاده میکنم.

از آن به این صورت استفاده کنید: waitForKeyElements("elementtowaitfor", functiontocall)