Skip to content

Commit

Permalink
perf: 优化复制逻辑
Browse files Browse the repository at this point in the history
  • Loading branch information
Chanzhaoyu committed Apr 26, 2023
1 parent 3b033d0 commit dbb57d8
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 33 deletions.
18 changes: 18 additions & 0 deletions src/utils/copy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export function copyToClip(text: string) {
return new Promise((resolve, reject) => {
try {
const input: HTMLTextAreaElement = document.createElement('textarea')
input.setAttribute('readonly', 'readonly')
input.value = text
document.body.appendChild(input)
input.select()
if (document.execCommand('copy'))
document.execCommand('copy')
document.body.removeChild(input)
resolve(text)
}
catch (error) {
reject(error)
}
})
}
45 changes: 42 additions & 3 deletions src/views/chat/components/Message/Text.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
<script lang="ts" setup>
import { computed, ref } from 'vue'
import { computed, onMounted, onUnmounted, onUpdated, ref } from 'vue'
import MarkdownIt from 'markdown-it'
import mdKatex from '@traptitech/markdown-it-katex'
import mila from 'markdown-it-link-attributes'
import hljs from 'highlight.js'
import { useBasicLayout } from '@/hooks/useBasicLayout'
import { t } from '@/locales'
import { copyToClip } from '@/utils/copy'
interface Props {
inversion?: boolean
Expand All @@ -22,7 +23,7 @@ const { isMobile } = useBasicLayout()
const textRef = ref<HTMLElement>()
const mdi = new MarkdownIt({
html: true,
html: false,
linkify: true,
highlight(code, language) {
const validLang = !!(language && hljs.getLanguage(language))
Expand Down Expand Up @@ -61,7 +62,45 @@ function highlightBlock(str: string, lang?: string) {
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>`
}
defineExpose({ textRef })
function addCopyEvents() {
if (textRef.value) {
const copyBtn = textRef.value.querySelectorAll('.code-block-header__copy')
copyBtn.forEach((btn) => {
btn.addEventListener('click', () => {
const code = btn.parentElement?.nextElementSibling?.textContent
if (code) {
copyToClip(code).then(() => {
btn.textContent = '复制成功'
setTimeout(() => {
btn.textContent = '复制代码'
}, 1000)
})
}
})
})
}
}
function removeCopyEvents() {
if (textRef.value) {
const copyBtn = textRef.value.querySelectorAll('.code-block-header__copy')
copyBtn.forEach((btn) => {
btn.removeEventListener('click', () => {})
})
}
}
onMounted(() => {
addCopyEvents()
})
onUpdated(() => {
addCopyEvents()
})
onUnmounted(() => {
removeCopyEvents()
})
</script>

<template>
Expand Down
18 changes: 15 additions & 3 deletions src/views/chat/components/Message/index.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<script setup lang='ts'>
import { computed, ref } from 'vue'
import { NDropdown } from 'naive-ui'
import { NDropdown, useMessage } from 'naive-ui'
import AvatarComponent from './Avatar.vue'
import TextComponent from './Text.vue'
import { SvgIcon } from '@/components/common'
import { copyText } from '@/utils/format'
import { useIconRender } from '@/hooks/useIconRender'
import { t } from '@/locales'
import { useBasicLayout } from '@/hooks/useBasicLayout'
import { copyToClip } from '@/utils/copy'
interface Props {
dateTime?: string
Expand All @@ -30,6 +30,8 @@ const { isMobile } = useBasicLayout()
const { iconRender } = useIconRender()
const message = useMessage()
const textRef = ref<HTMLElement>()
const asRawText = ref(props.inversion)
Expand Down Expand Up @@ -64,7 +66,7 @@ const options = computed(() => {
function handleSelect(key: 'copyText' | 'delete' | 'toggleRenderType') {
switch (key) {
case 'copyText':
copyText({ text: props.text ?? '' })
handleCopy()
return
case 'toggleRenderType':
asRawText.value = !asRawText.value
Expand All @@ -78,6 +80,16 @@ function handleRegenerate() {
messageRef.value?.scrollIntoView()
emit('regenerate')
}
async function handleCopy() {
try {
await copyToClip(props.text || '')
message.success('复制成功')
}
catch {
message.error('复制失败')
}
}
</script>

<template>
Expand Down
24 changes: 0 additions & 24 deletions src/views/chat/hooks/useCopyCode.ts

This file was deleted.

3 changes: 0 additions & 3 deletions src/views/chat/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import html2canvas from 'html2canvas'
import { Message } from './components'
import { useScroll } from './hooks/useScroll'
import { useChat } from './hooks/useChat'
import { useCopyCode } from './hooks/useCopyCode'
import { useUsingContext } from './hooks/useUsingContext'
import HeaderComponent from './components/Header/index.vue'
import { HoverButton, SvgIcon } from '@/components/common'
Expand All @@ -27,8 +26,6 @@ const ms = useMessage()
const chatStore = useChatStore()
useCopyCode()
const { isMobile } = useBasicLayout()
const { addChat, updateChat, updateChatSome, getChatByUuidAndIndex } = useChat()
const { scrollRef, scrollToBottom, scrollToBottomIfAtBottom } = useScroll()
Expand Down

0 comments on commit dbb57d8

Please sign in to comment.