您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
库
当前为
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.greasyfork.icu/scripts/448895/1077673/ElementGetter%E5%BA%93.js
// ==UserScript== // @name ElementGetter库 // @author cxxjackie // @version 1.1.1 // @namespace http://tampermonkey.net/ // @description 库 // @icon // @grant none // ==/UserScript== (function() { 'use strict'; // Your code here... })(); class ElementGetter { #jQuery; #window; #matchesSelector; #mutationObserver; #addListener; #listeners; #addObserver(target, callback) { const observer = new this.#mutationObserver(mutations => { for (const mutation of mutations) { for (const addedNode of mutation.addedNodes) { if (observer.canceled) return; callback(addedNode); } } }); observer.canceled = false; observer.observe(target, { childList: true, subtree: true }); return function() { observer.canceled = true; observer.disconnect(); }; } #addEvent(target, callback) { const listener = e => callback(e.target); target.addEventListener('DOMNodeInserted', listener); return function() { target.removeEventListener('DOMNodeInserted', listener); }; } #addFilter(target, filter) { if (this.#listeners.has(target)) { const listener = this.#listeners.get(target); listener.filters.push(filter); } else { const removeFunc = this.#addListener(target, node => { if (node instanceof Element) { listener.filters.forEach(f => f(node)); } }); const listener = { filters: [filter], remove: removeFunc }; this.#listeners.set(target, listener); } } #removeFilter(target, filter) { if (!this.#listeners.has(target)) return; const listener = this.#listeners.get(target); const index = listener.filters.indexOf(filter); listener.filters.splice(index, 1); if (listener.filters.length === 0) { listener.remove(); this.#listeners.delete(target); } } #query(selector, parent, includeParent) { const $ = this.#jQuery; if ($) { let jNodes = $(parent.querySelectorAll('*')); if (includeParent) jNodes = jNodes.add(parent); jNodes = jNodes.filter(selector); return jNodes.length > 0 ? $(jNodes.get(0)) : null; } else { if (includeParent && this.#matchesSelector.call(parent, selector)) { return parent; } return parent.querySelector(selector); } } #queryAll(selector, parent, includeParent) { const $ = this.#jQuery; let result = []; if ($) { let jNodes = $(parent.querySelectorAll('*')); if (includeParent) jNodes = jNodes.add(parent); jNodes = jNodes.filter(selector); jNodes.each((i, elm) => result.push($(elm))); } else { if (includeParent && this.#matchesSelector.call(parent, selector)) { result.push(parent); } result.push(...parent.querySelectorAll(selector)); } return result; } #getOne(selector, parent, timeout) { return new Promise(resolve => { const result = this.#query(selector, parent, false); if (result) return resolve(result); let timer; const filter = node => { const result = this.#query(selector, node, true); if (result) { this.#removeFilter(parent, filter); timer && clearTimeout(timer); resolve(result); } }; this.#addFilter(parent, filter); if (timeout > 0) { timer = setTimeout(() => { this.#removeFilter(parent, filter); resolve(null); }, timeout); } }); } #getList(selectorList, parent, timeout) { const promiseList = []; for (const selector of selectorList) { promiseList.push(this.#getOne(selector, parent, timeout)); } return Promise.all(promiseList); } constructor(jQuery) { this.#jQuery = jQuery && jQuery.fn && jQuery.fn.jquery ? jQuery : null; this.#window = window.unsafeWindow || document.defaultView || window; const elmProto = this.#window.Element.prototype; this.#matchesSelector = elmProto.matches || elmProto.matchesSelector || elmProto.webkitMatchesSelector || elmProto.msMatchesSelector || elmProto.mozMatchesSelector; this.#mutationObserver = this.#window.MutationObserver || this.#window.WebkitMutationObserver || this.#window.MozMutationObserver; this.#addListener = this.#mutationObserver ? this.#addObserver : this.#addEvent; this.#listeners = new WeakMap(); } get(selector, ...args) { const parent = typeof args[0] !== 'number' && args.shift() || this.#window.document; const timeout = args[0] || 0; if (typeof selector === 'string' || selector instanceof String) { return this.#getOne(selector, parent, timeout); } else if (selector instanceof Array) { return this.#getList(selector, parent, timeout); } else { return Promise.resolve(null); } } each(selector, ...args) { const parent = typeof args[0] !== 'function' && args.shift() || this.#window.document; const callback = args[0]; let removed = false; const handle = { remove: () => { removed = true; } }; setTimeout(() => { const elms = this.#queryAll(selector, parent, false); for (const elm of elms) { if (callback(elm, false) === false || removed) return; } const refs = new WeakSet(); const removeFunc = this.#addListener(parent, node => { if (node instanceof Element) { const elms = this.#queryAll(selector, node, true); for (const elm of elms) { const _node = this.#jQuery ? elm.get(0) : elm; if (!refs.has(_node)) { refs.add(_node); if (callback(elm, false) === false) handle.remove(); if (removed) return; } } } }); handle.remove = () => { removed = true; removeFunc(); }; }, 0); return handle; } remove(handle) { handle && handle.remove(); } create(domString) { const template = this.#window.document.createElement('template'); template.innerHTML = domString; const node = template.content.firstElementChild || template.content.firstChild; node.remove(); return node; } }