// ==UserScript==
// @name CSS Extractor for Lanhu
// @namespace http://tampermonkey.net/
// @version 1.0.0
// @description 从蓝湖网站上提取CSS代码并打印到控制台
// @author TikeAI
// @match https://lanhuapp.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=lanhuapp.com
// @license MIT
// @grant none
// ==/UserScript==
(function () {
"use strict";
// 定义抽屉元素类型
/**
* @typedef {HTMLDivElement & { disconnect: VoidFunction }} DrawerElement
*/
// 全局引用对象,用于存储当前抽屉元素和CSS内容
let ref = {
current: null,
css: "",
};
/**
* 观察抽屉元素变化的函数
* @param {DrawerElement} el - 抽屉元素
*/
function observeDrawer(el) {
// 如果存在之前的抽屉元素,断开其观察器连接并清空CSS
if (ref.current) {
ref.current.disconnect && ref.current.disconnect();
ref.css = "";
}
ref.current = el;
// 使用防抖处理观察到的变化
let obsFn = debounce(
async () => {
// 查找代码详情元素
let detailbox = el.querySelector(".annotation_item.code_detail");
let codebox = detailbox?.querySelector(".code_box");
let anchor = null;
let css = "";
// 获取原本的css样式
{
if (codebox) {
// 如果存在代码框,直接获取其中的CSS内容
anchor = detailbox;
css = codebox.textContent;
} else {
// 否则从标注项中获取尺寸信息
let itembox = last(
Array.from(
el.querySelectorAll(".annotation_container > .annotation_item")
)
);
anchor = itembox;
// 查找包含"大小"的列表项
let list = el.querySelectorAll(
".annotation_container > .annotation_item li"
);
let sizebox = Array.from(list).find((li) => {
return trim(li.textContent).startsWith("大小");
});
if (sizebox) {
// 提取宽度和高度信息
let sizeElements = Array.from(
sizebox.querySelectorAll(".item_two")
);
if (sizeElements.length >= 2) {
let width = trim(sizeElements[0].textContent);
let height = trim(sizeElements[1].textContent);
css = `width: ${width}; height: ${height};`;
}
}
}
// 将CSS包装在.app选择器中
css = `.app { ${css} }`;
}
// 如果CSS内容发生变化
if (ref.css !== css) {
ref.css = css;
try {
// 直接打印CSS到控制台
console.log("%c[CSS提取]", "color:#3799a8;", css);
// 在页面上显示提取的CSS
showCssPopup(css);
} catch (e) {
console.warn("%c[error]", "color:red;", e);
}
}
},
100,
{ leading: false, trailing: true }
);
// 创建并配置MutationObserver来观察元素变化
let obs = new MutationObserver(obsFn);
obs.observe(el, {
characterData: true,
subtree: true,
childList: true,
});
// 添加断开观察器的方法
el.disconnect = () => {
obs.disconnect();
};
}
/**
* 格式化CSS代码使其更易读
* @param {string} css - 原始CSS代码
* @returns {string} - 格式化后的CSS代码
*/
function formatCss(css) {
// 移除多余空格和换行
let formatted = css.replace(/\s+/g, " ");
// 替换分号后添加换行
formatted = formatted.replace(/;\s*/g, ";\n ");
// 替换左大括号后添加换行
formatted = formatted.replace(/{\s*/g, "{\n ");
// 替换右大括号前添加换行
formatted = formatted.replace(/\s*}/g, "\n}");
// 处理嵌套选择器
formatted = formatted.replace(/}\s*\./g, "}\n\n.");
return formatted;
}
/**
* 将CSS属性转换为Tailwind CSS格式
* @param {string} css - 原始CSS代码
* @returns {string} - 转换后的Tailwind CSS代码
*/
function convertToTailwind(css) {
// 提取CSS属性
const properties = {};
const regex = /(\w+-?\w*?):\s*([^;]+);/g;
let match;
while ((match = regex.exec(css)) !== null) {
const property = match[1].trim();
const value = match[2].trim();
properties[property] = value;
}
// 转换为Tailwind类
const tailwindClasses = [];
// 处理背景色
if (properties.background) {
tailwindClasses.push(`bg-[${properties.background}]`);
}
// 处理圆角
if (properties["border-radius"]) {
tailwindClasses.push(`rounded-[${properties["border-radius"]}]`);
}
// 只有在没有字体大小时才处理宽高
if (!properties["font-size"]) {
// 处理宽度
if (properties.width) {
tailwindClasses.push(`w-[${properties.width}]`);
}
// 处理高度
if (properties.height) {
tailwindClasses.push(`h-[${properties.height}]`);
}
}
// 处理字体系列
// if (properties["font-family"]) {
// tailwindClasses.push(`font-[${properties["font-family"]}]`);
// }
// 处理字体粗细
if (properties["font-weight"]) {
const weightMap = {
100: "thin",
200: "extralight",
300: "light",
400: "normal",
500: "medium",
600: "semibold",
700: "bold",
800: "extrabold",
900: "black",
};
const weight = weightMap[properties["font-weight"]];
tailwindClasses.push(`font-${weight}`);
}
// 处理字体大小
if (properties["font-size"]) {
tailwindClasses.push(`text-[${properties["font-size"]}]`);
}
// 处理颜色
if (properties.color) {
tailwindClasses.push(`text-[${properties.color}]`);
}
// 处理行高
// if (properties["line-height"]) {
// tailwindClasses.push(`leading-[${properties["line-height"]}]`);
// }
// 处理字间距
// if (properties["letter-spacing"]) {
// tailwindClasses.push(`tracking-[${properties["letter-spacing"]}]`);
// }
// 处理文本对齐
// if (properties["text-align"]) {
// tailwindClasses.push(`text-${properties["text-align"]}`);
// }
// 处理字体样式
// if (properties["font-style"]) {
// if (properties["font-style"] === "italic") {
// tailwindClasses.push("italic");
// } else if (properties["font-style"] === "normal") {
// tailwindClasses.push("not-italic");
// }
// }
// 过滤掉空字符串并以换行方式返回
return tailwindClasses.filter((c) => c).join("\n");
}
/**
* 在页面上显示CSS弹窗
* @param {string} css - 提取的CSS代码
*/
function showCssPopup(css) {
// 格式化CSS代码
const formattedCss = formatCss(css);
// 转换为Tailwind CSS
const tailwindCss = convertToTailwind(css);
// 检查是否已存在弹窗
let existingPopup = document.getElementById("css-extractor-popup");
if (existingPopup) {
existingPopup.querySelector(".css-content").textContent = formattedCss;
existingPopup.querySelector(".tailwind-content").textContent =
tailwindCss;
return;
}
// 添加动画和全局样式
const styleElement = document.createElement("style");
styleElement.textContent = `
@keyframes fadeIn {
from { opacity: 0; transform: translateY(-10px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes slideIn {
from { transform: translateX(10px); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
.tab-hover {
transition: all 0.2s ease;
}
.tab-hover:hover {
background-color: rgba(74, 144, 226, 0.1);
}
`;
document.head.appendChild(styleElement);
// 创建弹窗容器
const popup = document.createElement("div");
popup.id = "css-extractor-popup";
popup.style.cssText = `
position: fixed;
top: 49px;
right: 302px;
background: white;
border: none;
border-radius: 12px;
padding: 0;
width: 380px;
overflow: hidden;
z-index: 9999;
box-shadow: 0 8px 24px rgba(0,0,0,0.12), 0 2px 8px rgba(0,0,0,0.08);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
animation: fadeIn 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
`;
// 创建标题栏
const titleBar = document.createElement("div");
titleBar.style.cssText = `
background: linear-gradient(135deg, #4a90e2, #5a6acf);
color: white;
padding: 12px 18px;
font-weight: 600;
font-size: 15px;
display: flex;
justify-content: space-between;
align-items: center;
cursor: move;
user-select: none;
border-top-left-radius: 12px;
border-top-right-radius: 12px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
`;
titleBar.innerHTML =
'<span style="display: flex; align-items: center;"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 8px;"><path d="M20.24 12.24a6 6 0 0 0-8.49-8.49L5 10.5V19h8.5z"></path><line x1="16" y1="8" x2="2" y2="22"></line><line x1="17.5" y1="15" x2="9" y2="15"></line></svg>CSS提取器</span>';
titleBar.className = "css-extractor-titlebar";
// 创建按钮容器
const buttonContainer = document.createElement("div");
buttonContainer.style.cssText = `
display: flex;
gap: 8px;
`;
// 创建回到原位按钮
const resetPositionBtn = document.createElement("button");
resetPositionBtn.innerHTML =
'<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"></path><path d="M3 3v5h5"></path></svg>';
resetPositionBtn.style.cssText = `
border: none;
background: rgba(255,255,255,0.25);
color: white;
border-radius: 6px;
padding: 5px;
cursor: pointer;
font-size: 13px;
transition: all 0.2s;
display: flex;
align-items: center;
justify-content: center;
`;
resetPositionBtn.title = "回到原位置";
resetPositionBtn.onmouseover = () => {
resetPositionBtn.style.backgroundColor = "rgba(255,255,255,0.4)";
resetPositionBtn.style.transform = "scale(1.05)";
};
resetPositionBtn.onmouseout = () => {
resetPositionBtn.style.backgroundColor = "rgba(255,255,255,0.25)";
resetPositionBtn.style.transform = "scale(1)";
};
resetPositionBtn.onclick = (e) => {
e.stopPropagation();
popup.style.transition = "all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1)";
popup.style.top = "49px";
popup.style.right = "302px";
popup.style.left = "auto";
popup.style.bottom = "auto";
// 添加一个轻微的动画效果
popup.style.transform = "scale(1.03)";
setTimeout(() => {
popup.style.transform = "scale(1)";
}, 300);
};
// 创建关闭按钮
const closeBtn = document.createElement("button");
closeBtn.innerHTML =
'<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>';
closeBtn.style.cssText = `
border: none;
background: rgba(255,255,255,0.25);
color: white;
border-radius: 6px;
padding: 5px;
cursor: pointer;
font-size: 13px;
transition: all 0.2s;
display: flex;
align-items: center;
justify-content: center;
width: 26px;
height: 26px;
`;
closeBtn.onmouseover = () => {
closeBtn.style.background = "rgba(255,255,255,0.4)";
closeBtn.style.transform = "translateY(-1px)";
};
closeBtn.onmouseout = () => {
closeBtn.style.background = "rgba(255,255,255,0.25)";
closeBtn.style.transform = "translateY(0)";
};
closeBtn.onclick = () => {
document.body.removeChild(popup);
};
// 将按钮添加到按钮容器
buttonContainer.appendChild(resetPositionBtn);
buttonContainer.appendChild(closeBtn);
// 将按钮容器添加到标题栏
titleBar.appendChild(buttonContainer);
// 创建内容容器
const tabContainer = document.createElement("div");
tabContainer.style.cssText = `
display: flex;
border-bottom: 1px solid rgba(0,0,0,0.08);
background: #f8f9fa;
padding: 0 10px;
`;
// 创建CSS标签
const cssTab = document.createElement("div");
cssTab.textContent = "CSS";
cssTab.className = "css-tab tab-hover";
cssTab.style.cssText = `
padding: 12px 18px;
cursor: pointer;
border-bottom: 2px solid transparent;
font-weight: 500;
color: #666;
font-size: 14px;
transition: all 0.2s ease;
border-radius: 6px 6px 0 0;
margin: 6px 4px 0 4px;
`;
// 创建Tailwind标签
const tailwindTab = document.createElement("div");
tailwindTab.textContent = "Tailwind";
tailwindTab.className = "tailwind-tab active-tab tab-hover";
tailwindTab.style.cssText = `
padding: 12px 18px;
cursor: pointer;
border-bottom: 2px solid #4a90e2;
font-weight: 600;
color: #4a90e2;
font-size: 14px;
transition: all 0.2s ease;
background-color: rgba(74, 144, 226, 0.08);
border-radius: 6px 6px 0 0;
margin: 6px 4px 0 4px;
`;
// 添加标签到标签容器
tabContainer.appendChild(cssTab);
tabContainer.appendChild(tailwindTab);
// 创建内容容器
const contentContainer = document.createElement("div");
contentContainer.style.cssText = `
padding: 20px;
max-height: none;
overflow: auto;
background: #f8f9fa;
border-radius: 0 0 12px 12px;
`;
// 创建CSS内容区域
const cssContent = document.createElement("pre");
cssContent.className = "css-content";
cssContent.style.cssText = `
margin: 0;
margin-bottom: 10px;
white-space: pre-wrap;
word-break: break-all;
font-family: 'SF Mono', Consolas, Monaco, 'Andale Mono', monospace;
font-size: 14px;
color: #333;
line-height: 1.6;
display: none;
padding: 16px;
background-color: #ffffff;
border-radius: 8px;
animation: fadeIn 0.3s ease-in-out;
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
border: 1px solid rgba(0,0,0,0.05);
cursor: pointer;
`;
cssContent.textContent = formattedCss;
// 添加双击复制功能
cssContent.ondblclick = (event) => {
// 阻止默认行为,防止页面滚动
event.preventDefault();
// 获取内容并替换换行符为空格
let contentToCopy = cssContent.textContent;
contentToCopy = contentToCopy.replace(/\n/g, " ");
// 复制到剪贴板
navigator.clipboard.writeText(contentToCopy).then(
() => {
// 复制成功提示 - 添加临时样式变化
const originalBackground = cssContent.style.backgroundColor;
const originalColor = cssContent.style.color;
cssContent.style.backgroundColor = "rgba(16, 185, 129, 0.1)";
cssContent.style.color = "rgba(16, 185, 129, 1)";
setTimeout(() => {
cssContent.style.backgroundColor = originalBackground;
cssContent.style.color = originalColor;
}, 1000);
},
(err) => {
console.error("复制失败:", err);
// 复制失败提示
const originalBackground = cssContent.style.backgroundColor;
cssContent.style.backgroundColor = "rgba(239, 68, 68, 0.1)";
setTimeout(() => {
cssContent.style.backgroundColor = originalBackground;
}, 1000);
}
);
};
// 创建Tailwind内容区域
const tailwindContent = document.createElement("pre");
tailwindContent.className = "tailwind-content";
tailwindContent.style.cssText = `
margin: 0;
margin-bottom: 10px;
white-space: pre-wrap;
word-break: break-all;
font-family: 'SF Mono', Consolas, Monaco, 'Andale Mono', monospace;
font-size: 14px;
color: #2563eb;
line-height: 1.8;
display: block;
padding: 16px;
background-color: #f1f5f9;
border-radius: 8px;
animation: fadeIn 0.3s ease-in-out;
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
border: 1px solid rgba(0,0,0,0.05);
cursor: pointer;
`;
tailwindContent.textContent = tailwindCss;
// 添加双击复制功能
tailwindContent.ondblclick = (event) => {
// 阻止默认行为,防止页面滚动
event.preventDefault();
// 获取内容并替换换行符为空格
let contentToCopy = tailwindContent.textContent;
contentToCopy = contentToCopy.replace(/\n/g, " ");
// 复制到剪贴板
navigator.clipboard.writeText(contentToCopy).then(
() => {
// 复制成功提示 - 添加临时样式变化
const originalBackground = tailwindContent.style.backgroundColor;
const originalColor = tailwindContent.style.color;
tailwindContent.style.backgroundColor = "rgba(16, 185, 129, 0.1)";
tailwindContent.style.color = "rgba(16, 185, 129, 1)";
setTimeout(() => {
tailwindContent.style.backgroundColor = originalBackground;
tailwindContent.style.color = originalColor;
}, 1000);
},
(err) => {
console.error("复制失败:", err);
// 复制失败提示
const originalBackground = tailwindContent.style.backgroundColor;
tailwindContent.style.backgroundColor = "rgba(239, 68, 68, 0.1)";
setTimeout(() => {
tailwindContent.style.backgroundColor = originalBackground;
}, 1000);
}
);
};
// 添加双击复制提示
const copyHintText = document.createElement("div");
copyHintText.style.cssText = `
font-size: 13px;
color: #4a90e2;
text-align: center;
margin-bottom: 10px;
font-style: italic;
padding: 5px;
border-radius: 4px;
background-color: rgba(74, 144, 226, 0.08);
transition: all 0.2s ease;
cursor: help;
`;
copyHintText.innerHTML = "✨ 双击可复制内容 ✨";
copyHintText.onmouseover = () => {
copyHintText.style.backgroundColor = "rgba(74, 144, 226, 0.15)";
};
copyHintText.onmouseout = () => {
copyHintText.style.backgroundColor = "rgba(74, 144, 226, 0.08)";
};
contentContainer.appendChild(copyHintText);
// 添加标签切换功能
cssTab.onclick = (event) => {
// 阻止默认行为,防止页面滚动
event.preventDefault();
cssTab.style.borderBottom = "2px solid #4a90e2";
cssTab.style.fontWeight = "600";
cssTab.style.color = "#4a90e2";
cssTab.style.backgroundColor = "rgba(74, 144, 226, 0.08)";
tailwindTab.style.borderBottom = "2px solid transparent";
tailwindTab.style.fontWeight = "500";
tailwindTab.style.color = "#666";
tailwindTab.style.backgroundColor = "transparent";
cssContent.style.display = "block";
tailwindContent.style.display = "none";
// 添加动画效果
cssContent.style.animation = "fadeIn 0.3s ease-in-out";
};
tailwindTab.onclick = (event) => {
// 阻止默认行为,防止页面滚动
event.preventDefault();
tailwindTab.style.borderBottom = "2px solid #4a90e2";
tailwindTab.style.fontWeight = "600";
tailwindTab.style.color = "#4a90e2";
tailwindTab.style.backgroundColor = "rgba(74, 144, 226, 0.08)";
cssTab.style.borderBottom = "2px solid transparent";
cssTab.style.fontWeight = "500";
cssTab.style.color = "#666";
cssTab.style.backgroundColor = "transparent";
cssContent.style.display = "none";
tailwindContent.style.display = "block";
// 添加动画效果
tailwindContent.style.animation = "fadeIn 0.3s ease-in-out";
};
// 组装弹窗
contentContainer.appendChild(cssContent);
contentContainer.appendChild(tailwindContent);
popup.appendChild(titleBar);
popup.appendChild(tabContainer);
popup.appendChild(contentContainer);
document.body.appendChild(popup);
// 添加拖动功能 - 改进版本
let isDragging = false;
let offsetX, offsetY;
titleBar.addEventListener("mousedown", (e) => {
// 阻止默认行为,防止页面滚动
e.preventDefault();
isDragging = true;
offsetX = e.clientX - popup.getBoundingClientRect().left;
offsetY = e.clientY - popup.getBoundingClientRect().top;
popup.style.transition = "none";
popup.style.opacity = "0.92";
popup.style.transform = "scale(1.01)";
document.body.style.cursor = "grabbing";
titleBar.style.cursor = "grabbing";
});
document.addEventListener(
"mousemove",
(e) => {
if (isDragging) {
// 阻止默认行为,防止页面滚动
e.preventDefault();
const x = e.clientX - offsetX;
const y = e.clientY - offsetY;
// 确保弹窗不会被拖出视口
const maxX = window.innerWidth - popup.offsetWidth;
const maxY = window.innerHeight - popup.offsetHeight;
popup.style.left = `${Math.max(0, Math.min(x, maxX))}px`;
popup.style.right = "auto";
popup.style.top = `${Math.max(0, Math.min(y, maxY))}px`;
popup.style.bottom = "auto";
}
},
{ passive: false }
); // 设置passive为false,允许阻止默认行为
document.addEventListener(
"mouseup",
(e) => {
if (isDragging) {
// 阻止默认行为,防止页面滚动
e.preventDefault();
isDragging = false;
popup.style.transition = "all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1)";
popup.style.opacity = "1";
popup.style.transform = "scale(1)";
document.body.style.cursor = "default";
titleBar.style.cursor = "move";
}
},
{ passive: false }
); // 设置passive为false,允许阻止默认行为
// 添加窗口大小调整时的位置修正
window.addEventListener("resize", () => {
const rect = popup.getBoundingClientRect();
const maxX = window.innerWidth - popup.offsetWidth;
const maxY = window.innerHeight - popup.offsetHeight;
if (rect.right > window.innerWidth) {
popup.style.left = `${Math.max(0, maxX)}px`;
}
if (rect.bottom > window.innerHeight) {
popup.style.top = `${Math.max(0, maxY)}px`;
}
});
}
/**
* 防抖函数
* @param {Function} func - 要执行的函数
* @param {number} wait - 等待时间
* @param {Object} options - 配置选项
* @returns {Function} - 防抖处理后的函数
*/
function debounce(func, wait, options) {
let lastArgs, lastThis, maxWait, result, timerId, lastCallTime;
let lastInvokeTime = 0;
let leading = false;
let maxing = false;
let trailing = true;
if (typeof options === "object") {
leading = !!options.leading;
maxing = "maxWait" in options;
maxWait = maxing ? Math.max(+options.maxWait || 0, wait) : maxWait;
trailing = "trailing" in options ? !!options.trailing : trailing;
}
function invokeFunc(time) {
const args = lastArgs;
const thisArg = lastThis;
lastArgs = lastThis = undefined;
lastInvokeTime = time;
result = func.apply(thisArg, args);
return result;
}
function leadingEdge(time) {
lastInvokeTime = time;
timerId = setTimeout(timerExpired, wait);
return leading ? invokeFunc(time) : result;
}
function remainingWait(time) {
const timeSinceLastCall = time - lastCallTime;
const timeSinceLastInvoke = time - lastInvokeTime;
const timeWaiting = wait - timeSinceLastCall;
return maxing
? Math.min(timeWaiting, maxWait - timeSinceLastInvoke)
: timeWaiting;
}
function shouldInvoke(time) {
const timeSinceLastCall = time - lastCallTime;
const timeSinceLastInvoke = time - lastInvokeTime;
return (
lastCallTime === undefined ||
timeSinceLastCall >= wait ||
timeSinceLastCall < 0 ||
(maxing && timeSinceLastInvoke >= maxWait)
);
}
function timerExpired() {
const time = Date.now();
if (shouldInvoke(time)) {
return trailingEdge(time);
}
timerId = setTimeout(timerExpired, remainingWait(time));
}
function trailingEdge(time) {
timerId = undefined;
if (trailing && lastArgs) {
return invokeFunc(time);
}
lastArgs = lastThis = undefined;
return result;
}
function cancel() {
if (timerId !== undefined) {
clearTimeout(timerId);
}
lastInvokeTime = 0;
lastArgs = lastCallTime = lastThis = timerId = undefined;
}
function flush() {
return timerId === undefined ? result : trailingEdge(Date.now());
}
function debounced() {
const time = Date.now();
const isInvoking = shouldInvoke(time);
lastArgs = arguments;
lastThis = this;
lastCallTime = time;
if (isInvoking) {
if (timerId === undefined) {
return leadingEdge(lastCallTime);
}
if (maxing) {
timerId = setTimeout(timerExpired, wait);
return invokeFunc(lastCallTime);
}
}
if (timerId === undefined) {
timerId = setTimeout(timerExpired, wait);
}
return result;
}
debounced.cancel = cancel;
debounced.flush = flush;
return debounced;
}
/**
* 获取数组的最后一个元素
* @param {Array} array - 输入数组
* @returns {*} - 最后一个元素
*/
function last(array) {
const length = array == null ? 0 : array.length;
return length ? array[length - 1] : undefined;
}
/**
* 去除字符串两端的空白
* @param {string} str - 输入字符串
* @returns {string} - 处理后的字符串
*/
function trim(str) {
return str ? str.trim() : "";
}
// 立即执行的函数,用于监视抽屉的打开状态
(async () => {
let obs = new MutationObserver(() => {
// 获取所有抽屉元素
const drawerList = document.querySelectorAll(
"#detail_container .mu-drawer"
);
// 查找打开的抽屉
let openDrawer = Array.from(drawerList).find((d) =>
d.classList.contains("open")
);
// 如果找到新打开的抽屉,开始观察它
if (openDrawer && ref.current !== openDrawer) {
observeDrawer(openDrawer);
}
});
// 观察整个文档body的变化
obs.observe(document.body, {
subtree: true,
attributes: true,
childList: true,
});
// 添加初始化提示
console.log(
"%c[CSS提取器]",
"color:#3799a8; font-weight:bold;",
"已初始化,等待蓝湖设计稿打开..."
);
})();
})();