refactor(miaoImages): 将图片查看功能提取为独立组件

提取图片查看逻辑到独立的 MiaoImageViewer 组件,提高代码复用性和可维护性
移除原文件中的重复代码,统一处理图片缩放和拖拽功能
This commit is contained in:
539943419 committed 2025-08-23 03:07:39 +08:00
1 parent 79221d37d6
commit c1373de573
2 files changed
+138 -20

No files matched your search

+129
View File
@@ -0,0 +1,129 @@
<template>
<miao-mask :show="show" @click="$emit('close')" class="miaoImage-mask" @wheel="handleWheel">
<ChevronBack class="miaoImage-mask-btn miaoImage-mask-btn-back" @click.stop="$emit('back')" />
<MiaoDraggableDiv
v-if="file"
:is-draggable="isDraggable"
:bind-virtual-files="[file]"
@dragend="handleDragEnd"
@pointerdown="handlePressStart"
@pointerup="handlePressEnd"
@pointercancel="handlePressEnd"
@pointerleave="handlePressEnd"
@touchstart.passive="handleTouchStart"
@touchend="handleTouchEnd"
>
<img :src="file.url" class="miaoImage-mask-active" @click="(e) => e.stopPropagation()" draggable="false" :style="{ transform: `scale(${imgViewScale})` }" />
</MiaoDraggableDiv>
<ChevronForward class="miaoImage-mask-btn miaoImage-mask-btn-forward" @click.stop="$emit('forward')" />
</miao-mask>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
import miaoMask from '@/components/miaoMask.vue'
import MiaoDraggableDiv from '@/components/miaoDraggableDiv.vue'
import { ChevronBack, ChevronForward } from '@vicons/ionicons5'
import type { VirtualFile } from '@/class/VirtualDirectory'
const props = defineProps<{
show: boolean
file?: VirtualFile
}>()
const emit = defineEmits<{
close: []
back: []
forward: []
}>()
const imgViewScale = ref(1)
const isDraggable = ref(false)
let pressTimer: number | undefined
const clearPress = () => {
if (pressTimer !== undefined) {
clearTimeout(pressTimer)
pressTimer = undefined
}
}
const handlePressStart = () => {
clearPress()
pressTimer = window.setTimeout(() => {
isDraggable.value = true
}, 100)
}
const handlePressEnd = () => {
clearPress()
// 延迟复位,避免影响 drop
setTimeout(() => {
isDraggable.value = false
}, 0)
}
const handleTouchStart = () => handlePressStart()
const handleTouchEnd = () => handlePressEnd()
const handleDragEnd = () => {
isDraggable.value = false
}
const handleWheel = (e: WheelEvent) => {
if (e.deltaY < 0) {
imgViewScale.value *= 1.42857
} else {
imgViewScale.value /= 1.42857
}
}
watch(
() => props.file,
() => {
imgViewScale.value = 1
isDraggable.value = false
clearPress()
}
)
watch(
() => props.show,
(v) => {
if (!v) {
imgViewScale.value = 1
isDraggable.value = false
clearPress()
}
}
)
</script>
<style scoped lang="scss">
.miaoImage-mask {
background-color: rgba(0, 0, 0, 0.444);
overflow: hidden;
}
.miaoImage-mask-active {
max-width: 80%;
max-height: 80%;
user-select: none;
}
.miaoImage-mask-btn {
color: #ffffff99;
width: 7%;
position: absolute;
cursor: pointer;
z-index: 9999;
&-back {
left: 1%;
}
&-forward {
right: 1%;
}
}
</style>
+9 -20
View File
@@ -25,28 +25,26 @@
</div> </div>
</div> </div>
</n-scrollbar> </n-scrollbar>
<miao-mask :show="activeImage !== undefined" @click="activeImage = undefined" class="miaoImage-mask" <MiaoImageViewer
@wheel="handleWheel"> :show="activeImage !== undefined"
<ChevronBack class="miaoImage-mask-btn miaoImage-mask-btn-back" @click="handleActiveImageBack" /> :file="activeImage"
<img :src="activeImage?.url" class="miaoImage-mask-active" @click="(e) => e.stopPropagation()" @close="activeImage = undefined"
draggable="false" :style="{ transform: `scale(${imgViewScale})` }" /> @back="handleActiveImageBack"
<ChevronForward class="miaoImage-mask-btn miaoImage-mask-btn-forward" @forward="handleActiveImageForward"
@click="handleActiveImageForward" /> />
</miao-mask>
</div> </div>
</miao-message-provider> </miao-message-provider>
</miao-drop-handler> </miao-drop-handler>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import miaoMask from '@/components/miaoMask.vue'
import miaoDropHandler from '@/components/miaoDropHandler.vue' import miaoDropHandler from '@/components/miaoDropHandler.vue'
import miaoMessageProvider from '@/components/miaoAlertTipProvider.vue' import miaoMessageProvider from '@/components/miaoAlertTipProvider.vue'
import VirtualDirectory, { VirtualFile } from '@/class/VirtualDirectory' import VirtualDirectory, { VirtualFile } from '@/class/VirtualDirectory'
import uniq from 'lodash/uniq' import uniq from 'lodash/uniq'
import { computed, nextTick, onMounted, ref, watch } from 'vue' import { computed, nextTick, onMounted, ref, watch } from 'vue'
import { NScrollbar } from 'naive-ui' import { NScrollbar } from 'naive-ui'
import { ChevronBack, ChevronForward } from '@vicons/ionicons5' import MiaoImageViewer from './miaoImageViewer.vue'
const imageSuffixList = [ const imageSuffixList = [
'xbm', 'xbm',
@@ -80,7 +78,6 @@ const currentFiles = defineModel<VirtualFile[]>('currentFiles', {
const NScrollbarRef = ref() const NScrollbarRef = ref()
const rootRef = ref<any>() const rootRef = ref<any>()
const miaoMessageRef = ref<InstanceType<typeof miaoMessageProvider>>() const miaoMessageRef = ref<InstanceType<typeof miaoMessageProvider>>()
const imgViewScale = ref(1)
const imageFileList = ref<VirtualFile[]>([]) const imageFileList = ref<VirtualFile[]>([])
const activeImage = ref<VirtualFile>() const activeImage = ref<VirtualFile>()
@@ -90,7 +87,6 @@ const imageGroupList = computed(() => {
watch(activeImage, () => { watch(activeImage, () => {
nextTick(scrollToActiveImage) nextTick(scrollToActiveImage)
imgViewScale.value = 1
}) })
const groupByDay = (array: VirtualFile[]) => { const groupByDay = (array: VirtualFile[]) => {
@@ -210,14 +206,6 @@ const updateImageSrcList = async (source: VirtualFile[] | VirtualDirectory) => {
) )
} }
const handleWheel = (e: WheelEvent) => {
if (e.deltaY < 0) {
imgViewScale.value *= 1.42857
} else {
imgViewScale.value /= 1.42857
}
}
onMounted(async () => { onMounted(async () => {
const length_before = imageFileList.value.length const length_before = imageFileList.value.length
for (const i of [currentFiles.value, ...currentDirectories.value]) { for (const i of [currentFiles.value, ...currentDirectories.value]) {
@@ -329,6 +317,7 @@ onMounted(async () => {
width: 7%; width: 7%;
position: absolute; position: absolute;
cursor: pointer; cursor: pointer;
z-index: 9999;
&-back { &-back {
left: 1%; left: 1%;