您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
chatgpt渲染html代码块,像Claude一样实时预览html ( chatgpt renders HTML code blocks, previewing HTML in real-time like Claude )
当前为
// ==UserScript== // @name ChatGPT 渲染HTML代码 // @namespace https://github.com/21888/chatgpt-render-html // @version 2024-10-07 // @description chatgpt渲染html代码块,像Claude一样实时预览html ( chatgpt renders HTML code blocks, previewing HTML in real-time like Claude ) // @author chabai // @match https://chatgpt.com/c/* // @icon https://www.google.com/s2/favicons?sz=64&domain=chatgpt.com // @grant none // @license GPL-2.0-only // ==/UserScript== (function () { "use strict"; // 使用 MutationObserver 监听 DOM 变化 const observer = new MutationObserver(debounce(xuanranHTML, 500)); const createIframeObserver = new MutationObserver(debounce(createIframe, 500)); // 观察目标节点的变化 observer.observe(document.body, { childList: true, subtree: true }); createIframeObserver.observe(document.body, { childList: true, subtree: true }); // 首次调用渲染 window.addEventListener("load", () => { setTimeout(xuanranHTML, 1000); // 创建一个iframe setTimeout(createIframe, 1000); }); })(); function createIframe() { // 判断是否已经创建 dynamicContentIframe if (document.getElementById("dynamicContentIframe")) { console.log("已经创建 dynamicContentIframe"); return; } // 创建一个基于main标签的兄弟iframe元素 const mainElement = document.querySelector("main"); // mainElement.style.display = "flex"; mainElement.style.overflow = "hidden"; if (mainElement) { const iframe = document.createElement("iframe"); iframe.id = "dynamicContentIframe"; // 添加id以便动态修改内容 iframe.style.display = "relative"; iframe.style.width = "100%"; iframe.style.height = "100%"; iframe.style.backgroundColor = "#FFFDF6"; // 添加奶白色背景 // 创建切换显示代码块的div const toggleCodeButton = document.createElement("div"); toggleCodeButton.id = "toggleCodeButton"; toggleCodeButton.style.position = "absolute"; toggleCodeButton.style.top = "10px"; toggleCodeButton.style.right = "40px"; toggleCodeButton.style.cursor = "pointer"; toggleCodeButton.innerHTML = ` <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M4 6H16M4 10H16M4 14H16" stroke="black" stroke-width="2" stroke-linecap="round"/> </svg> `; toggleCodeButton.onclick = () => { // document.getElementById("dynamicContentIframe").contentWindow.document.body.innerHTML = "123"; document.getElementById("codeContainer").style.display = document.getElementById("codeContainer").style.display === "none" ? "block" : "none"; }; // 创建缩小按钮 const minimizeButton = document.createElement("div"); minimizeButton.id = "minimizeButton"; minimizeButton.style.position = "absolute"; minimizeButton.style.top = "10px"; minimizeButton.style.right = "10px"; minimizeButton.style.cursor = "pointer"; minimizeButton.innerHTML = ` <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M4 10H16" stroke="black" stroke-width="2" stroke-linecap="round"/> </svg> `; minimizeButton.onclick = () => { iframe.style.display = iframe.style.display === "none" ? "block" : "none"; document.querySelector("main").style.display = document.querySelector("main").style.display === "block" ? "flex" : "block"; document .querySelector( "body > div.relative.flex.h-full.w-full.overflow-hidden.transition-colors.z-0 > div.flex-shrink-0.overflow-x-hidden.bg-token-sidebar-surface-primary.max-md\\:\\!w-0 > div > div > div > nav > div.flex.justify-between.flex.h-\\[60px\\].items-center.md\\:h-header-height > span > button" ) .click(); }; // toggleCodeButton 和 minimizeButton 添加到一个div下 const buttonContainer = document.createElement("div"); buttonContainer.id = "buttonContainer"; buttonContainer.style.position = "relative"; buttonContainer.style.top = "10px"; buttonContainer.style.right = "10px"; buttonContainer.appendChild(minimizeButton); buttonContainer.appendChild(toggleCodeButton); // 直接将 iframe 和按钮添加到 main 元素下 mainElement.appendChild(iframe); mainElement.appendChild(buttonContainer); // 设置 main 元素为相对定位,以便正确定位最小化按钮 mainElement.style.position = "relative"; // mainElement.insertBefore(container, mainElement.nextSibling); // 创建一个用户存放显示代码的div const codeContainer = document.createElement("div"); codeContainer.id = "codeContainer"; codeContainer.style.width = "100%"; codeContainer.style.height = "100%"; codeContainer.style.zIndex = "1000"; // codeContainer.style.backgroundColor = "#FFFDF6"; // 添加奶白色背景 codeContainer.style.display = "block"; codeContainer.style.overflow = "hidden"; codeContainer.style.overflowY = "scroll"; codeContainer.style.display = "none"; mainElement.appendChild(codeContainer); } else { console.error("Main element not found"); } // 显示 document.getElementById("dynamicContentIframe").style.display = "block"; } function xuanranHTML() { // 获取所有的 code 元素 const codes = document.querySelectorAll(".overflow-y-auto.p-4 code"); // 遍历所有的 code 元素 codes.forEach((codeElement) => { // 检查是否已经处理过,避免重复插入 if (codeElement.classList.contains("processed")) { return; } // 标记该元素已经处理过 codeElement.classList.add("processed"); // 判断 codeElement.textContent 是否是 HTML 内容 if (codeElement.parentNode.parentNode.children[0].innerText != "html") { console.log( "不渲染: " + codeElement.parentNode.parentNode.children[0].innerText ); return; } // 隐藏codeElement codeElement.parentNode.parentNode.style.display = "none"; let componentContainer = renderSmallWindow(codeElement); }); } function renderSmallWindow(codeElement) { // 创建组件容器 const componentContainer = document.createElement("div"); componentContainer.style.display = "flex"; componentContainer.style.alignItems = "center"; componentContainer.style.border = "1px solid #e5e7eb"; componentContainer.style.borderRadius = "8px"; componentContainer.style.padding = "10px"; componentContainer.style.backgroundColor = "#f9fafb"; componentContainer.style.marginBottom = "20px"; componentContainer.style.cursor = "pointer"; // 创建图标容器 const iconContainer = document.createElement("div"); iconContainer.style.borderRight = "1px solid #e5e7eb"; iconContainer.style.paddingRight = "10px"; // 创建 SVG 图标 const svgIcon = document.createElementNS( "http://www.w3.org/2000/svg", "svg" ); svgIcon.setAttribute("xmlns", "http://www.w3.org/2000/svg"); svgIcon.setAttribute("style", "height: 24px; width: 24px; color: #6b7280;"); svgIcon.setAttribute("fill", "none"); svgIcon.setAttribute("viewBox", "0 0 24 24"); svgIcon.setAttribute("stroke", "currentColor"); svgIcon.setAttribute("stroke-width", "2"); const pathElement = document.createElementNS( "http://www.w3.org/2000/svg", "path" ); pathElement.setAttribute("stroke-linecap", "round"); pathElement.setAttribute("stroke-linejoin", "round"); pathElement.setAttribute( "d", "M16 8c0-1.104-.9-2-2-2H6c-1.1 0-2 .896-2 2v8c0 1.104.9 2 2 2h8c1.1 0 2-.896 2-2V8zm-4 4h.01m-3 0h.01M7 12h.01m0 0h.01M12 7v.01M8 7v.01M7 7v.01M12 8v.01m-5 0v.01m-1 0v.01" ); svgIcon.appendChild(pathElement); iconContainer.appendChild(svgIcon); // 创建文本容器 const textContainer = document.createElement("div"); textContainer.style.marginLeft = "10px"; // 创建标题 const title = document.createElement("h3"); title.textContent = codeElement.parentNode.parentNode.children[0].innerText; title.style.margin = "0"; title.style.fontSize = "16px"; title.style.fontWeight = "600"; title.style.color = "#374151"; // 创建描述 const description = document.createElement("p"); description.textContent = "预览页面 / 刷新渲染"; description.style.margin = "0"; description.style.fontSize = "14px"; description.style.color = "#6b7280"; textContainer.appendChild(title); textContainer.appendChild(description); // 组装组件 componentContainer.appendChild(iconContainer); componentContainer.appendChild(textContainer); // 添加点击事件,切换代码显示状态 componentContainer.addEventListener("click", function () { const codeParent = codeElement.parentNode.parentNode; const mainElement = document.querySelector("main"); // codeParent.style.display = codeParent.style.display === 'none' ? 'block' : 'none'; // 隐藏展开左侧历史记录 if (mainElement.style.display != "flex") { mainElement.style.display = "flex"; } if ( document.querySelector( "body > div.relative.flex.h-full.w-full.overflow-hidden.transition-colors.z-0 > div.flex-shrink-0.overflow-x-hidden.bg-token-sidebar-surface-primary.max-md\\:\\!w-0" ).style.width != "0px" ) { document .querySelector( "body > div.relative.flex.h-full.w-full.overflow-hidden.transition-colors.z-0 > div.flex-shrink-0.overflow-x-hidden.bg-token-sidebar-surface-primary.max-md\\:\\!w-0 > div > div > div > nav > div.flex.justify-between.flex.h-\\[60px\\].items-center.md\\:h-header-height > span > button" ) .click(); // dynamicContentIframe document.getElementById("dynamicContentIframe").style.display = "block"; } // iframe 赋值 renderIframeContent( document.getElementById("dynamicContentIframe"), codeElement.textContent ); // 设置代码容器代码 // document.getElementById("codeContainer").innerHTML = codeElement.parentNode.parentNode.innerHTML; const codeContainer = document.getElementById("codeContainer"); codeContainer.innerHTML = ""; const clonedContent = codeElement.parentNode.parentNode.cloneNode(true); codeContainer.appendChild(clonedContent); codeContainer.childNodes[0].style.display = "contents"; // 查找并处理按钮 const buttons = clonedContent.querySelectorAll("button"); buttons.forEach((button, index) => { console.log(button); if (button.className == "flex gap-1 items-center py-1") { button.addEventListener("click", function (event) { button.innerText = " success √ "; setTimeout(() => { button.innerText = "Copy code"; }, 1000); }); } button.addEventListener("click", function (event) { event.stopPropagation(); // 阻止事件冒泡到父元素 // 找到原始按钮并模拟点击 const originalButtons = codeElement.parentNode.parentNode.querySelectorAll( "button" ); if (originalButtons[index]) { originalButtons[index].click(); } }); }); // 添加事件委托到 codeContainer(用于处理代码元素的点击) codeContainer.addEventListener("click", function (event) { const clickedElement = event.target.closest("code"); if (clickedElement) { // 模拟原始代码元素的点击行为 const originalCodeElement = codeElement.closest("code"); if (originalCodeElement) { originalCodeElement.click(); } } }); }); // 将组件插入到代码元素之前 codeElement.parentNode.parentNode.insertAdjacentElement( "beforebegin", componentContainer ); return componentContainer; } function renderIframeContent(iframe, content) { // 获取 iframe 内部的 document 对象 const iframeDoc = iframe.contentDocument || iframe.contentWindow.document; // 将 code 元素的内容设置为 iframe 的内容 iframeDoc.open(); if (true) { // 刷新特效,true为有感刷新,!true为无痕刷新 iframeDoc.write(`loading`); setTimeout(() => iframeDoc.write(content), 100); } else { iframeDoc.write(content); } iframeDoc.close(); } function debounce(func, wait) { let timeout; return function () { const context = this, args = arguments; clearTimeout(timeout); timeout = setTimeout(() => func.apply(context, args), wait); }; }
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址