Commit 0f82ec2b by pangchong

fix(editor): 优化多处文本编辑行为,支持安全的换行和换行样式

- 为多个编辑区域添加 whitespace-pre-wrap 样式,解决换行显示问题
- 新增 handleEnterKey 函数,拦截 Enter 键实现安全换行,避免生成多余节点
- 编辑模式中使用 v-text 确保文本内容在失焦后正确刷新 DOM
- 多处文本编辑元素添加 @keydown.enter.prevent,防止默认换行行为
- 对比模式下展示词级差异时保持文本单行预格式化显示
- ListEditor、TableEditor、TextBlockEditor 组件中同步改进换行和按键行为
parent 4114f00e
...@@ -345,6 +345,33 @@ export function useDocNodeRenderer(props: { node: XmlNode; parent?: XmlNode | nu ...@@ -345,6 +345,33 @@ export function useDocNodeRenderer(props: { node: XmlNode; parent?: XmlNode | nu
return props.node.children.find((c) => c.id === childId) return props.node.children.find((c) => c.id === childId)
} }
// 拦截 Enter 键以使用安全的文本换行,避免浏览器生成多余的嵌套 div/br 节点
const handleEnterKey = (e: KeyboardEvent) => {
e.preventDefault()
try {
if (document.queryCommandSupported && document.queryCommandSupported('insertText')) {
document.execCommand('insertText', false, '\n')
return
}
} catch (err) {
// 忽略报错,回退到 Range 插入
}
const selection = window.getSelection()
if (!selection || !selection.rangeCount) return
const range = selection.getRangeAt(0)
range.deleteContents()
const textNode = document.createTextNode('\n')
range.insertNode(textNode)
range.setStartAfter(textNode)
range.setEndAfter(textNode)
selection.removeAllRanges()
selection.addRange(range)
const el = e.target as HTMLElement
el.dispatchEvent(new Event('input', { bubbles: true }))
}
// 文本框值修改同步 // 文本框值修改同步
const handleTextBlur = (e: FocusEvent) => { const handleTextBlur = (e: FocusEvent) => {
const el = e.target as HTMLElement const el = e.target as HTMLElement
...@@ -448,6 +475,7 @@ export function useDocNodeRenderer(props: { node: XmlNode; parent?: XmlNode | nu ...@@ -448,6 +475,7 @@ export function useDocNodeRenderer(props: { node: XmlNode; parent?: XmlNode | nu
getTopicContentNodes, getTopicContentNodes,
getChildNode, getChildNode,
handleTextBlur, handleTextBlur,
handleEnterKey,
handleChildTextBlur, handleChildTextBlur,
handleMixedTextBlur, handleMixedTextBlur,
getGraphicTitle, getGraphicTitle,
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
contenteditable="true" contenteditable="true"
class="flex-1 min-h-[32px] px-2 py-1.5 rounded border border-divider focus:outline-none focus:ring-1 focus:ring-primary text-sm bg-fill-3 text-color2 leading-relaxed" class="flex-1 min-h-[32px] px-2 py-1.5 rounded border border-divider focus:outline-none focus:ring-1 focus:ring-primary text-sm bg-fill-3 text-color2 leading-relaxed"
@blur="(e) => handleTextBlur(item.id, e)" @blur="(e) => handleTextBlur(item.id, e)"
@keydown.enter.prevent
v-text="item.text" v-text="item.text"
></div> ></div>
</div> </div>
......
...@@ -101,6 +101,7 @@ ...@@ -101,6 +101,7 @@
:data-node-id="para.id" :data-node-id="para.id"
data-tag-name="PARA" data-tag-name="PARA"
:contenteditable="!isDiffMode" :contenteditable="!isDiffMode"
class="whitespace-pre-wrap"
:class="[ :class="[
isNodeSelected(para.id) isNodeSelected(para.id)
? 'ring-2 ring-primary bg-primary/5 font-bold' ? 'ring-2 ring-primary bg-primary/5 font-bold'
...@@ -111,6 +112,7 @@ ...@@ -111,6 +112,7 @@
:style="para.attributes?.MERGED === 'TRUE' ? { backgroundColor: 'yellow' } : {}" :style="para.attributes?.MERGED === 'TRUE' ? { backgroundColor: 'yellow' } : {}"
@click.stop="isDiffMode ? null : handleParaClick(para, cell, $event)" @click.stop="isDiffMode ? null : handleParaClick(para, cell, $event)"
@blur="(e) => handleCellBlur(para.id, e)" @blur="(e) => handleCellBlur(para.id, e)"
@keydown.enter.prevent
v-text="para.text" v-text="para.text"
></div> ></div>
</template> </template>
...@@ -211,6 +213,7 @@ ...@@ -211,6 +213,7 @@
:data-node-id="para.id" :data-node-id="para.id"
data-tag-name="PARA" data-tag-name="PARA"
:contenteditable="!isDiffMode" :contenteditable="!isDiffMode"
class="whitespace-pre-wrap"
:class="[ :class="[
isNodeSelected(para.id) isNodeSelected(para.id)
? 'ring-2 ring-primary bg-primary/5' ? 'ring-2 ring-primary bg-primary/5'
...@@ -221,6 +224,7 @@ ...@@ -221,6 +224,7 @@
:style="para.attributes?.MERGED === 'TRUE' ? { backgroundColor: 'yellow' } : {}" :style="para.attributes?.MERGED === 'TRUE' ? { backgroundColor: 'yellow' } : {}"
@click.stop="isDiffMode ? null : handleParaClick(para, cell, $event)" @click.stop="isDiffMode ? null : handleParaClick(para, cell, $event)"
@blur="(e) => handleCellBlur(para.id, e)" @blur="(e) => handleCellBlur(para.id, e)"
@keydown.enter.prevent
v-text="para.text" v-text="para.text"
></div> ></div>
</template> </template>
......
...@@ -53,6 +53,7 @@ ...@@ -53,6 +53,7 @@
contenteditable="true" contenteditable="true"
class="flex-1 min-h-[32px] px-2 py-1.5 rounded border border-divider focus:outline-none focus:ring-1 focus:ring-primary text-sm bg-fill-3 text-color2" class="flex-1 min-h-[32px] px-2 py-1.5 rounded border border-divider focus:outline-none focus:ring-1 focus:ring-primary text-sm bg-fill-3 text-color2"
@blur="(e) => handleSliceTextBlur(index, e)" @blur="(e) => handleSliceTextBlur(index, e)"
@keydown.enter.prevent
v-text="item.text" v-text="item.text"
></div> ></div>
</div> </div>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment