fix: 🧩 修復不能換行

This commit is contained in:
2025-07-31 12:36:42 +08:00
parent 4e8f3e6564
commit 1566a72cb6
2 changed files with 122 additions and 89 deletions

BIN
dist.zip

Binary file not shown.

View File

@@ -112,7 +112,7 @@
<script setup name="Editor"> <script setup name="Editor">
import { QuillEditor, Quill } from "@vueup/vue-quill"; import { QuillEditor, Quill } from "@vueup/vue-quill";
import "@vueup/vue-quill/dist/vue-quill.snow.css"; import "@vueup/vue-quill/dist/vue-quill.snow.css";
import { getCurrentInstance, reactive, ref, toRaw, computed, onMounted, nextTick, watch } from "vue"; import { getCurrentInstance, reactive, ref, toRaw, computed, onMounted, nextTick } from "vue";
import { generateUUID } from "@/utils"; import { generateUUID } from "@/utils";
// import { h } from "@/utils/url"; // import { h } from "@/utils/url";
import { routerObj } from "./utils.js"; import { routerObj } from "./utils.js";
@@ -228,17 +228,9 @@ const options = reactive({
outerVisible.value = value; outerVisible.value = value;
} }
} }
},
clipboard: {
matchVisual: false // 禁用视觉匹配(减少空标签)
} }
}, },
formats: [
// ... 原有格式
"align",
"bold",
"italic" // 只保留必要格式,减少自动生成的空标签
],
placeholder: "请输入内容...", placeholder: "请输入内容...",
readOnly: props.readOnly readOnly: props.readOnly
}); });
@@ -302,27 +294,88 @@ const handleBeforeUpload = file => {
imageListDb.value = imageListDb.value.filter(item => item.customUid !== file.customUid); imageListDb.value = imageListDb.value.filter(item => item.customUid !== file.customUid);
return false; return false;
} }
console.log(imageListDb.value, "=================value==================");
return true; return true;
}; };
// 图片上传(保持不变) // // 图片上传(保持不变)
// const handleHttpUpload = async options => {
// let formData = new FormData();
// formData.append("image", options.file);
// imageList.value.push(options.file);
// try {
// const result = await uploadImg(formData, routerName.value, options.file.customUid);
// if (result?.data?.code === 0) {
// const { data } = result.data;
// const { imgId } = result;
// const fileItem = imageListDb.value.find(item => item.customUid === imgId);
// if (fileItem) {
// fileItem.serverImgId = imgId;
// fileItem.path = data.path;
// }
// const allFilesUploaded = imageListDb.value.every(item => item.path);
// if (allFilesUploaded) {
// let rawQuillEditor = "";
// let quill = "";
// if (activeEditor.value === "main") {
// rawQuillEditor = toRaw(myQuillEditor.value);
// quill = rawQuillEditor.getQuill();
// } else {
// const tabIndex = parseInt(activeEditor.value.split("-")[1]);
// rawQuillEditor = toRaw(tabEditors.value[tabIndex]);
// quill = rawQuillEditor.getQuill();
// }
// imageListDb.value.forEach(item => {
// const length = quill.getLength() - 1;
// quill.insertEmbed(length, "customImage", {
// url: item.path,
// id: item.serverImgId || generateUUID()
// });
// quill.setSelection(length + 1);
// });
// const finalLength = quill.getLength();
// quill.setSelection(finalLength);
// imageList.value = [];
// imageListDb.value = [];
// }
// }
// } catch (error) {
// console.error("图片上传失败:", error);
// imageList.value = imageList.value.filter(item => item.customUid !== options.file.customUid);
// imageListDb.value = imageListDb.value.filter(item => item.customUid !== options.file.customUid);
// }
// };
// // 图片上传(修改插入位置逻辑)
const handleHttpUpload = async options => { const handleHttpUpload = async options => {
let formData = new FormData(); let formData = new FormData();
formData.append("image", options.file); formData.append("image", options.file);
imageList.value.push(options.file); // imageList.value.push(options.file);
try { try {
const result = await uploadImg(formData, routerName.value, options.file.customUid); const result = await uploadImg(formData, routerName.value, options.file.customUid);
if (result?.data?.code === 0) { if (result?.data?.code === 0) {
const { data } = result.data; const { data } = result.data;
const { imgId } = result; const { imgId } = result;
// imageListDb.value.forEach(item => {
// if (item.customUid === imgId) {
// item.serverImgId = imgId;
// item.path = data.path;
// console.log(item.path, "================>");
// }
// });
const fileItem = imageListDb.value.find(item => item.customUid === imgId); const fileItem = imageListDb.value.find(item => item.customUid === imgId);
console.log(fileItem, "=fileItem=");
if (fileItem) { if (fileItem) {
fileItem.serverImgId = imgId; fileItem.serverImgId = imgId;
fileItem.path = data.path; fileItem.path = data.path;
} }
const allFilesUploaded = imageListDb.value.every(item => item.path); const allFilesUploaded = imageListDb.value.every(item => item.path);
if (allFilesUploaded) { if (allFilesUploaded) {
let rawQuillEditor = ""; let rawQuillEditor = "";
@@ -336,17 +389,23 @@ const handleHttpUpload = async options => {
quill = rawQuillEditor.getQuill(); quill = rawQuillEditor.getQuill();
} }
imageListDb.value.forEach(item => { // 关键修改:获取当前光标位置(选区起始索引)
const length = quill.getLength() - 1; const selection = quill.getSelection();
quill.insertEmbed(length, "customImage", { // 如果没有选区(光标未激活),默认插入到末尾
const insertPosition = selection ? selection.index : quill.getLength();
imageListDb?.value?.forEach(item => {
// 使用光标位置插入图片
quill.insertEmbed(insertPosition, "customImage", {
url: item.path, url: item.path,
id: item.serverImgId || generateUUID() id: item.serverImgId || generateUUID()
}); });
quill.setSelection(length + 1); // 插入后光标后移一位(避免多张图片重叠插入)
quill.setSelection(insertPosition + 1);
}); });
const finalLength = quill.getLength(); // 最终光标定位到最后一张图片后面
quill.setSelection(finalLength); const finalPosition = insertPosition + imageListDb.value.length;
quill.setSelection(finalPosition);
imageList.value = []; imageList.value = [];
imageListDb.value = []; imageListDb.value = [];
@@ -639,43 +698,38 @@ const loadTabsDataToEditor = tabs => {
}); });
}; };
// 清理空标签的专用函数(针对 Quill 生成的空 <p> // const cleanEmptyTags = container => {
const cleanEmptyTags = container => { // if (!container) return;
if (!container) return;
// 1. 获取所有 <p> 标签 // // 获取所有 <p> 标签
const allPTags = container.querySelectorAll("p"); // const pTags = container.querySelectorAll("p");
if (allPTags.length === 0) return;
// 2. 手动判断标签是否为空(处理隐形字符 // // 只清理真正的空标签(不含任何内容,包括<br>
Array.from(allPTags).forEach(pTag => { // Array.from(pTags).forEach(pTag => {
// 清除所有空白字符(包括 &nbsp;、换行、空格) // // 判断标准:
const trimmedContent = pTag.innerHTML // // 1. 完全没有子节点
.replace(/&nbsp;/g, "") // 替换 HTML 空格实体 // // 2. 或innerHTML为空字符串
.replace(/\s+/g, "") // 替换所有空白字符(空格、换行等) // const isCompletelyEmpty = pTag.childNodes.length === 0 || pTag.innerHTML.trim() === "";
.replace(/<br\s*\/?>/gi, ""); // 移除 <br> 标签
// 判断是否为空标签(清理后内容长度为 0 // if (isCompletelyEmpty) {
const isEmpty = trimmedContent.length === 0; // // 特殊处理:保留首尾空标签,避免编辑器异常
// const isFirstOrLast = pTag === container.firstElementChild || pTag === container.lastElementChild;
if (isEmpty) { // if (isFirstOrLast) {
// 保留首尾空标签,避免编辑器异常 // pTag.innerHTML = ""; // 清空内容
const isFirstOrLast = pTag === container.firstElementChild || pTag === container.lastElementChild; // } else {
if (!isFirstOrLast) { // pTag.remove(); // 移除中间的纯空标签
pTag.remove(); // }
} else { // }
pTag.innerHTML = ""; // 清空内容 // });
} // };
} // // 触发清理的函数(针对所有编辑器)
}); // const handleCleanEmptyTags = () => {
}; // // 处理主编辑器
// 触发清理的函数(针对所有编辑器) // const mainEditor = document.querySelector("#mainEditor .ql-editor");
const handleCleanEmptyTags = () => { // console.log(mainEditor, "=mainEditor=");
// 处理主编辑器 // if (mainEditor) cleanEmptyTags(mainEditor);
const mainEditor = document.querySelector("#mainEditor .ql-editor"); // };
console.log(mainEditor, "=mainEditor=");
if (mainEditor) cleanEmptyTags(mainEditor);
};
onMounted(() => { onMounted(() => {
initTitle(); initTitle();
@@ -695,14 +749,14 @@ onMounted(() => {
}); });
} }
// 等待编辑器首次渲染完成 // 等待编辑器首次渲染完成
setTimeout(handleCleanEmptyTags, 300); // setTimeout(handleCleanEmptyTags, 300);
}); });
// 监听内容变化,重新清理空标签 // 监听内容变化,重新清理空标签
watch(editorContent, () => { // watch(editorContent, () => {
nextTick(() => { // nextTick(() => {
setTimeout(handleCleanEmptyTags, 100); // 延迟确保 Quill 已重新渲染 // setTimeout(handleCleanEmptyTags, 100); // 延迟确保 Quill 已重新渲染
}); // });
}); // });
defineExpose({ defineExpose({
clearEditor: () => { clearEditor: () => {
const quill = toRaw(myQuillEditor.value)?.getQuill(); const quill = toRaw(myQuillEditor.value)?.getQuill();
@@ -740,52 +794,36 @@ defineExpose({
width: 100px; width: 100px;
margin: -2px 0; /* 与标签对齐 */ margin: -2px 0; /* 与标签对齐 */
} }
/* 详情样式 */
.o_detail_all { .o_detail_all {
overflow: hidden;
text-align: center; text-align: center;
background-color: #ffffff;
} }
.o_detail_title { .o_detail_title {
margin-top: 3.125vw; margin-top: 2vw;
margin-bottom: 1.25vw; margin-bottom: 1.25vw;
overflow: hidden;
font-size: 2.25em; font-size: 2.25em;
font-weight: 600; font-weight: 600;
line-height: 1.2em; line-height: 1.2em;
color: #101010; color: #101010;
text-align: center;
background-color: #ffffff;
} }
/* stylelint-disable-next-line no-duplicate-selectors */
.o_detail_small { .o_detail_small {
margin-bottom: 0.7vw; margin-bottom: 0.7vw;
font-size: 1.5em; font-size: 1.5em;
color: #333333; color: #333333;
} }
/* stylelint-disable-next-line no-duplicate-selectors */
.o_detail_text { .o_detail_text {
width: 80%; width: 80%;
margin-right: auto; margin-right: auto;
margin-bottom: 0.7vw; margin-bottom: 0.7vw;
margin-left: auto; margin-left: auto;
font-size: 1em;
line-height: 1.5em;
color: #737373;
}
/* stylelint-disable-next-line no-duplicate-selectors */
.o_detail_title {
padding: 4% 0 2.8%;
font-size: 2.25em;
color: #101010;
}
/* stylelint-disable-next-line no-duplicate-selectors */
.o_detail_small {
padding-bottom: 1.8%;
font-size: 1.5em;
color: #333333;
}
/* stylelint-disable-next-line no-duplicate-selectors */
.o_detail_text {
width: 80%;
padding: 0 0 1.8%;
margin: auto;
font-size: 1.125em; font-size: 1.125em;
line-height: 1.875em; line-height: 1.5em;
color: #737373; color: #737373;
} }
.products_des { .products_des {
@@ -841,9 +879,4 @@ defineExpose({
.seo-pro a:hover { .seo-pro a:hover {
color: #009fdf; color: #009fdf;
} }
/* stylelint-disable-next-line no-duplicate-selectors */
// .o_detail_all {
// text-align: center;
// }
/* stylelint-disable-next-line no-duplicate-selectors */
</style> </style>