您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
使用 Vue 3 Composition API,合併啟動選項,移除 IIFE,狀態同步
// ==UserScript== // @name 批量打開 reddit 的 r/udemyfreeebies 連結(Vue Composition 簡化) // @namespace http://tampermonkey.net/ // @version 0.13 // @description 使用 Vue 3 Composition API,合併啟動選項,移除 IIFE,狀態同步 // @license GPL-3.0 // @match https://www.reddit.com/r/udemyfreeebies/* // @grant GM_registerMenuCommand // @author twozwu // ==/UserScript== let links = []; let currentIndex = 0; function loadVue() { const vueScript = document.createElement('script'); vueScript.src = 'https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js'; vueScript.onload = initApp; document.head.appendChild(vueScript); } function initApp() { const appContainer = document.createElement('div'); appContainer.id = 'vue-bulk-opener'; document.body.appendChild(appContainer); document.getElementById('vue-bulk-opener').innerHTML = ` <div id="app" style=" position: fixed; top: 80px; right: 20px; background: #fff; border: 2px solid #ccc; border-radius: 12px; padding: 15px; z-index: 9999; font-family: sans-serif; width: 260px; box-shadow: 0 0 10px rgba(0,0,0,0.2); "> <h3 style="margin-top: 0;">🔗 批量開啟設定</h3> <div> <label>每批數量: <input type="number" v-model.number="perClick" min="1" style="width: 4rem;"> </label> </div> <div style="margin-top: 6px;"> <label>從第 <input type="number" v-model.number="indexKey" style="width: auto;"> 個開始 </label> <small style="display:block;color:#666;">(預設為上次進度)</small> </div> <div style="margin-top:10px;"> <button @click="runOpener">🚀 開始</button> <button @click="closePanel" style="float: right;">❌</button> </div> <div v-if="controlVisible" style="margin-top:15px;"> <p>{{ statusText }}</p> <button @click="continueBatch">▶️ 繼續</button> <button @click="stopBatch">🛑 停止</button> </div> </div> `; const { createApp, ref, watch } = Vue; createApp({ setup() { const perClick = ref(parseInt(localStorage.getItem('defaultPerClick')) || 15); const indexKey = ref(parseInt(localStorage.getItem('indexKey')) || 0); const controlVisible = ref(false); const statusText = ref(''); // 同步 currentIndex <-> indexKey 雙向同步 watch(indexKey, val => { currentIndex = val; }); const closePanel = () => { document.getElementById('vue-bulk-opener')?.remove(); }; const updateStatus = () => { if (currentIndex >= links.length) { alert("✅ 所有連結已打開完畢!"); controlVisible.value = false; indexKey.value = 0; localStorage.removeItem('indexKey'); } else { statusText.value = `已打開 ${currentIndex} / ${links.length},繼續下一批?`; } }; const gatherLinks = () => { links = []; document.querySelectorAll('.text-neutral-content ul li a').forEach(anchor => { if (anchor.href) links.push(anchor.href); }); if (links.length === 0) { alert("⚠️ 找不到連結!"); } }; const openBatch = () => { const end = Math.min(currentIndex + perClick.value, links.length); for (let i = currentIndex; i < end; i++) { const win = window.open(links[i], "_blank", "noopener,noreferrer"); if (win) { win.blur(); window.focus(); } } currentIndex = end; indexKey.value = end; // 雙向更新 localStorage.setItem('indexKey', end.toString()); updateStatus(); }; const runOpener = () => { localStorage.setItem('defaultPerClick', perClick.value.toString()); currentIndex = indexKey.value || 0; gatherLinks(); controlVisible.value = true; openBatch(); }; const continueBatch = () => openBatch(); const stopBatch = () => { alert("⏹️ 已停止,進度已保存"); }; return { perClick, indexKey, controlVisible, statusText, runOpener, continueBatch, stopBatch, closePanel, }; } }).mount('#app'); } GM_registerMenuCommand("📂 開啟連結設定面板", loadVue);
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址