perf: 优化裁剪后的图片替换逻辑

This commit is contained in:
zxc
2026-05-17 13:58:16 +08:00
parent 30a1d88a18
commit 4ad7faa1c9
3 changed files with 78 additions and 77 deletions
+72
View File
@@ -0,0 +1,72 @@
import { type Ref } from 'vue'
import { storeToRefs } from 'pinia'
import { useMainStore, useSlidesStore } from '@/store'
import type { PPTImageElement } from '@/types/slides'
import { getImageDataURL, getImageSize } from '@/utils/image'
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
export default () => {
const mainStore = useMainStore()
const slidesStore = useSlidesStore()
const { handleElement, handleElementId } = storeToRefs(mainStore)
const handleImageElement = handleElement as Ref<PPTImageElement>
const { addHistorySnapshot } = useHistorySnapshot()
const replaceImage = (files: FileList) => {
const imageFile = files[0]
const imageElement = handleImageElement.value
const imageElementId = handleElementId.value
if (!imageFile || !imageElement || imageElement.type !== 'image' || !imageElementId) return
getImageDataURL(imageFile).then(dataURL => {
const originWidth = imageElement.width
const originHeight = imageElement.height
const originLeft = imageElement.left
const originTop = imageElement.top
const centerX = originLeft + originWidth / 2
const centerY = originTop + originHeight / 2
getImageSize(dataURL).then(({ width, height }) => {
const h = originHeight
const w = width * (originHeight / height)
const l = centerX - w / 2
const t = centerY - h / 2
const clip = imageElement.clip
if (clip && clip.shape !== 'rect') {
slidesStore.updateElement({
id: imageElementId,
props: {
src: dataURL,
width: w,
height: h,
left: l,
top: t,
clip: {
...clip,
range: [[0, 0], [100, 100]],
},
},
})
}
else {
slidesStore.removeElementProps({
id: imageElementId,
propName: 'clip',
})
slidesStore.updateElement({
id: imageElementId,
props: { src: dataURL, width: w, height: h, left: l, top: t },
})
}
addHistorySnapshot()
})
})
}
return {
replaceImage,
}
}
@@ -14,12 +14,10 @@
</template>
<script lang="ts" setup>
import { type Ref } from 'vue'
import { storeToRefs } from 'pinia'
import { useMainStore, useSlidesStore } from '@/store'
import { useMainStore } from '@/store'
import type { PPTImageElement } from '@/types/slides'
import { getImageDataURL, getImageSize } from '@/utils/image'
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
import useImageHandler from '@/hooks/useImageHandler'
import FileInput from '@/components/FileInput.vue'
@@ -28,49 +26,13 @@ defineProps<{
}>()
const mainStore = useMainStore()
const slidesStore = useSlidesStore()
const { handleElement, handleElementId } = storeToRefs(mainStore)
const handleImageElement = handleElement as Ref<PPTImageElement>
const { addHistorySnapshot } = useHistorySnapshot()
const { handleElementId } = storeToRefs(mainStore)
const { replaceImage } = useImageHandler()
const clipImage = () => {
mainStore.setClipingImageElementId(handleElementId.value)
}
const replaceImage = (files: FileList) => {
const imageFile = files[0]
const imageElement = handleImageElement.value
const imageElementId = handleElementId.value
if (!imageFile || !imageElement || imageElement.type !== 'image' || !imageElementId) return
getImageDataURL(imageFile).then(dataURL => {
const originWidth = imageElement.width
const originHeight = imageElement.height
const originLeft = imageElement.left
const originTop = imageElement.top
const centerX = originLeft + originWidth / 2
const centerY = originTop + originHeight / 2
getImageSize(dataURL).then(({ width, height }) => {
const h = originHeight
const w = width * (originHeight / height)
const l = centerX - w / 2
const t = centerY - h / 2
slidesStore.removeElementProps({
id: imageElementId,
propName: 'clip',
})
slidesStore.updateElement({
id: imageElementId,
props: { src: dataURL, width: w, height: h, left: l, top: t },
})
addHistorySnapshot()
})
})
}
</script>
<style lang="scss" scoped>
@@ -74,8 +74,8 @@ import { storeToRefs } from 'pinia'
import { useMainStore, useSlidesStore } from '@/store'
import type { PPTImageElement, SlideBackground } from '@/types/slides'
import { CLIPPATHS } from '@/configs/imageClip'
import { getImageDataURL, getImageSize } from '@/utils/image'
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
import useImageHandler from '@/hooks/useImageHandler'
import ElementOutline from '../common/ElementOutline.vue'
import ElementShadow from '../common/ElementShadow.vue'
@@ -133,6 +133,7 @@ const handleImageElement = handleElement as Ref<PPTImageElement>
const clipPanelVisible = ref(false)
const { addHistorySnapshot } = useHistorySnapshot()
const { replaceImage } = useImageHandler()
// 打开自由裁剪
const clipImage = () => {
@@ -217,40 +218,6 @@ const presetImageClip = (shape: string, ratio = 0) => {
clipImage()
}
// 替换图片(保持当前的样式)
const replaceImage = (files: FileList) => {
const imageFile = files[0]
const imageElement = handleImageElement.value
const imageElementId = handleElementId.value
if (!imageFile || !imageElement || imageElement.type !== 'image' || !imageElementId) return
getImageDataURL(imageFile).then(dataURL => {
const originWidth = imageElement.width
const originHeight = imageElement.height
const originLeft = imageElement.left
const originTop = imageElement.top
const centerX = originLeft + originWidth / 2
const centerY = originTop + originHeight / 2
getImageSize(dataURL).then(({ width, height }) => {
const h = originHeight
const w = width * (originHeight / height)
const l = centerX - w / 2
const t = centerY - h / 2
slidesStore.removeElementProps({
id: imageElementId,
propName: 'clip',
})
slidesStore.updateElement({
id: imageElementId,
props: { src: dataURL, width: w, height: h, left: l, top: t },
})
addHistorySnapshot()
})
})
}
// 重置图片:清除全部样式
const resetImage = () => {
const _handleElement = handleElement.value as PPTImageElement