refactor(editor): 优化编辑器输入处理逻辑和性能

- 重构输入事件处理函数,减少不必要的DOM操作
- 简化键盘事件处理逻辑,移除冗余日志
- 优化消息发送逻辑,增加内容检查
- 改进引用元素处理,增强交互体验
- 统一表情处理逻辑,使用switch语句替代if-else
- 优化草稿保存和加载机制,使用DocumentFragment提高性能
- 清理冗余代码和注释,保持代码简洁
This commit is contained in:
Phoenix 2025-06-09 11:37:39 +08:00
parent 3ec981ea7f
commit 7fea56f704
2 changed files with 362 additions and 386 deletions

View File

@ -94,7 +94,7 @@ const toolbarConfig = computed(() => {
return config return config
}) })
// // - DOM
const handleInput = (event) => { const handleInput = (event) => {
const target = event.target const target = event.target
@ -108,24 +108,33 @@ const handleInput = (event) => {
let textContent = editorClone.textContent || '' let textContent = editorClone.textContent || ''
// alt // alt
emojiImages.forEach(emoji => { if (emojiImages.length > 0) {
const altText = emoji.getAttribute('alt') emojiImages.forEach(emoji => {
if (altText) { const altText = emoji.getAttribute('alt')
textContent += altText if (altText) {
} textContent += altText
}) }
})
}
// //
editorContent.value = textContent editorContent.value = textContent
// placeholder
const isEmpty = textContent.trim() === '' &&
!target.querySelector('img, .editor-file, .mention')
if (isEmpty && target.innerHTML !== '') {
target.innerHTML = ''
}
// HTML
editorHtml.value = target.innerHTML || '' editorHtml.value = target.innerHTML || ''
// @mention //
checkMention(target) checkMention(target)
// 稿
saveDraft() saveDraft()
//
emit('editor-event', { emit('editor-event', {
event: 'input_event', event: 'input_event',
data: editorContent.value data: editorContent.value
@ -301,7 +310,7 @@ const handlePaste = (event) => {
} }
} }
// // -
const handleKeydown = (event) => { const handleKeydown = (event) => {
// @ // @
if (showMention.value) { if (showMention.value) {
@ -313,11 +322,8 @@ const handleKeydown = (event) => {
nextTick(() => { nextTick(() => {
const mentionList = document.querySelector('.mention-list ul') const mentionList = document.querySelector('.mention-list ul')
const selectedItem = mentionList?.children[selectedMentionIndex.value] const selectedItem = mentionList?.children[selectedMentionIndex.value]
if (mentionList && selectedItem) { if (mentionList && selectedItem && selectedItem.offsetTop < mentionList.scrollTop) {
// mentionList.scrollTop = selectedItem.offsetTop
if (selectedItem.offsetTop < mentionList.scrollTop) {
mentionList.scrollTop = selectedItem.offsetTop
}
} }
}) })
break break
@ -329,7 +335,6 @@ const handleKeydown = (event) => {
const mentionList = document.querySelector('.mention-list ul') const mentionList = document.querySelector('.mention-list ul')
const selectedItem = mentionList?.children[selectedMentionIndex.value] const selectedItem = mentionList?.children[selectedMentionIndex.value]
if (mentionList && selectedItem) { if (mentionList && selectedItem) {
//
const itemBottom = selectedItem.offsetTop + selectedItem.offsetHeight const itemBottom = selectedItem.offsetTop + selectedItem.offsetHeight
const listBottom = mentionList.scrollTop + mentionList.clientHeight const listBottom = mentionList.scrollTop + mentionList.clientHeight
if (itemBottom > listBottom) { if (itemBottom > listBottom) {
@ -341,8 +346,9 @@ const handleKeydown = (event) => {
case 'Enter': case 'Enter':
case 'Tab': case 'Tab':
event.preventDefault() event.preventDefault()
if (mentionList.value[selectedMentionIndex.value]) { const selectedMember = mentionList.value[selectedMentionIndex.value]
insertMention(mentionList.value[selectedMentionIndex.value]) if (selectedMember) {
insertMention(selectedMember)
} }
break break
case 'Escape': case 'Escape':
@ -351,146 +357,104 @@ const handleKeydown = (event) => {
} }
return return
} }
console.log('键盘事件:', event.key, 'Ctrl:', event.ctrlKey, 'Meta:', event.metaKey, 'Shift:', event.shiftKey);
// Ctrl+EnterShift+Enter // Ctrl+EnterShift+Enter
if (event.key === 'Enter' && (event.ctrlKey || event.metaKey || event.shiftKey)) { if (event.key === 'Enter' && (event.ctrlKey || event.metaKey || event.shiftKey)) {
console.log('Ctrl+Enter或Shift+Enter换行');
//
// //
const selection = window.getSelection(); const selection = window.getSelection()
if (selection && selection.rangeCount > 0) { if (selection && selection.rangeCount > 0) {
const range = selection.getRangeAt(0); const range = selection.getRangeAt(0)
const br = document.createElement('br'); const br = document.createElement('br')
range.deleteContents(); range.deleteContents()
range.insertNode(br); range.insertNode(br)
// //
const textNode = document.createTextNode(''); const textNode = document.createTextNode('')
range.setStartAfter(br); range.setStartAfter(br)
range.insertNode(textNode); range.insertNode(textNode)
range.setStartAfter(textNode); range.setStartAfter(textNode)
range.collapse(true); range.collapse(true)
selection.removeAllRanges(); selection.removeAllRanges()
selection.addRange(range); selection.addRange(range)
// //
handleInput({ target: editorRef.value }); handleInput({ target: editorRef.value })
} }
// //
event.preventDefault(); event.preventDefault()
return; return
} }
// EnterCtrl/Cmd/Shift // EnterCtrl/Cmd/Shift
if (event.key === 'Enter' && !event.ctrlKey && !event.metaKey && !event.shiftKey) { if (event.key === 'Enter' && !event.ctrlKey && !event.metaKey && !event.shiftKey) {
console.log('Enter发送消息'); event.preventDefault()
event.preventDefault();
console.log('editorContent.value', editorContent.value); // quoteData quoteData
console.log('editorHtml.value', editorHtml.value); const editor = editorRef.value
// const quoteElement = editor?.querySelector('.editor-quote')
// handleInput editorContent.value if (!quoteElement && quoteData.value) {
// if (editorContent.value.trim()) { quoteData.value = null
if (true) {
// quoteData quoteData
const editor = editorRef.value
const quoteElement = editor?.querySelector('.editor-quote')
if (!quoteElement && quoteData.value) {
console.log('引用元素已被删除,但 quoteData 仍有值,清除 quoteData')
quoteData.value = null
}
//
const messageData = parseEditorContent()
console.log('编辑器内容解析结果:', JSON.stringify(messageData, null, 2))
//
console.log('消息项目数量:', messageData.items.length)
console.log('消息项目类型:', messageData.items.map(item => item.type))
console.log('提及用户IDs:', messageData.mentionUids)
console.log('引用消息ID:', messageData.quoteId)
//
sendMessage()
} }
//
sendMessage()
} }
// Ctrl+EnterWangEditoronKeyDown
} }
// // -
const sendMessage = () => { const sendMessage = () => {
console.log('发送消息'); //
//
// if (!editorContent.value.trim()) {
// return
// }
console.log('发送消息1');
const messageData = parseEditorContent() const messageData = parseEditorContent()
// //
console.log('完整消息数据:', { if (messageData.items.length === 0 ||
items: messageData.items, (messageData.items.length === 1 &&
mentionUids: messageData.mentionUids, messageData.items[0].type === 1 &&
quoteId: messageData.quoteId, !messageData.items[0].content.trim())) {
quoteData: quoteData.value ? { return //
id: quoteData.value.id, }
title: quoteData.value.title,
describe: quoteData.value.describe, //
image: quoteData.value.image
} : null
})
messageData.items.forEach(item => { messageData.items.forEach(item => {
// //
if (item.type === 1) { if (item.type === 1 && item.content.trim()) {
const data={ const data = {
items:[{ items: [{
content:item.content, content: item.content,
type:1 type: 1
}], }],
mentionUids:messageData.mentionUids, mentionUids: messageData.mentionUids,
mentions:[], mentions: [],
quoteId:messageData.quoteId, quoteId: messageData.quoteId,
} }
console.log('发送前',data)
console.log('quoteData',quoteData.value)
emit( emit(
'editor-event', 'editor-event',
emitCall('text_event', data,(ok)=>{ emitCall('text_event', data)
console.log('发送后',ok)
})
) )
}else if(item.type === 2){ } else if (item.type === 3) { //
// const data = {
}else if(item.type === 3){ height: 0,
console.log('发送图片消息') width: 0,
const data={ size: 10000,
height:0, url: item.content,
width:0,
size:10000,
url:item.content,
}
emit(
'editor-event',
emitCall(
'image_event',
data,
(ok) => {
//
}
)
)
}else if(item.type === 4){
} }
clearEditor()
emit(
'editor-event',
emitCall('image_event', data)
)
} else if (item.type === 4) { //
//
}
}) })
//
clearEditor()
} }
// //
const parseEditorContent = () => { const parseEditorContent = () => {
const items = [] const items = []
const mentionUids = [] const mentionUids = []
@ -501,102 +465,120 @@ const parseEditorContent = () => {
// //
const quoteElements = tempDiv.querySelectorAll('.editor-quote') const quoteElements = tempDiv.querySelectorAll('.editor-quote')
let quoteInfo = null const hasQuote = quoteElements.length > 0 && quoteData.value
if (quoteElements.length > 0 && quoteData.value) { const quoteId = hasQuote ? quoteData.value.id || '' : ''
quoteInfo = {
id: quoteData.value.id, //
title: quoteData.value.title, quoteElements.forEach(quote => quote.remove())
describe: quoteData.value.describe,
image: quoteData.value.image let textContent = ''
//
const processNode = (node) => {
if (node.nodeType === Node.TEXT_NODE) {
//
textContent += node.textContent
return
}
if (node.nodeType !== Node.ELEMENT_NODE) return
//
if (node.classList.contains('mention')) {
// @
const userId = node.getAttribute('data-user-id')
if (userId) {
mentionUids.push(parseInt(userId))
}
textContent += node.textContent
} else if (node.tagName === 'IMG') {
//
processImage(node)
} else if (node.classList.contains('emoji')) {
// emoji
textContent += node.getAttribute('alt') || node.textContent
} else if (node.classList.contains('editor-file')) {
//
processFile(node)
} else if (node.childNodes.length) {
//
Array.from(node.childNodes).forEach(processNode)
} else {
//
textContent += node.textContent
} }
} }
let textContent = '' //
const nodes = Array.from(tempDiv.childNodes) const processImage = (node) => {
const src = node.getAttribute('src')
nodes.forEach(node => { const width = node.getAttribute('data-original-width') || node.getAttribute('width') || ''
if (node.nodeType === Node.TEXT_NODE) { const height = node.getAttribute('data-original-height') || node.getAttribute('height') || ''
textContent += node.textContent const isEmoji = node.classList.contains('editor-emoji')
} else if (node.nodeType === Node.ELEMENT_NODE) {
// // items
if (node.classList.contains('editor-quote')) { if (textContent.trim()) {
return items.push({
} type: 1,
content: textContent.trim()
if (node.classList.contains('mention')) { })
const userId = node.getAttribute('data-user-id') textContent = ''
if (userId) {
mentionUids.push(parseInt(userId))
}
textContent += node.textContent
} else if (node.tagName === 'IMG') {
//
const src = node.getAttribute('src')
const width = node.getAttribute('data-original-width') || node.getAttribute('width') || ''
const height = node.getAttribute('data-original-height') || node.getAttribute('height') || ''
const isEmoji = node.classList.contains('editor-emoji')
if (textContent.trim()) {
items.push({
type: 1,
content: textContent.trim()
})
textContent = ''
}
if (isEmoji) {
//
const altText = node.getAttribute('alt') || ''
if (altText) {
// alt
textContent += altText
} else {
//
items.push({
type: 3,
content: src + (width && height ? `?width=${width}&height=${height}` : ''),
isEmoji: true
})
}
} else {
//
items.push({
type: 3,
content: src + (width && height ? `?width=${width}&height=${height}` : ''),
width: width,
height: height
})
}
} else if (node.classList.contains('emoji')) {
textContent += node.getAttribute('alt') || node.textContent
} else if (node.classList.contains('editor-file')) {
//
const fileUrl = node.getAttribute('data-url')
const fileName = node.getAttribute('data-name')
const fileSize = node.getAttribute('data-size')
if (textContent.trim()) {
items.push({
type: 1,
content: textContent.trim()
})
textContent = ''
}
if (fileUrl && fileName) {
items.push({
type: 'file',
content: fileUrl,
name: fileName,
size: node.getAttribute('data-size-raw') || fileSize || 0
})
}
} else {
textContent += node.textContent
}
} }
})
if (isEmoji) {
//
const altText = node.getAttribute('alt') || ''
if (altText) {
// alt
textContent += altText
} else {
//
items.push({
type: 3,
content: src + (width && height ? `?width=${width}&height=${height}` : ''),
isEmoji: true
})
}
} else {
//
items.push({
type: 3,
content: src + (width && height ? `?width=${width}&height=${height}` : ''),
width: width,
height: height
})
}
}
//
const processFile = (node) => {
const fileUrl = node.getAttribute('data-url')
const fileName = node.getAttribute('data-name')
const fileSize = node.getAttribute('data-size')
// items
if (textContent.trim()) {
items.push({
type: 1,
content: textContent.trim()
})
textContent = ''
}
if (fileUrl && fileName) {
items.push({
type: 4, // 使
content: fileUrl,
name: fileName,
size: node.getAttribute('data-size-raw') || fileSize || 0
})
}
}
//
Array.from(tempDiv.childNodes).forEach(processNode)
//
if (textContent.trim()) { if (textContent.trim()) {
items.push({ items.push({
type: 1, type: 1,
@ -605,30 +587,28 @@ const parseEditorContent = () => {
} }
// //
const result = { return {
items: items.length > 0 ? items : [{ type: 1, content: '' }], items: items.length > 0 ? items : [{ type: 1, content: '' }],
mentionUids, mentionUids,
quoteId: quoteElements.length > 0 && quoteData.value ? quoteData.value.id ||'' : '' quoteId
} }
//
if (quoteInfo) {
result.quoteInfo = quoteInfo
}
return result
} }
// //
const clearEditor = () => { const clearEditor = () => {
//
editorContent.value = '' editorContent.value = ''
editorHtml.value = '' editorHtml.value = ''
quoteData.value = null
// DOM
if (editorRef.value) { if (editorRef.value) {
editorRef.value.innerHTML = '' editorRef.value.innerHTML = ''
//
nextTick(() => editorRef.value.focus())
} }
// // @
quoteData.value = null
hideMentionList() hideMentionList()
// 稿 // 稿
@ -655,8 +635,8 @@ const insertImage = (src, width, height) => {
img.src = src img.src = src
img.className = 'editor-image' img.className = 'editor-image'
img.alt = '图片' img.alt = '图片'
img.style.maxHeight = '200px' img.style.maxHeight = '150px'
img.style.maxWidth = '100%' img.style.maxWidth = '150px'
img.style.objectFit = 'contain' // img.style.objectFit = 'contain' //
// //
@ -712,30 +692,25 @@ const onUploadSendImg=async (eventFile)=>{
} }
} }
async function onUploadFile(e) { async function onUploadFile(e) {
let file = e.target.files[0] const file = e.target.files[0]
if (!file) return
e.target.value = null // input
// input
console.log("文件类型"+file.type) e.target.value = null
if (file.type.indexOf('image/') === 0) { if (file.type.indexOf('image/') === 0) {
console.log("进入图片")
// - // -
let fn = emitCall('image_event', file, () => {}) emit('editor-event', emitCall('image_event', file))
emit('editor-event', fn)
return return
} }
if (file.type.indexOf('video/') === 0) { if (file.type.indexOf('video/') === 0) {
console.log("进入视频")
// //
let fn = emitCall('video_event', file, () => {}) emit('editor-event', emitCall('video_event', file))
emit('editor-event', fn)
} else { } else {
console.log("进入其他")
// //
let fn = emitCall('file_event', file, () => {}) emit('editor-event', emitCall('file_event', file))
emit('editor-event', fn)
} }
} }
@ -745,29 +720,29 @@ const onEmoticonEvent = (emoji) => {
emoticonRef.value?.setShow(false) emoticonRef.value?.setShow(false)
// //
if (emoji.type === 'text') { switch (emoji.type) {
// case 'text':
insertTextEmoji(emoji.value) case 'emoji':
} else if (emoji.type === 'image') { // 使
//
insertImageEmoji(emoji.img, emoji.value)
} else if (emoji.type === 'emoji') {
//
insertTextEmoji(emoji.value)
} else if (emoji.type === 1) {
//
if (emoji.img) {
insertImageEmoji(emoji.img, emoji.value)
} else {
insertTextEmoji(emoji.value) insertTextEmoji(emoji.value)
} break
} else {
// case 'image':
emit('editor-event', { //
event: 'emoticon_event', insertImageEmoji(emoji.img, emoji.value)
data: emoji.value || emoji.id, break
callBack: () => {}
}) case 1: //
emoji.img ? insertImageEmoji(emoji.img, emoji.value) : insertTextEmoji(emoji.value)
break
default:
//
emit('editor-event', {
event: 'emoticon_event',
data: emoji.value || emoji.id
})
break
} }
} }
@ -892,28 +867,23 @@ const onSubscribeQuote = (data) => {
// 使 // 使
quoteElement.addEventListener('click', (e) => { quoteElement.addEventListener('click', (e) => {
console.log('执行删除',e)
// //
const closeButton = e.target.classList?.contains('quote-close') ? e.target : e.target.closest('.quote-close') const closeButton = e.target.classList?.contains('quote-close') ? e.target : e.target.closest('.quote-close')
//
e.stopPropagation()
if (closeButton) { if (closeButton) {
// //
e.stopPropagation()
//
quoteElement.remove() quoteElement.remove()
//
quoteData.value = null quoteData.value = null
// handleInput稿 // handleInput稿
//
editorContent.value = editor.textContent || '' editorContent.value = editor.textContent || ''
editorHtml.value = editor.innerHTML || '' editorHtml.value = editor.innerHTML || ''
// // 使nextTickDOM
setTimeout(() => { nextTick(() => editor.focus())
editor.focus()
}, 0)
} else { } else {
// //
const selection = window.getSelection() const selection = window.getSelection()
@ -923,7 +893,7 @@ const onSubscribeQuote = (data) => {
selection.removeAllRanges() selection.removeAllRanges()
selection.addRange(range) selection.addRange(range)
// //
editor.focus() editor.focus()
} }
}) })
@ -935,11 +905,11 @@ const onSubscribeQuote = (data) => {
// //
// //
// //
//
const handleDeleteQuote = function(e) { const handleDeleteQuote = function(e) {
// Backspace Delete // Backspace Delete
if (e.key === 'Backspace' || e.key === 'Delete') { if (e.key !== 'Backspace' && e.key !== 'Delete') return;
const selection = window.getSelection(); const selection = window.getSelection();
if (selection.rangeCount === 0) return; if (selection.rangeCount === 0) return;
@ -952,25 +922,32 @@ const onSubscribeQuote = (data) => {
return; return;
} }
//
const quoteIndex = Array.from(editor.childNodes).indexOf(quoteElement);
// BackspaceDelete // BackspaceDelete
const isBeforeQuote = e.key === 'Backspace' && const isBeforeQuote = e.key === 'Backspace' &&
range.collapsed && range.collapsed &&
range.startContainer === editor && range.startContainer === editor &&
Array.from(editor.childNodes).indexOf(quoteElement) === range.startOffset; quoteIndex === range.startOffset;
const isAfterQuote = e.key === 'Delete' && const isAfterQuote = e.key === 'Delete' &&
range.collapsed && range.collapsed &&
range.startContainer === editor && range.startContainer === editor &&
Array.from(editor.childNodes).indexOf(quoteElement) === range.startOffset - 1; quoteIndex === range.startOffset - 1;
if (isBeforeQuote || isAfterQuote) { if (isBeforeQuote || isAfterQuote) {
//
e.preventDefault();
//
quoteElement.remove(); quoteElement.remove();
quoteData.value = null; quoteData.value = null;
//
handleInput({ target: editor }); handleInput({ target: editor });
e.preventDefault();
} }
} };
};
editor.addEventListener('keydown', handleDeleteQuote); editor.addEventListener('keydown', handleDeleteQuote);
@ -1062,38 +1039,34 @@ const onSubscribeClear = () => {
// 稿 // 稿
const saveDraft = () => { const saveDraft = () => {
if (!indexName.value) return if (!indexName.value || !editorRef.value) return
// //
let contentToSave = '' // 使DocumentFragmentDOM
let htmlToSave = '' const fragment = document.createDocumentFragment()
const tempDiv = document.createElement('div')
tempDiv.innerHTML = editorRef.value.innerHTML
fragment.appendChild(tempDiv)
if (editorRef.value) { // DOM
// const quoteElements = tempDiv.querySelectorAll('.editor-quote')
const quoteElements = [] quoteElements.forEach(quote => quote.remove())
const editorQuotes = editorRef.value.querySelectorAll('.editor-quote')
//
// const contentToSave = tempDiv.textContent || ''
const clonedEditor = editorRef.value.cloneNode(true) const htmlToSave = tempDiv.innerHTML || ''
//
const clonedQuotes = clonedEditor.querySelectorAll('.editor-quote')
clonedQuotes.forEach(quote => quote.remove())
//
contentToSave = clonedEditor.textContent || ''
htmlToSave = clonedEditor.innerHTML || ''
}
// //
const hasContent = contentToSave.trim() || htmlToSave.includes('<img') || htmlToSave.includes('editor-file') const hasContent = contentToSave.trim().length > 0 ||
htmlToSave.includes('<img') ||
htmlToSave.includes('editor-file')
// 稿
if (hasContent) { if (hasContent) {
// 稿store // 稿store
editorDraftStore.items[indexName.value] = JSON.stringify({ editorDraftStore.items[indexName.value] = JSON.stringify({
content: contentToSave, content: contentToSave,
html: htmlToSave html: htmlToSave
// quoteData稿
}) })
} else { } else {
// 稿 // 稿
@ -1101,80 +1074,80 @@ const saveDraft = () => {
} }
} }
// 稿 // 稿
const loadDraft = () => { const loadDraft = () => {
if (!indexName.value) return if (!indexName.value) return
// DOM // 使nextTickDOM
setTimeout(() => { nextTick(() => {
// //
const currentQuoteData = quoteData.value const currentQuoteData = quoteData.value
// //
quoteData.value = null quoteData.value = null
//
if (!editorRef.value) return
//
editorRef.value.innerHTML = ''
editorContent.value = ''
editorHtml.value = ''
// 稿
const draft = editorDraftStore.items[indexName.value] const draft = editorDraftStore.items[indexName.value]
// 稿稿
if (draft) { if (draft) {
try { try {
const draftData = JSON.parse(draft) const draftData = JSON.parse(draft)
// // 稿
if (editorRef.value) { editorRef.value.innerHTML = draftData.html || ''
// editorContent.value = draftData.content || ''
editorRef.value.innerHTML = '' editorHtml.value = draftData.html || ''
// 稿
editorRef.value.innerHTML = draftData.html || ''
editorContent.value = draftData.content || ''
editorHtml.value = draftData.html || ''
//
if (currentQuoteData) {
//
onSubscribeQuote(currentQuoteData)
}
}
} catch (error) { } catch (error) {
console.error('加载草稿失败:', error) console.warn('加载草稿失败,使用空内容', error)
}
} else {
// 稿
if (editorRef.value) {
//
editorRef.value.innerHTML = ''
editorContent.value = ''
editorHtml.value = ''
//
if (currentQuoteData) {
onSubscribeQuote(currentQuoteData)
}
} }
} }
}, 0)
// 稿
if (currentQuoteData) {
onSubscribeQuote(currentQuoteData)
}
})
} }
// 稿 // 稿
watch(indexName, loadDraft, { immediate: true }) watch(indexName, loadDraft, { immediate: true })
// @
const handleDocumentClick = (event) => {
if (!editorRef.value?.contains(event.target)) {
hideMentionList()
}
}
// //
onMounted(() => { onMounted(() => {
bus.subscribe(EditorConst.Mention, onSubscribeMention) //
bus.subscribe(EditorConst.Quote, onSubscribeQuote) const subscriptions = [
bus.subscribe(EditorConst.Edit, onSubscribeEdit) [EditorConst.Mention, onSubscribeMention],
bus.subscribe(EditorConst.Clear, onSubscribeClear) [EditorConst.Quote, onSubscribeQuote],
[EditorConst.Edit, onSubscribeEdit],
// [EditorConst.Clear, onSubscribeClear]
if (editorRef.value) { ]
editorRef.value.addEventListener('click', handleEditorClick);
}
// mention //
document.addEventListener('click', (event) => { subscriptions.forEach(([event, handler]) => {
if (!editorRef.value?.contains(event.target)) { bus.subscribe(event, handler)
hideMentionList()
}
}) })
//
editorRef.value?.addEventListener('click', handleEditorClick)
// mention - 使便
document.addEventListener('click', handleDocumentClick)
// 稿 // 稿
loadDraft() loadDraft()
@ -1182,24 +1155,27 @@ onMounted(() => {
/** /**
* 组件生命周期钩子 - 组件卸载前 * 组件生命周期钩子 - 组件卸载前
* * 清理所有事件订阅和监听器防止内存泄漏
* onBeforeUnmount是Vue 3的生命周期钩子在组件卸载前执行
* 在这里用于清理事件订阅防止内存泄漏
* 使用bus.unsubscribe取消订阅之前通过bus.subscribe注册的事件处理函数
*/ */
onBeforeUnmount(() => { onBeforeUnmount(() => {
// //
bus.unsubscribe(EditorConst.Mention, onSubscribeMention) const subscriptions = [
bus.unsubscribe(EditorConst.Quote, onSubscribeQuote) [EditorConst.Mention, onSubscribeMention],
bus.unsubscribe(EditorConst.Edit, onSubscribeEdit) [EditorConst.Quote, onSubscribeQuote],
bus.unsubscribe(EditorConst.Clear, onSubscribeClear) [EditorConst.Edit, onSubscribeEdit],
[EditorConst.Clear, onSubscribeClear]
]
//
subscriptions.forEach(([event, handler]) => {
bus.unsubscribe(event, handler)
})
// //
if (editorRef.value) { editorRef.value?.removeEventListener('click', handleEditorClick)
editorRef.value.removeEventListener('click', handleEditorClick);
}
// DOM //
document.removeEventListener('click', handleDocumentClick)
const editor = editorRef.value const editor = editorRef.value
if (editor && handleDeleteQuote) { if (editor && handleDeleteQuote) {
editor.removeEventListener('keydown', handleDeleteQuote) editor.removeEventListener('keydown', handleDeleteQuote)
@ -1729,16 +1705,16 @@ const handleEditorClick = (event) => {
* 限制编辑器中插入的图片大小 * 限制编辑器中插入的图片大小
* 添加圆角和鼠标指针样式 * 添加圆角和鼠标指针样式
*/ */
.editor-image { // .editor-image {
max-width: 300px; // max-width: 300px;
max-height: 200px; // max-height: 200px;
border-radius: 3px; // border-radius: 3px;
background-color: #48484d; // background-color: #48484d;
margin: 0px 2px; // margin: 0px 2px;
cursor: pointer; // cursor: pointer;
object-fit: contain; /* 保持原始比例 */ // object-fit: contain; /* */
display: inline-block; /* 确保图片正确显示 */ // display: inline-block; /* */
} // }
/** /**
* 表情样式 * 表情样式

View File

@ -18,7 +18,7 @@ export function isLoggedIn() {
*/ */
export function getAccessToken() { export function getAccessToken() {
// return storage.get(AccessToken) || '' // return storage.get(AccessToken) || ''
return JSON.parse(localStorage.getItem('token'))||'46d71a72d8d845ad7ed23eba9bdde260e635407190c2ce1bf7fd22088e41682ea07773ec65cae8946d2003f264d55961f96e0fc5da10eb96d3a348c1664e9644ce2108c311309f398ae8ea1b8200bfd490e5cb6e8c52c9e5d493cbabb163368f8351420451a631dbfa749829ee4cda49b77b5ed2d3dced5d0f2b7dd9ee76ba5465c84a17c23af040cd92b6b2a4ea48befbb5c729dcdad0a9c9668befe84074cc24f78899c1d947f8e7f94c7eda5325b8ed698df729e76febb98549ef3482ae942fb4f4a1c92d21836fa784728f0c5483aab2760a991b6b36e6b10c84f840a6433a6ecc31dee36e8f1c6158818bc89d22403363066ad3c046839f7b2cf8a6186da017388f197c0c3b219b1c04e7d986e9774b72664a22a6075cee77da3584b7a2131365913796a5fcabc8f4594284e480a592a84a40a9aa7f5f27c951a53a369c' return JSON.parse(localStorage.getItem('token'))||'46d71a72d8d845ad7ed23eba9bdde260e635407190c2ce1bf7fd22088e41682ea07773ec65cae8946d2003f264d55961f96e0fc5da10eb96d3a348c1664e9644ce2108c311309f398ae8ea1b8200bfd490e5cb6e8c52c9e5d493cbabb163368f8351420451a631dbfa749829ee4cda49b77b5ed2d3dced5d0f2b7dd9ee76ba5465c84a17c23af040cd92b6b2a4ea48befbb5c729dcdad0a9c9668befe84074cc24f78899c1d947f8e7f94c7eda5325b8ed698df729e76febb98549ef3482ae942fb4f4a1c92d21836fa784728f0c5483aab2760a991b6b36e6b10c84f840a6433a6ecc31dee36e8f1c6158818bc89d22c9c2f9b60a57573e8b08cdf47105e1ba85550c21fa55526e8a00bf316c623eb67abf749622c48beab908d61d3db7b22ed3eb6aa8a08c77680ad4d8a3458c1e72f97ba2b8480674df77f0501a34e82b58'
} }
/** /**