|
|
动机
有一个官方的勋章交易帖,就在勋章公会板块下的“【勛章信息 - 即時動態】”这里。哪怕是对勋章已经有了一定的了解,也可能不常看,甚至根本不知道有这个帖子。
由于论坛是基于Discuz!架构,没法达到即时通讯软件那样的时效性,所以在这里回复内容已经算是最高效的方法了。
功能
这个脚本在“勋章商城”主页面增加了一个小窗口,会直接出现在 https://www.gamemale.com/wodexunzhang-showxunzhang.html 页面的 #div.myfenleilist.clearfix.myfenleilist_1 元素前。这张图片会展示地更加一目了然:
代码
@Name @Match @Icon
- // ==UserScript==
- // @name 勋章:把[勛章信息 - 即時動態]插入勋章商城页
- // @namespace https://www.gamemale.com/
- // @version 1.0.0
- // @description 在访问“我的勋章”页面时,将论坛页的 #livethread(即时动态)插入到 #div.myfenleilist.clearfix.myfenleilist_1 前,并尽量保留全部功能(刷新、回复等)。
- // @match https://www.gamemale.com/wodexunzhang-showxunzhang.html
- // @run-at document-end
- // @grant none
- // ==/UserScript==
- (function () {
- 'use strict';
- const SOURCE_URL = 'https://www.gamemale.com/forum-128-1.html';
- const TARGET_SELECTOR ='div.myfenleilist.clearfix.myfenleilist_1';
- const INSERT_BEFORE = true;
- function log(...args) {
- console.log('[GM-livethread]', ...args);
- }
- function waitForElement(selector, timeoutMs = 15000) {
- return new Promise((resolve, reject) => {
- const el = document.querySelector(selector);
- if (el) return resolve(el);
- const obs = new MutationObserver(() => {
- const el2 = document.querySelector(selector);
- if (el2) {
- obs.disconnect();
- resolve(el2);
- }
- });
- obs.observe(document.documentElement, { childList: true, subtree: true });
- setTimeout(() => {
- obs.disconnect();
- reject(new Error('Timeout waiting for ' + selector));
- }, timeoutMs);
- });
- }
- function createHostBox() {
- const host = document.createElement('div');
- host.id = 'gm_livethread_host';
- host.style.margin = '12px 0';
- host.style.border = '1px solid #e5e5e5';
- host.style.borderRadius = '8px';
- host.style.overflow = 'hidden';
- host.style.background = '#fff';
- const iframe = document.createElement('iframe');
- iframe.id = 'gm_livethread_iframe';
- iframe.src = SOURCE_URL;
- iframe.style.width = '100%';
- iframe.style.border = '0';
- iframe.style.display = 'block';
- iframe.style.height = '0px'; // 初始高度,加载后会自动调
- iframe.referrerPolicy = 'no-referrer-when-downgrade';
- host.appendChild(iframe);
- return { host, iframe };
- }
- function cropIframeToLiveThread(iframe) {
- iframe.addEventListener('load', () => {
- try {
- const doc = iframe.contentDocument;
- const win = iframe.contentWindow;
- if (!doc) return;
- const live = doc.querySelector('#livethread');
- if (!live) {
- log('iframe内未找到 #livethread,可能页面结构变了。');
- return;
- }
- // 注入样式:隐藏其他所有内容,只展示 #livethread
- const style = doc.createElement('style');
- style.textContent = `
- html, body { margin: 0 !important; padding: 0 !important; background: transparent !important; }
- body > * { display: none !important; }
- #livethread { display: block !important; margin: 0 !important; }
- /* 让它在“我的勋章”页更贴合 */
- #livethread { padding: 10px 12px !important; }
- #livethread .livethreadtitle img { vertical-align: middle; }
- `;
- doc.head.appendChild(style);
- // 把 #livethread 挪到 body 直接子级(避免它原本嵌套导致 body>* 隐藏规则误伤)
- // 注意:这样仍然在同一个页面环境内,功能不会丢。
- if (live.parentElement !== doc.body) {
- doc.body.appendChild(live);
- }
- // 自动高度:随内容变化而变
- const resize = () => {
- // 给一点余量,避免滚动条闪烁
- const h = Math.max(200, live.scrollHeight + 24);
- iframe.style.height = h + 'px';
- };
- resize();
- // 监听内容变化:新回复、展开等
- const mo = new MutationObserver(() => resize());
- mo.observe(live, { childList: true, subtree: true, characterData: true });
- // 更稳妥:ResizeObserver(如果浏览器支持)
- if ('ResizeObserver' in win) {
- const ro = new win.ResizeObserver(() => resize());
- ro.observe(live);
- }
- // 兜底:定时修正(避免某些异步资源加载导致高度不准)
- let ticks = 0;
- const timer = win.setInterval(() => {
- resize();
- ticks += 1;
- if (ticks >= 20) win.clearInterval(timer);
- }, 500);
- log('已裁剪并嵌入 #livethread');
- } catch (e) {
- log('裁剪iframe失败:', e);
- // 常见原因:X-Frame-Options / CSP 阻止、或跨域(一般同域不会)
- }
- });
- }
- (async function main() {
- // 避免重复插入
- if (document.querySelector('#gm_livethread_host')) return;
- let target;
- try {
- target = await waitForElement(TARGET_SELECTOR);
- } catch (e) {
- console.warn('[GM-livethread] 未找到网页②插入点元素:', TARGET_SELECTOR, e);
- return;
- }
- const { host, iframe } = createHostBox();
- // 插入到目标前
- if (INSERT_BEFORE && target.parentNode) {
- target.parentNode.insertBefore(host, target);
- } else {
- target.prepend(host);
- }
- cropIframeToLiveThread(iframe);
- })();
- })();
复制代码
来自群组: 星象占卜 |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
评分
-
查看全部评分
|