From 1b5cf793003cd488d709e29dd43834d137109dfd Mon Sep 17 00:00:00 2001 From: "DESKTOP-RQ919RC\\Pc" <1300399510@qq.com> Date: Fri, 28 Nov 2025 19:23:01 +0800 Subject: [PATCH] =?UTF-8?q?refactor(editor):=20=E4=BC=98=E5=8C=96=E5=AF=8C?= =?UTF-8?q?=E6=96=87=E6=9C=AC=E5=86=85=E5=AE=B9=E8=BD=AC=E6=8D=A2=E9=80=BB?= =?UTF-8?q?=E8=BE=91=E5=B9=B6=E4=BF=AE=E5=A4=8D=E5=9B=BE=E7=89=87=E5=A4=84?= =?UTF-8?q?=E7=90=86=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 重构 restoreHtml 和 formatContent 函数,改进 BBCode 标记与 HTML 的相互转换 - 修复 parseImageSrc 函数在失败时未返回空字符串的问题 - 改进图片宽高处理,支持百分比单位和更精确的尺寸控制 - 增强视频和附件处理逻辑,完善资源匹配机制 - 优化 HTML 结构处理,确保符合编辑器的块级元素要求 --- js/edit.js | 354 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 213 insertions(+), 141 deletions(-) diff --git a/js/edit.js b/js/edit.js index 7b035d4..922a87f 100644 --- a/js/edit.js +++ b/js/edit.js @@ -227,6 +227,7 @@ const editApp = createApp({ console.log("href", href); }, async parseImageSrc(src) { + console.log("parseImageSrc", src); // 如果图片链接中已经包含了 ?aid= ,则说明是本站图片,直接返回,无需处理 if (src.includes("?aid=")) return src; @@ -242,11 +243,13 @@ const editApp = createApp({ const res = await ajax(uConfigData.url, formData); if (res.code == 200 && res.data) return `${res.data.url}?aid=${res.data.aid}`; - else creationAlertBox("error", res.message || "操作失败"); + else { + creationAlertBox("error", res.message || "操作失败"); + return ""; + } } catch (e) { console.error("Transform network image failed", e); } - return src; }, }, @@ -400,126 +403,141 @@ const editApp = createApp({ const restoreHtml = (formattedText, attachments) => { const imageList = attachments?.images || []; - const filesList = attachments?.files || []; const videosList = attachments?.videos || []; - let html = formattedText; + let html = formattedText || ""; - // 0. 将所有
,
+ html = html.replace(/\[p\]([\s\S]*?)\[\/p\]/gi, "
$1
"); + + // 0. 基础清理:换行符转/g, "
"); - - // 1. 还原换行符为/g, "
");
+ html = html.replace(/<\/p>
/g, "
$1
'); - // console.log("html1", html); + // 2. [b] -> strong + html = html.replace(/\[b\]([\s\S]*?)\[\/b\]/gi, "$1"); - // 5. 还原 a > [img] 的情况 - html = html.replace(/]*>\[img(?:=([0-9]+(?:\.[0-9]+)?)(?:,([0-9]+(?:\.[0-9]+)?))?)?\](\d+)\[\/img\]<\/a>/gi, (match, href, width, height, aid) => { + // 3. [align=center] + // 特殊处理嵌套在 h1 中的居中 + html = html.replace(/$1
'); + + // 定义图片处理函数 + const processImg = (aid, width, height, href) => { const image = imageList.find((img) => String(img.aid) === String(aid)); - if (!image) return match; - + if (!image) return ""; + + // 移除已使用的图片 const index = imageList.findIndex((img) => String(img.aid) === String(aid)); if (index > -1) imageList.splice(index, 1); let style = ""; - const w = width ? Number(width) : 0; - const h = height ? Number(height) : 0; - if (w > 0 && h > 0) style = `style="width: ${w}px; height: ${h}px;"`; - else if (w > 0) style = `style="width: ${w}px;"`; + const formatStyleVal = (val) => { + if (!val) return null; + if (String(val).endsWith('%')) return val; + const num = Number(val); + return num > 0 ? `${num}px` : null; + }; - return `]*>([\s\S]*?)<\/p>/gi, "[p]$1[/p]");
+
+ // 3. 处理加粗 [b] (对应 strong, b)
+ html = html.replace(/<(strong|b)[^>]*>([\s\S]*?)<\/\1>/gi, "[b]$2[/b]");
+
+ // 4. 处理图片 [img]
html = html.replace(/]*>/gi, (imgTag) => {
- const srcMatch = imgTag.match(/src="([^"]+)"/i);
let aid = "";
- if (srcMatch && srcMatch[1]) {
- const aidMatch = srcMatch[1].match(/aid=(\d+)/);
+ // 尝试从 src 中获取 aid
+ const srcMatch = imgTag.match(/src="([^"]+)"/i);
+ if (srcMatch) {
+ const aidMatch = srcMatch[1].match(/[?&]aid=(\d+)/);
if (aidMatch) aid = aidMatch[1];
}
-
+ // 尝试从 data-aid 中获取 aid
if (!aid) {
- const dataAidMatch = imgTag.match(/data-aid="(\d+)"/i);
- if (dataAidMatch) aid = dataAidMatch[1];
+ const dataAid = imgTag.match(/data-aid="(\d+)"/i);
+ if (dataAid) aid = dataAid[1];
}
- if (!aid) return imgTag;
+ if (!aid) return ""; // 无法获取 aid,跳过
+
+ // 获取宽高 (支持 px 和 %)
+ let w = 0,
+ h = 0;
const styleMatch = imgTag.match(/style="([^"]+)"/i);
- let width = 0,
- height = 0;
- if (styleMatch && styleMatch[1]) {
- const widthMatch = styleMatch[1].match(/width:\s*(\d+(?:\.\d+)?)px/i);
- const heightMatch = styleMatch[1].match(/height:\s*(\d+(?:\.\d+)?)px/i);
- width = widthMatch ? Number(widthMatch[1]) : 0;
- height = heightMatch ? Number(heightMatch[1]) : 0;
-
- if (!width) {
- const widthPctMatch = styleMatch[1].match(/width:\s*(\d+(?:\.\d+)?)%/i);
- if (widthPctMatch) {
- const el = (editorRef && editorRef.value) || document.querySelector("#editor-container");
- const boxW = el ? el.getBoundingClientRect().width || el.clientWidth || 0 : 0;
- const pct = Number(widthPctMatch[1]);
- if (boxW && pct > 0) width = Math.round((pct / 100) * boxW);
- }
+ if (styleMatch) {
+ // 匹配数字+单位 (px或%)
+ const wMatch = styleMatch[1].match(/width:\s*([\d.]+(?:px|%)?)/i);
+ const hMatch = styleMatch[1].match(/height:\s*([\d.]+(?:px|%)?)/i);
+
+ if (wMatch) {
+ // 如果是百分比,直接保留字符串;如果是纯数字默认视为 px;如果是 px 去掉单位
+ let val = wMatch[1];
+ if (val.endsWith('%')) w = val; // 保留百分比字符串
+ else w = parseFloat(val); // 转为数字 (px)
+ }
+ if (hMatch) {
+ let val = hMatch[1];
+ if (val.endsWith('%')) h = val;
+ else h = parseFloat(val);
}
}
+ // 兼容 width/height 属性 (通常只有数字)
+ if (!w) {
+ const wAttr = imgTag.match(/\swidth="(\d+)"/i);
+ if (wAttr) w = Number(wAttr[1]);
+ }
+ if (!h) {
+ const hAttr = imgTag.match(/\sheight="(\d+)"/i);
+ if (hAttr) h = Number(hAttr[1]);
+ }
- console.log("width", width, "height", height);
+ let result = "";
+ if (w || h) { // 只要有一个有值
+ const formatVal = (val) => {
+ if (typeof val === 'string' && val.endsWith('%')) return val;
+ return val ? parseFloat(Number(val).toFixed(2)) : 0;
+ };
+ result = `[img=${formatVal(w)},${formatVal(h)}]${aid}[/img]`;
+ } else {
+ result = `[img]${aid}[/img]`;
+ }
- // 第四步:按规则生成格式
- let result;
- if (width == 0 && height == 0) result = `[img]${aid}[/img]`;
- else result = `[img=${width}${height ? "," + height : ""}]${aid}[/img]`;
-
- // 提取 data-href 并添加 a 标签
- const dataHrefMatch = imgTag.match(/data-href="([^"]+)"/i);
- if (dataHrefMatch && dataHrefMatch[1]) result = `${result}`;
+ // 处理 data-href,包裹在 [url] 中
+ const hrefMatch = imgTag.match(/data-href="([^"]+)"/i);
+ if (hrefMatch && hrefMatch[1]) {
+ result = `[url=${hrefMatch[1]}]${result}[/url]`;
+ }
return result;
});
- // 1.1 替换视频标签
+ // 5. 处理视频 [attach]
html = html.replace(/