Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitdbb57d8

Browse files
committed
perf: 优化复制逻辑
1 parent3b033d0 commitdbb57d8

File tree

5 files changed

+75
-33
lines changed

5 files changed

+75
-33
lines changed

‎src/utils/copy.ts‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
exportfunctioncopyToClip(text:string){
2+
returnnewPromise((resolve,reject)=>{
3+
try{
4+
constinput:HTMLTextAreaElement=document.createElement('textarea')
5+
input.setAttribute('readonly','readonly')
6+
input.value=text
7+
document.body.appendChild(input)
8+
input.select()
9+
if(document.execCommand('copy'))
10+
document.execCommand('copy')
11+
document.body.removeChild(input)
12+
resolve(text)
13+
}
14+
catch(error){
15+
reject(error)
16+
}
17+
})
18+
}

‎src/views/chat/components/Message/Text.vue‎

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
<script lang="ts" setup>
2-
import {computed,ref }from'vue'
2+
import {computed,onMounted,onUnmounted,onUpdated,ref }from'vue'
33
importMarkdownItfrom'markdown-it'
44
importmdKatexfrom'@traptitech/markdown-it-katex'
55
importmilafrom'markdown-it-link-attributes'
66
importhljsfrom'highlight.js'
77
import {useBasicLayout }from'@/hooks/useBasicLayout'
88
import {t }from'@/locales'
9+
import {copyToClip }from'@/utils/copy'
910
1011
interfaceProps {
1112
inversion?:boolean
@@ -22,7 +23,7 @@ const { isMobile } = useBasicLayout()
2223
const textRef=ref<HTMLElement>()
2324
2425
const mdi=newMarkdownIt({
25-
html:true,
26+
html:false,
2627
linkify:true,
2728
highlight(code,language) {
2829
const validLang=!!(language&&hljs.getLanguage(language))
@@ -61,7 +62,45 @@ function highlightBlock(str: string, lang?: string) {
6162
return`<pre class="code-block-wrapper"><div class="code-block-header"><span class="code-block-header__lang">${lang}</span><span class="code-block-header__copy">${t('chat.copyCode')}</span></div><code class="hljs code-block-body ${lang}">${str}</code></pre>`
6263
}
6364
64-
defineExpose({textRef })
65+
function addCopyEvents() {
66+
if (textRef.value) {
67+
const copyBtn=textRef.value.querySelectorAll('.code-block-header__copy')
68+
copyBtn.forEach((btn)=> {
69+
btn.addEventListener('click', ()=> {
70+
const code=btn.parentElement?.nextElementSibling?.textContent
71+
if (code) {
72+
copyToClip(code).then(()=> {
73+
btn.textContent='复制成功'
74+
setTimeout(()=> {
75+
btn.textContent='复制代码'
76+
},1000)
77+
})
78+
}
79+
})
80+
})
81+
}
82+
}
83+
84+
function removeCopyEvents() {
85+
if (textRef.value) {
86+
const copyBtn=textRef.value.querySelectorAll('.code-block-header__copy')
87+
copyBtn.forEach((btn)=> {
88+
btn.removeEventListener('click', ()=> {})
89+
})
90+
}
91+
}
92+
93+
onMounted(()=> {
94+
addCopyEvents()
95+
})
96+
97+
onUpdated(()=> {
98+
addCopyEvents()
99+
})
100+
101+
onUnmounted(()=> {
102+
removeCopyEvents()
103+
})
65104
</script>
66105

67106
<template>

‎src/views/chat/components/Message/index.vue‎

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
<script setup lang='ts'>
22
import {computed,ref }from'vue'
3-
import {NDropdown }from'naive-ui'
3+
import {NDropdown,useMessage }from'naive-ui'
44
importAvatarComponentfrom'./Avatar.vue'
55
importTextComponentfrom'./Text.vue'
66
import {SvgIcon }from'@/components/common'
7-
import {copyText }from'@/utils/format'
87
import {useIconRender }from'@/hooks/useIconRender'
98
import {t }from'@/locales'
109
import {useBasicLayout }from'@/hooks/useBasicLayout'
10+
import {copyToClip }from'@/utils/copy'
1111
1212
interfaceProps {
1313
dateTime?:string
@@ -30,6 +30,8 @@ const { isMobile } = useBasicLayout()
3030
3131
const { iconRender }=useIconRender()
3232
33+
const message=useMessage()
34+
3335
const textRef=ref<HTMLElement>()
3436
3537
const asRawText=ref(props.inversion)
@@ -64,7 +66,7 @@ const options = computed(() => {
6466
function handleSelect(key:'copyText'|'delete'|'toggleRenderType') {
6567
switch (key) {
6668
case'copyText':
67-
copyText({ text:props.text??'' })
69+
handleCopy()
6870
return
6971
case'toggleRenderType':
7072
asRawText.value=!asRawText.value
@@ -78,6 +80,16 @@ function handleRegenerate() {
7880
messageRef.value?.scrollIntoView()
7981
emit('regenerate')
8082
}
83+
84+
asyncfunction handleCopy() {
85+
try {
86+
awaitcopyToClip(props.text||'')
87+
message.success('复制成功')
88+
}
89+
catch {
90+
message.error('复制失败')
91+
}
92+
}
8193
</script>
8294

8395
<template>

‎src/views/chat/hooks/useCopyCode.ts‎

Lines changed: 0 additions & 24 deletions
This file was deleted.

‎src/views/chat/index.vue‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import html2canvas from 'html2canvas'
88
import {Message }from'./components'
99
import {useScroll }from'./hooks/useScroll'
1010
import {useChat }from'./hooks/useChat'
11-
import {useCopyCode }from'./hooks/useCopyCode'
1211
import {useUsingContext }from'./hooks/useUsingContext'
1312
importHeaderComponentfrom'./components/Header/index.vue'
1413
import {HoverButton,SvgIcon }from'@/components/common'
@@ -27,8 +26,6 @@ const ms = useMessage()
2726
2827
const chatStore=useChatStore()
2928
30-
useCopyCode()
31-
3229
const { isMobile }=useBasicLayout()
3330
const { addChat, updateChat, updateChatSome, getChatByUuidAndIndex }=useChat()
3431
const { scrollRef, scrollToBottom, scrollToBottomIfAtBottom }=useScroll()

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp