富文本优化

This commit is contained in:
2026-07-14 13:09:35 +08:00
parent 3ded1868a3
commit b909dd693e
@@ -52,6 +52,7 @@
:title="disabled ? '富文本宽屏查看' : '富文本宽屏编辑'"
width="96vw"
:footer="null"
centered
:mask-closable="false"
:body-style="{ padding: '0', height: '82vh', overflow: 'hidden' }"
@update:open="handleFullscreenVisibleChange"
@@ -177,11 +178,11 @@ const toolbarGroups = [
{ key: 'insertUnorderedList', label: '无序列表', command: 'insertUnorderedList' },
{ key: 'insertOrderedList', label: '有序列表', command: 'insertOrderedList' },
],
[
{ key: 'insertTable', label: '插入表格', type: 'insertTable' },
{ key: 'undo', label: '撤销', command: 'undo' },
{ key: 'redo', label: '重做', command: 'redo' },
],
// [
// { key: 'insertTable', label: '插入表格', type: 'insertTable' },
// { key: 'undo', label: '撤销', command: 'undo' },
// { key: 'redo', label: '重做', command: 'redo' },
// ],
]
const savedRanges = {
@@ -357,6 +358,10 @@ function handleToolbarAction(action, targetSurface = '') {
insertDefaultTable(targetSurface)
return
}
if (['justifyLeft', 'justifyCenter', 'justifyRight'].includes(action.command)) {
applyTextAlignment(action.command, targetSurface)
return
}
runDocumentCommand(action.command, action.value, targetSurface)
}
@@ -396,6 +401,9 @@ function insertHtmlAtCursor(html, targetSurface = '') {
const editor = getEditorElement(surface)
insertHtmlByRange(editor, html)
}
if (/<table[\s>]/i.test(html)) {
focusFirstTableCell(surface)
}
captureSelection(surface)
handleEditorInput(surface)
}
@@ -435,10 +443,10 @@ function insertHtmlByRange(editor, html) {
function buildDefaultTableHtml(rows = 4, cols = 4) {
const minWidth = Math.max(640, cols * 140)
const rowHtml = Array.from({ length: rows }, () => {
const cellHtml = Array.from({ length: cols }, () => '<td><br></td>').join('')
const cellHtml = Array.from({ length: cols }, () => '<td>&nbsp;</td>').join('')
return `<tr>${cellHtml}</tr>`
}).join('')
return `<table style="width:100%;min-width:${minWidth}px;border-collapse:collapse;table-layout:auto;margin:8px 0;">${rowHtml}</table><p><br></p>`
return `<table style="width:100%;min-width:${minWidth}px;border-collapse:collapse;table-layout:auto;margin:8px 0;border:1px solid #1f2937;">${rowHtml}</table><p><br></p>`
}
function handlePaste(event, surface) {
@@ -586,6 +594,7 @@ function applyNormalizedCellStyle(sourceCell, targetCell) {
targetCell.style.wordBreak = 'keep-all'
targetCell.style.overflowWrap = 'break-word'
targetCell.style.whiteSpace = 'pre-wrap'
targetCell.style.lineHeight = '1.7'
targetCell.style.minWidth = '120px'
if (textAlign) {
@@ -678,13 +687,81 @@ function buildPlainTextTableHtml(text) {
.map((cells) => {
const cellHtml = Array.from({ length: columnCount }, (_, index) => {
const value = escapeHtml(String(cells[index] || '').trim())
return `<td>${value || '<br>'}</td>`
return `<td>${value || '&nbsp;'}</td>`
}).join('')
return `<tr>${cellHtml}</tr>`
})
.join('')
return `<table style="width:100%;min-width:${minWidth}px;border-collapse:collapse;table-layout:auto;margin:8px 0;">${rowHtml}</table><p><br></p>`
return `<table style="width:100%;min-width:${minWidth}px;border-collapse:collapse;table-layout:auto;margin:8px 0;border:1px solid #1f2937;">${rowHtml}</table><p><br></p>`
}
function applyTextAlignment(command, targetSurface = '') {
if (props.disabled) {
return
}
const surface = resolveTargetSurface(targetSurface)
activeSurface.value = surface
restoreSelection(surface)
const editor = getEditorElement(surface)
if (!editor) {
return
}
const alignValue = resolveAlignValue(command)
if (!alignValue) {
return
}
const selection = window.getSelection()
if (!selection || !selection.rangeCount) {
editor.style.textAlign = alignValue
handleEditorInput(surface)
return
}
const range = selection.getRangeAt(0)
const block = findAlignmentTarget(range.startContainer, editor)
;(block || editor).style.textAlign = alignValue
captureSelection(surface)
handleEditorInput(surface)
}
function resolveAlignValue(command) {
if (command === 'justifyLeft') return 'left'
if (command === 'justifyCenter') return 'center'
if (command === 'justifyRight') return 'right'
return ''
}
function findAlignmentTarget(node, editor) {
let current = node?.nodeType === Node.ELEMENT_NODE ? node : node?.parentElement || null
while (current && current !== editor) {
const tag = String(current.tagName || '').toLowerCase()
if (['p', 'div', 'li', 'td', 'th'].includes(tag)) {
return current
}
current = current.parentElement
}
return editor
}
function focusFirstTableCell(surface) {
const editor = getEditorElement(surface)
if (!editor) {
return
}
const firstCell = editor.querySelector('td, th')
if (!firstCell) {
return
}
const selection = window.getSelection()
if (!selection) {
return
}
const range = document.createRange()
range.selectNodeContents(firstCell)
range.collapse(true)
selection.removeAllRanges()
selection.addRange(range)
savedRanges[surface] = range.cloneRange()
}
function openFullscreen() {
@@ -833,6 +910,7 @@ function escapeHtml(text) {
margin: 8px 0;
border-collapse: collapse;
table-layout: auto;
border: 1px solid #1f2937;
background: #fff;
}
@@ -845,6 +923,7 @@ function escapeHtml(text) {
word-break: keep-all;
overflow-wrap: break-word;
white-space: pre-wrap;
line-height: 1.7;
}
.editor-surface th {