您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
一个好用的 Cloudflare 缓存清理工具,支持清除当前页面链接缓存、图片/CSS/JS 资源缓存,以及自定义多个 URL 的缓存清除。
// ==UserScript== // @name Cloudflare 缓存清除工具 // @namespace https://github.com/JsBeta/cloudflare-cache-purge/ // @version 1.8.4 // @author xuwei // @description 一个好用的 Cloudflare 缓存清理工具,支持清除当前页面链接缓存、图片/CSS/JS 资源缓存,以及自定义多个 URL 的缓存清除。 // @icon data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iaWNvbiIgIHZpZXdCb3g9IjAgMCAxMDI0IDEwMjQiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBmaWxsPSIjZTc4OTMwIiBkPSJNODAwLjIxMzMzMyA0MzQuMzQ2NjY3YTI5OC42NjY2NjcgMjk4LjY2NjY2NyAwIDAgMC01NjEuOTItNDEuNkEyMTMuMzMzMzMzIDIxMy4zMzMzMzMgMCAwIDAgMjk4LjY2NjY2NyA4MTAuNjY2NjY3aDQ0OGExOTIgMTkyIDAgMCAwIDUzLjU0NjY2Ni0zNzYuMzJ6TTc0Ni42NjY2NjcgNzI1LjMzMzMzM0gyOTguNjY2NjY3YTEyOCAxMjggMCAwIDEgMC0yNTZoNC4yNjY2NjZBMjEzLjMzMzMzMyAyMTMuMzMzMzMzIDAgMCAxIDcyNS4zMzMzMzMgNTEyYTcuMjUzMzMzIDcuMjUzMzMzIDAgMCAxIDAgMi4xMzMzMzMgMTIwLjk2IDEyMC45NiAwIDAgMSAyMS4zMzMzMzQtMi4xMzMzMzMgMTA2LjY2NjY2NyAxMDYuNjY2NjY3IDAgMCAxIDAgMjEzLjMzMzMzM3ogbS0yMzQuNjY2NjY3LTQyLjY2NjY2NmExNDkuMzMzMzMzIDE0OS4zMzMzMzMgMCAxIDEgMTQ5LjMzMzMzMy0xNDkuMzMzMzM0aC04NS4zMzMzMzNhNjQgNjQgMCAxIDAtNjQgNjR6IiAvPjwvc3ZnPg== // @include * // @license MIT // @connect api.cloudflare.com // @run-at document-end // @grant GM_getValue // @grant GM_registerMenuCommand // @grant GM_setValue // @grant GM_xmlhttpRequest // ==/UserScript== (function () { 'use strict'; function styleInject(css, ref) { if ( ref === void 0 ) ref = {}; var insertAt = ref.insertAt; if (!css || typeof document === 'undefined') { return; } var head = document.head || document.getElementsByTagName('head')[0]; var style = document.createElement('style'); style.type = 'text/css'; if (insertAt === 'top') { if (head.firstChild) { head.insertBefore(style, head.firstChild); } else { head.appendChild(style); } } else { head.appendChild(style); } if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } } var css_248z = ".main_icon__RYCes {\n display: inline-block;\n vertical-align: middle;\n}\n.main_icon__RYCes path {\n fill: #e78930;\n}\n.main_menu__MLtUQ {\n position: fixed;\n width: 40px;\n right: 0;\n top: 300px;\n z-index: 100;\n box-sizing: content-box;\n font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;\n}\n.main_menu__MLtUQ:hover ul {\n right: 0px;\n}\n.main_menu__MLtUQ:hover .main_entry__oOnCr {\n background: #0a4b85;\n opacity: 1;\n}\n.main_menu__MLtUQ .main_entry__oOnCr {\n padding: 3px;\n cursor: pointer;\n background: #fff;\n border-radius: 25% 0 0 25%;\n margin-bottom: 5px;\n box-shadow: 2px 6px 10px 0px #0e121629;\n opacity: 0.5;\n transition: all 0.3s ease-in-out;\n}\n.main_menu__MLtUQ .main_entry__oOnCr .main_icon__RYCes path {\n fill: #e78930;\n}\n.main_menu__MLtUQ .main_entry__oOnCr .main_icon__RYCes:hover {\n rotate: 180deg;\n transition: all 0.5s ease-in-out;\n}\n.main_menu__MLtUQ ul {\n position: absolute;\n transition: all 0.3s ease-in-out;\n right: -40px;\n margin: 0;\n padding: 0;\n}\n.main_menu__MLtUQ li {\n height: 34px;\n margin-bottom: 2px;\n list-style: none;\n cursor: pointer;\n position: relative;\n}\n.main_menu__MLtUQ li:hover .main_item__njE-F {\n width: 85px;\n}\n.main_menu__MLtUQ li:hover .main_icon__RYCes path {\n fill: #fff;\n}\n.main_menu__MLtUQ .main_item__njE-F {\n box-sizing: content-box;\n overflow: hidden;\n white-space: nowrap;\n width: 24px;\n height: 24px;\n line-height: 24px;\n padding: 5px 5px 6px 5px;\n position: absolute;\n top: 0;\n right: 0;\n font-size: 12px;\n color: #fff;\n background: #0a4b85;\n border-radius: 2px 0px 0px 2px;\n transition: width 0.3s ease-in;\n}\n.main_menu__MLtUQ .main_item__njE-F:hover {\n background: #e78930;\n}\n.main_menu__MLtUQ .main_item__njE-F .main_icon__RYCes {\n margin-right: 5px;\n transform: translateY(-1px);\n}\n.main_panel__t3SIt {\n display: none;\n border: 1px solid #ccc;\n border-radius: 8px;\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);\n background: #fff;\n z-index: 9999;\n}\n.main_panel__t3SIt.main_show__HRMDu {\n display: block;\n}\n.main_panel__t3SIt .main_close__2MGVA {\n position: absolute;\n top: 10px;\n right: 10px;\n cursor: pointer;\n width: 20px;\n height: 20px;\n}\n.main_panel__t3SIt .main_head__AwcOE {\n height: 40px;\n line-height: 40px;\n padding: 0 20px;\n border-bottom: 1px solid #ccc;\n color: #000;\n font-size: 16px;\n font-weight: 600;\n}\n.main_panel__t3SIt .main_foot__-LFyQ {\n height: 55px;\n line-height: 40px;\n padding: 5px 20px;\n display: flex;\n justify-content: flex-end;\n gap: 20px;\n align-items: center;\n border-top: 1px solid #ccc;\n}\n.main_panel__t3SIt .main_foot__-LFyQ button {\n cursor: pointer;\n height: 35px;\n line-height: 35px;\n padding: 0px 30px;\n background: #e78930;\n color: #fff;\n font-size: 14px;\n border: none;\n border-radius: 8px;\n}\n.main_panel__t3SIt .main_foot__-LFyQ button[data-id=\"panel-close\"] {\n background: #ccc;\n color: #333;\n}\n.main_panel__t3SIt .main_foot__-LFyQ button[data-id=\"panel-close\"]:hover {\n color: #fff;\n}\n.main_panel__t3SIt .main_foot__-LFyQ button:hover {\n background: #c46d1c;\n}\n.main_panel__t3SIt .main_wall__0tq2S {\n position: relative;\n width: 900px;\n /* 4列 × (200px + gap) */\n height: 700px;\n overflow-y: auto;\n z-index: 99;\n}\n.main_panel__t3SIt .main_wall__0tq2S .main_item__njE-F {\n box-sizing: content-box;\n position: relative;\n display: inline-block;\n padding: 10px;\n vertical-align: top;\n position: absolute;\n transition: opacity 0.3s;\n}\n.main_panel__t3SIt .main_wall__0tq2S img {\n cursor: pointer;\n box-sizing: content-box;\n width: 200px;\n height: auto;\n display: block;\n background: #f1f1f1;\n object-fit: scale-down;\n}\n.main_panel__t3SIt .main_wall__0tq2S input[type=\"checkbox\"] {\n position: absolute;\n top: 5px;\n left: 5px;\n z-index: 1;\n}\n.main_panel__t3SIt .main_wall__0tq2S input[type=\"checkbox\"] {\n display: none;\n}\n.main_panel__t3SIt .main_wall__0tq2S input[type=\"checkbox\"]:checked + img {\n box-shadow: 0 0 0 2px rgba(245, 148, 3, 0.76);\n}\n.main_panel__t3SIt .main_list__f6SQm {\n padding: 20px;\n position: relative;\n width: 900px;\n max-height: 600px;\n overflow-y: auto;\n z-index: 99;\n}\n.main_panel__t3SIt .main_list__f6SQm .main_item__njE-F {\n cursor: pointer;\n display: block;\n padding: 0 5px;\n margin-bottom: 8px;\n}\n.main_panel__t3SIt .main_list__f6SQm .main_item__njE-F span {\n display: inline-block;\n padding: 5px;\n margin-left: 5px;\n border-radius: 5px;\n}\n.main_panel__t3SIt .main_list__f6SQm input[type=\"checkbox\"]:checked + span {\n box-shadow: 0 0 0 2px rgba(245, 148, 3, 0.76);\n}\n.main_panel__t3SIt .main_inputarea__mzOdr {\n box-sizing: content-box;\n padding: 20px;\n position: relative;\n width: 600px;\n max-height: 600px;\n overflow-y: auto;\n z-index: 99;\n}\n.main_panel__t3SIt .main_inputarea__mzOdr textarea {\n padding: 10px;\n margin-top: 10px;\n border: 1px solid #e78930;\n line-height: 2;\n border-radius: 5px;\n max-width: 575px;\n min-width: 575px;\n}\n.main_panel__t3SIt .main_inputarea__mzOdr textarea:focus {\n outline: none;\n border: 1px solid #fff;\n box-shadow: 0 0 0 2px rgba(245, 148, 3, 0.76);\n}\n"; var style = {"icon":"main_icon__RYCes","menu":"main_menu__MLtUQ","entry":"main_entry__oOnCr","item":"main_item__njE-F","panel":"main_panel__t3SIt","show":"main_show__HRMDu","close":"main_close__2MGVA","head":"main_head__AwcOE","foot":"main_foot__-LFyQ","wall":"main_wall__0tq2S","list":"main_list__f6SQm","inputarea":"main_inputarea__mzOdr"}; styleInject(css_248z); // 配置信息 let config = { apiToken: GM_getValue("cfApiToken", ""), }; // 添加配置菜单 GM_registerMenuCommand("配置 API Token", function() { const apiToken = prompt( "请输入您的 Cloudflare API Token:", config.apiToken ); if (apiToken !== null) { GM_setValue("cfApiToken", apiToken); config.apiToken = apiToken; } }); // 添加清除缓存菜单和页面按钮 GM_registerMenuCommand("清除当前地址缓存", function() { clearCache([window.location.href]); }); // 修改验证配置 function validateConfig() { if (!config.apiToken) { alert("请先配置Cloudflare API Token."); return false; } return true; } // 查找zoneid async function getZoneId(domain) { return new Promise((resolve) => { console.debug("正在获取域名:", domain); GM_xmlhttpRequest({ method: "GET", url: `https://api.cloudflare.com/client/v4/zones?name=${domain}`, headers: { Authorization: `Bearer ${config.apiToken}`, "Content-Type": "application/json", }, onload: function(response) { console.debug("API响应状态:", response.status); const data = JSON.parse(response.responseText); console.debug("完整API响应:", data); if (data.result) { resolve(data.result[0]?.id); } else { resolve(null); } }, onerror: function(error) { console.error("获取Zone ID失败:", error); resolve(null); }, }); }); } // 清除缓存函数 async function clearCache(urls) { console.debug("开始清除缓存流程"); if (!urls.length) { alert("请选择或者输入需要清除的缓存项!"); return; } if (!validateConfig()) return; let domain = new URL(window.location.href).hostname; // 去除domain的www前缀 domain = domain.replace(/^www\./, ""); console.debug("解析出的域名:", domain); const zoneId = await getZoneId(domain); if (!zoneId) { alert("未找到该域名对应的Cloudflare zone,请检查域名是否正确!"); return; } // 使用动态zoneId发送请求... await purgeCache(zoneId, urls); } // 清除缓存封装 function purgeCache(zongeId, urls) { const apiUrl = `https://api.cloudflare.com/client/v4/zones/${zongeId}/purge_cache`; console.debug( "%c [ 需要清除的urls ]: ", "color: #bf2c9f; background: pink; font-size: 13px;", urls ); GM_xmlhttpRequest({ method: "POST", url: apiUrl, headers: { Authorization: `Bearer ${config.apiToken}`, "Content-Type": "application/json", }, data: JSON.stringify({ files: [...urls], }), onload: function(response) { const result = JSON.parse(response.responseText); if (result.success) { alert("缓存清理成功!"); // 刷新当前页面 window.location.reload(); } else { alert( "API请求清理缓存失败(onload):" + (result.errors ?.[0]?.message || "Unknown error") ); } }, onerror: function(error) { alert("API请求清理缓存失败(onerror): " + error.responseText); }, }); } // 获取当前链接请求响应头 const getCfResponseHeaders = async (url) => { return new Promise((resolve) => { GM_xmlhttpRequest({ method: "HEAD", url, onload: function(response) { // 返回响应头中的cf-cache-status字段 const cfCacheStatusMatch = response.responseHeaders.match(/cf-cache-status:\s*(.+)/i); const cfCacheStatusValue = cfCacheStatusMatch ? cfCacheStatusMatch[1] : null; resolve(cfCacheStatusValue); }, onerror: function(error) { console.error("获取响应头失败:", error); resolve(null); }, }); }); }; // 获取资源链接 const getResources = () => { const blacklistedPatterns = [ /analytics\.example\.com/, /www\.clarity/, /www\.google/, /app\.termly/, ]; const jsLinks = Array.from(document.scripts) .map((s) => s.src) .filter(Boolean) .filter( (url) => !blacklistedPatterns.some((pattern) => pattern.test(url)) ); const cssLinks = Array.from( document.querySelectorAll('link[rel="stylesheet"]') ).map((link) => link.href); const imgLinks = Array.from(document.images) .map((img) => img.src) .filter(Boolean); const cssBgImages = new Set(); Array.from(document.querySelectorAll("*")).forEach((el) => { const bg = getComputedStyle(el).backgroundImage; const m = bg.match(/url\(["']?(.*?)["']?\)/); if (m && m[1]) cssBgImages.add(m[1]); }); const allImages = Array.from(new Set([...imgLinks, ...cssBgImages])); return { js: jsLinks, css: cssLinks, img: allImages, }; }; // 图片瀑布流布局 const layoutMasonry = (containerSelector, columnCount = 4, spacing = 10) => { const container = document.querySelector(containerSelector); if (!container) return; const items = Array.from(container.querySelectorAll("label")); if (items.length === 0) return; const itemWidth = 200 + spacing * 2; // 每个图片项的宽度(含左右 margin) let columnHeights = Array(columnCount).fill(0); // 存储每一列的高度 items.forEach((item) => { // 找到当前最短的一列 const minHeight = Math.min(...columnHeights); const colIndex = columnHeights.indexOf(minHeight); // 设置绝对定位位置 item.style.left = `${colIndex * itemWidth}px`; item.style.top = `${minHeight}px`; // 更新该列的高度 const itemHeight = item.offsetHeight; columnHeights[colIndex] += itemHeight; }); }; // 创建资源列表面板; const createResourcePanel = (picArray, type) => { const container = document.createElement("div"); container.classList.add(style.panel); container.innerHTML = ` <div class="${style.head}"> <span class="title">资源列表</span> <svg data-id="panel-close" class="${ style.close }" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"> <polygon data-id="panel-close" points="35.31 9.86 24 21.17 12.69 9.86 9.86 12.69 21.17 24 9.86 35.31 12.69 38.14 24 26.83 35.31 38.14 38.14 35.31 26.83 24 38.14 12.69 35.31 9.86" /> </svg> </div> <div id="${type === "img" ? "x-panel-wall" : ""}" class="${type === "img" ? style.wall : style.list}"> ${picArray .map( (url) => ` <label class="${style.item}"> <input type="checkbox" value="${url}"/> ${ type === "img" ? `<img src="${url}" />` : `<span>${url}</span>` } </label> ` ) .join("\n")} </div> <div class="${style.foot}"> <button data-id="panel-close">取消</button> <button data-id="panel-submit" data-type="${type}">清除</button> </div> `; return container; }; // 创建输入框面板; const createInputPanel = (type) => { const container = document.createElement("div"); container.classList.add(style.panel); container.innerHTML = ` <div class="${style.head}"> <span class="title">清除多个url链接</span> <svg data-id="panel-close" class="${style.close}" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"> <polygon data-id="panel-close" points="35.31 9.86 24 21.17 12.69 9.86 9.86 12.69 21.17 24 9.86 35.31 12.69 38.14 24 26.83 35.31 38.14 38.14 35.31 26.83 24 38.14 12.69 35.31 9.86" /> </svg> </div> <div class="${style.inputarea}"> <textarea cols="80" rows="6" name="inputarea" placeholder="输入url链接,多个链接需要另取一行"></textarea> </div> <div class="${style.foot}"> <button data-id="panel-close">取消</button> <button data-id="panel-submit" data-type="${type}">清除</button> </div> `; return container; }; // 创建侧边菜单 const createMenu = () => { const menuEle = document.createElement("div"); menuEle.classList.add(style.menu); const entryEle = document.createElement("div"); // 入口按钮 entryEle.classList.add(style.entry); entryEle.innerHTML = ` <svg class="${style.icon}" width="36" height="36" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"> <path fill="#8D929C" d="M896 512A384 384 0 0 0 533.333333 129.066667h-21.333333A384 384 0 0 0 129.066667 490.666667v21.333333A384 384 0 0 0 490.666667 896h21.333333a384 384 0 0 0 384-362.666667v-21.333333z m-85.333333 0v13.013333a128 128 0 0 1-249.813334 23.893334A213.333333 213.333333 0 0 0 721.066667 298.666667 298.666667 298.666667 0 0 1 810.666667 512zM512 213.333333h13.013333a128 128 0 0 1 23.893334 249.813334A213.333333 213.333333 0 0 0 298.666667 302.933333 298.666667 298.666667 0 0 1 512 213.333333zM213.333333 512v-13.013333a128 128 0 0 1 249.813334-23.893334A213.333333 213.333333 0 0 0 302.933333 725.333333 298.666667 298.666667 0 0 1 213.333333 512z m298.666667 298.666667h-13.013333a128 128 0 0 1-23.893334-249.813334A213.333333 213.333333 0 0 0 725.333333 721.066667 298.666667 298.666667 0 0 1 512 810.666667z" /> </svg>`; const menuUlEle = document.createElement("ul"); // 入口菜单列表 menuUlEle.innerHTML = ` <li> <div class="${style.item}" data-id="imgs"> <svg class="${style.icon}" width="24" height="24" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"> <path fill="#8D929C" d="M853.333333 682.666667v-42.666667a42.666667 42.666667 0 0 0-85.333333 0v170.666667a42.666667 42.666667 0 0 0 85.333333 0h-42.666666v-85.333334h128v85.333334a128 128 0 0 1-256 0v-170.666667a128 128 0 0 1 256 0v42.666667z m-512-85.333334v-85.333333H85.333333v85.333333h85.333334v256H85.333333v85.333334h256v-85.333334h-85.333333V597.333333z m298.666667-85.333333v426.666667h-85.333333V654.293333l-42.666667 56.746667-42.666667-56.746667V938.666667h-85.333333V512h85.333333l42.666667 56.96L554.666667 512z m85.333333-426.666667l213.333334 213.333334v170.666666h-85.333334v-135.253333L689.92 170.666667H170.666667v298.666666H85.333333V85.333333z" /> </svg> 图片文件 </div> </li> <li> <div class="${style.item}" data-id="css"> <svg class="${style.icon}" width="24" height="24" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"> <path fill="#8D929C" d="M725.333333 85.333333l213.333334 213.333334v170.666666h-85.333334v-135.253333L689.92 170.666667H170.666667v298.666666H85.333333V85.333333zM256 768v42.666667a42.666667 42.666667 0 0 1-85.333333 0v-170.666667a42.666667 42.666667 0 0 1 85.333333 0v42.666667h85.333333v-42.666667a128 128 0 0 0-256 0v170.666667a128 128 0 0 0 256 0v-42.666667z m256-85.333333a42.666667 42.666667 0 1 1 42.666667-42.666667h85.333333a128 128 0 1 0-128 128 42.666667 42.666667 0 1 1-42.666667 42.666667h-85.333333a128 128 0 1 0 128-128z m298.666667 0a42.666667 42.666667 0 1 1 42.666666-42.666667h85.333334a128 128 0 1 0-128 128 42.666667 42.666667 0 1 1-42.666667 42.666667h-85.333333a128 128 0 1 0 128-128z" /> </svg> CSS文件 </div> </li> <li> <div class="${style.item}" data-id="js"> <svg class="${style.icon}" width="24" height="24" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"> <path fill="#8D929C" d="M938.666667 298.666667v640H682.666667v-85.333334h170.666666V334.08L689.92 170.666667H170.666667v298.666666H85.333333V85.333333h640zM512 682.666667a42.666667 42.666667 0 1 1 42.666667-42.666667h85.333333a128 128 0 1 0-128 128 42.666667 42.666667 0 1 1-42.666667 42.666667h-85.333333a128 128 0 1 0 128-128z m-256-170.666667v298.666667a42.666667 42.666667 0 0 1-85.333333 0v-42.666667H85.333333v42.666667a128 128 0 0 0 256 0V512z" /> </svg> JS文件 </div> </li> <li> <div class="${style.item}" data-id="link"> <svg class="${style.icon}" width="24" height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"> <path fill="#8D929C" d="M18,44V30a6,6,0,0,1,12,0V44H26V30a2,2,0,0,0-4,0V44ZM16,28V24H4v4H8V40H4v4H16V40H12V28ZM34,4H4V22H8V8H32.34L40,15.66V22h4V14ZM32,24V44h4V24Zm12,0H40L36,34l4,10h4L40,34Z" /> </svg> 当前链接 </div> </li> <li> <div class="${style.item}" data-id="urls"> <svg class="${style.icon}" width="24" height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"> <path fill="#8D929C" d="M44,40v4H32V24h4V40ZM40,15.66V22h4V14L34,4H4V22H8V8H32.34ZM28.08,34.39,30,44H26l-1.6-8L24,36H22v8H18V24h6a6,6,0,0,1,4.08,10.39ZM24,32a2,2,0,0,0,0-4H22v4ZM12,24V38a2,2,0,0,1-4,0V24H4V38a6,6,0,0,0,12,0V24Z" /> </svg> 多个链接 </div> </li> `; menuEle.appendChild(entryEle); menuEle.appendChild(menuUlEle); return menuEle; }; if (window.self === window.top) { window.addEventListener("load", function() { let xtoolsEle = null; getCfResponseHeaders(window.location.href).then((res) => { if (res) { console.info( `%c INFO %c 检测到当前网站经过 CloudFlare CDN 加速, 缓存清理小工具已经正常加载! %c`, `background:#909399;border:1px solid #909399; padding: 1px; border-radius: 2px 0 0 2px; color: #fff;`, `border:1px solid #909399; padding: 1px; border-radius: 0 2px 2px 0; color: #909399;`, 'background:transparent' ); xtoolsEle = document.createElement("div"); const menuEle = createMenu(); const resources = getResources(); const picPanelEle = createResourcePanel(resources.img, "img"); const cssPanelEle = createResourcePanel(resources.css, "css"); const jsPanelEle = createResourcePanel(resources.js, "js"); const inputPanelEle = createInputPanel("urls"); // 遍历childNodes,移除show样式 const closePanel = (nodes) => { nodes.forEach((node) => { node.classList.remove(style.show); }); }; // 对菜单项的点击事件进行监听 xtoolsEle.addEventListener("click", function(e) { e.stopPropagation(); switch (e.target.dataset.id) { case "imgs": // 选择图片 closePanel(this.childNodes); picPanelEle.classList.add(style.show); layoutMasonry("#x-panel-wall", 4); break; case "css": // 选择css closePanel(this.childNodes); cssPanelEle.classList.add(style.show); break; case "js": // 选择js closePanel(this.childNodes); jsPanelEle.classList.add(style.show); break; case "link": // 清除当前link clearCache([window.location.href]); break; case "urls": closePanel(this.childNodes); // 输入urls inputPanelEle.classList.add(style.show); break; case "panel-submit": { // 获取inputPanelEle中textarea的value 以回车分割成数组 // 如果textarea 为空 则返回空数组 const inputUrls = inputPanelEle .querySelector("textarea") .value.split("\n") .filter(Boolean); const selected = [ ...xtoolsEle.querySelectorAll( "input[type='checkbox']:checked" ), ].map((c) => c.value); clearCache([...inputUrls, ...selected]); } break; case "panel-close": // 遍历childNodes,移除show样式 closePanel(this.childNodes); // 遍历所有的checkbox,取消选中 this.querySelectorAll("input[type=checkbox]").forEach( (checkbox) => { checkbox.checked = false; } ); // 清空textarea的值 this.querySelector("textarea").value = ""; break; } }); xtoolsEle.appendChild(menuEle); xtoolsEle.appendChild(picPanelEle); xtoolsEle.appendChild(cssPanelEle); xtoolsEle.appendChild(jsPanelEle); xtoolsEle.appendChild(inputPanelEle); document.body.appendChild(xtoolsEle); } }); }); } })();