yssWaitForNode

Be smart!

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.gf.qytechs.cn/scripts/454354/1145153/yssWaitForNode.js

  1. // ==UserScript==
  2. // @name yssWaitForNode
  3. // @namespace https://ysslang.com/
  4. // @version 1.2.4.1
  5. // @description Be smart!
  6. // @author ysslang
  7. // @match *://*/*
  8. // @supportURL https://gf.qytechs.cn/scripts/454354
  9. // @run-at document-start
  10. // @grant none
  11. // ==/UserScript==
  12.  
  13. /* Done
  14. - 去除返回元素中的重复元素, 避免重复执行; bugfix: 忘记加const了;
  15. */
  16.  
  17. class WaitForNode {
  18. #currentURL;
  19. #observerList = [];
  20. #waitList = [];
  21.  
  22. constructor() { this.#currentURL = window.location.href; }
  23.  
  24. #checkIfUrlMatch(matcher) {
  25. var result = false;
  26. if (matcher === undefined || matcher === null) result = false;
  27. if (typeof matcher === "string") result = new RegExp(matcher.trim()).test(this.#currentURL);
  28. if (matcher instanceof RegExp) result = matcher.test(this.#currentURL);
  29. return result;
  30. }
  31.  
  32. #determineParentElement(arg) {
  33. var result = document;
  34. if (typeof arg === "string" && document.querySelector(arg)) result = document.querySelector(arg);
  35. if (arg instanceof Element) result = arg;
  36. return result;
  37. }
  38.  
  39. #mergeOptions(options) {
  40. options = options || {};
  41. var result = {
  42. immediate: [options.immediate, options.imdt, true].find((e) => typeof (e) !== 'undefined'),
  43. recursive: [options.recursive, options.rcs, true].find((e) => typeof (e) !== 'undefined'),
  44. once: [options.once, false].find((e) => typeof (e) !== 'undefined'),
  45. subtree: [options.subtree, options.sbt, true].find((e) => typeof (e) !== 'undefined'),
  46. childList: [options.childList, options.cld, true].find((e) => typeof (e) !== 'undefined'),
  47. parentEl: this.#determineParentElement(options.parent),
  48. };
  49. return result;
  50. }
  51.  
  52. #extractMatchedElements(mutations, selector, recursive) {
  53. const matchedElements = [];
  54. for (const { addedNodes } of mutations) {
  55. for (const node of addedNodes) {
  56. if (!node.tagName) continue;
  57. else if (node.matches(selector)) matchedElements.push(node);
  58. else if (recursive && node.firstElementChild) matchedElements.push(...node.querySelectorAll(selector));
  59. }
  60. }
  61. const result = [...new Set(matchedElements)]
  62. return result;
  63. }
  64.  
  65. #on(selector, callback, options) {
  66. if (options.immediate) {
  67. [...options.parentEl.querySelectorAll(selector)].forEach(callback);
  68. }
  69. const observer = new MutationObserver((mutations) => {
  70. const elements = this.#extractMatchedElements(mutations, selector, options.recursive);
  71. elements.forEach(callback);
  72. if (elements && options.once) this.disconnect();
  73. });
  74. observer.observe(options.parentEl, { subtree: options.subtree, childList: options.childList, });
  75. this.#observerList.push(observer);
  76. window.x = observer;
  77. return observer;
  78. }
  79.  
  80. #injectStyle(styleString) {
  81. const style = document.createElement('style');
  82. style.textContent = styleString;
  83. return document.head.append(style);
  84. }
  85.  
  86. add(name, url, selector, callback, options) {
  87. if (url === '') url = ['.*'];
  88. const urls = Array.isArray(url) ? url : [url];
  89. if (!urls.some(this.#checkIfUrlMatch, this)) return;
  90. const opts = this.#mergeOptions(options);
  91. const observer = this.#on(selector, callback, opts);
  92. this.#waitList.push({ 'name': name, 'url': url, 'selector': selector, 'callback': callback, 'options': opts, 'observer': observer });
  93. }
  94.  
  95. batchAdd(name, url, lists, para4, para5) {
  96. const callback = typeof para4 === 'function' ? para4 : (typeof para5 === 'function' ? para5 : undefined);
  97. const options = typeof para4 === 'object' ? para4 : (typeof para5 === 'object' ? para5 : undefined)
  98. lists.forEach((p) => {
  99. if (!p.find(pp => typeof pp === 'function')) {
  100. if (p.length === 1) this.add(name, url, p[0], callback, options);
  101. else if (p.length === 2) this.add(`${name}-${p[0]}`, url, p[1], callback, options);
  102. }
  103. else if (typeof p[1] === 'function') this.add(name, url, p[0], p[1], p[2] || options);
  104. else if (typeof p[2] === 'function') this.add(`${name}-${p[0]}`, url, p[1], p[2], p[3] || options);
  105. else if (typeof p[3] === 'function') this.add(`${name}-${p[0]}`, p[1], p[2], p[3], p[4] || options);
  106. else return;
  107. })
  108. }
  109.  
  110. addCss(name, url, cssString) {
  111. if (url === '') url = ['.*'];
  112. const urls = Array.isArray(url) ? url : [url];
  113. if (!urls.some(this.#checkIfUrlMatch, this)) return;
  114. this.#injectStyle(cssString);
  115. }
  116.  
  117. stopAll() {
  118. while (this.#observerList.length) this.#observerList.pop().disconnect();
  119. }
  120. }
  121.  
  122. const WFN = new WaitForNode();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址