一、 源代码
浏览器安全策略原因,只能使用插件或扩展破解,这里推荐油猴脚本,具体使用不过多赘述。
脚本1:
// ==UserScript==
// @name shadow-root
// @namespace http://tampermonkey.net/
// @version 2024-07-10
// @description try to take over the world!
// @author Vdoi
// @match *://*/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=gdzwfw.gov.cn
// @grant none
// ==/UserScript==
(function() {
'use strict';
// Your code here...
Element.prototype._attachShadow = Element.prototype.attachShadow;
Element.prototype.attachShadow = function () {
//console.log('attachShadow');
return this._attachShadow( { mode: "open" } );
};
})();
脚本2:
// ==UserScript==
// @name shadow-root(closed)2
// @namespace http://tampermonkey.net/
// @version 2025-02-21
// @description try to take over the world!
// @author Vdoi
// @match *://*/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=gdzwfw.gov.cn
// @grant none
// ==/UserScript==
(function() {
'use strict';
// Your code here...
// 保存原始 attachShadow 方法
const originalAttachShadow = Element.prototype.attachShadow;
// 覆盖 attachShadow
Element.prototype.attachShadow = function(options) {
// 强制设置为 open 模式
options.mode = 'open';
// 调用原始方法并保存 shadowRoot
const shadowRoot = originalAttachShadow.call(this, options);
// 将 shadowRoot 绑定到元素上
this._shadowRoot = shadowRoot;
return shadowRoot;
};
})();
脚本3:
// ==UserScript==
// @name shadow-root(closed)3
// @namespace http://tampermonkey.net/
// @version 2025-02-26
// @description try to take over the world!
// @author Vdoi
// @match *://*/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=gdzwfw.gov.cn
// @grant none
// ==/UserScript==
(function() {
'use strict';
// Your code here...
// 劫持元素原型链方法
let oldAttach = Element.prototype.attachShadow;
Element.prototype.attachShadow = function(...args) {
// 强制修改闭包模式为open
if (args[0]?.mode === 'closed') {
args[0].mode = 'open';
console.log('[Hook] ShadowRoot模式已强制开放');
}
return oldAttach.apply(this, args);
};
})();
脚本4:
// ==UserScript==
// @name Shadow-root(closed)4
// @namespace http://your-domain.com
// @version 1.2
// @description 强制解除shadow-root(closed)限制
// @author Vdoi
// @match *://*/*
// @run-at document-start
// @grant unsafeWindow
// @grant GM_addStyle
// ==/UserScript==
(function() {
'use strict';
// ================== 核心破解逻辑 ==================
const hijackShadowDOM = () => {
// 劫持原生API
const nativeAttachShadow = Element.prototype.attachShadow;
Element.prototype.attachShadow = function(config) {
// 强制修改closed模式为open
if (config?.mode === 'closed') {
console.debug('[破解] 检测到closed模式,已强制开启');
config.mode = 'open';
}
return nativeAttachShadow.call(this, config);
};
// 框架级破解(Vue/React)
if (unsafeWindow.Vue) {
const originalVueMount = unsafeWindow.Vue.prototype.$mount;
unsafeWindow.Vue.prototype.$mount = function(el) {
this.$el = el;
return originalVueMount.call(this, el);
};
console.debug('[破解] Vue组件Shadow DOM限制已解除');
}
};
// ================== 反检测机制 ==================
const antiDetection = () => {
// 屏蔽控制台特征
const originalConsoleLog = console.log;
console.log = function(...args) {
if (!args.some(str => str.includes('shadow'))) {
originalConsoleLog.apply(console, args);
}
};
// 阻断异常检测
const originalAddEventListener = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function(type, listener, options) {
if (type === 'securitypolicyviolation') return;
originalAddEventListener.call(this, type, listener, options);
};
};
// ================== DOM监控模块 ==================
const startDOMObserver = () => {
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
mutation.addedNodes.forEach(node => {
if (node.nodeType === 1 && node.shadowRoot) {
node.shadowRoot.innerHTML +=
'<style>:host { display: block !important; }</style>';
}
});
});
});
observer.observe(document.documentElement, {
childList: true,
subtree: true,
attributes: false,
characterData: false
});
};
// ================== 执行入口 ==================
hijackShadowDOM();
antiDetection();
startDOMObserver();
// 注入辅助样式
GM_addStyle(`
#shadow-root (closed) {
display: block !important;
border: 1px dashed red !important;
}
`);
// 调试模式开关(生产环境注释掉)
// unsafeWindow.__DEBUG_SHADOW__ = true;
})();