feat: 1.优化了miaoDirectory中多选的性能表现。2.图片浏览组件新增拖入虚拟文件/文件夹相关处理
This commit is contained in:
1 parent
704c80e019
commit
7574acdad2
3 files changed
+102
-37
No files matched your search
@@ -1,3 +1,5 @@
|
||||
<!-- 只适合用于渲染过程较为复杂的组件,不然可能得不偿失
|
||||
这么泛用的组件,性能差点也能理解 -->
|
||||
<template>
|
||||
<div class="miao-lazy" ref="miaoLazyRoot" :style="!show ? { minHeight, minWidth } : {}">
|
||||
<slot v-if="show" />
|
||||
@@ -5,13 +7,14 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { onBeforeUnmount, onMounted, ref } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
show: {
|
||||
disableLazy: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 仅在内容未加载时生效,用于占位
|
||||
minHeight: {
|
||||
type: String,
|
||||
default: 'none',
|
||||
@@ -24,26 +27,69 @@ const props = defineProps({
|
||||
|
||||
const miaoLazyRoot = ref<HTMLDivElement>()
|
||||
|
||||
const show = ref<boolean>(props.show === true)
|
||||
const show = ref<boolean>(props.disableLazy)
|
||||
|
||||
const isVisible = (dom: HTMLDivElement) => {
|
||||
const offset = dom.getBoundingClientRect().top
|
||||
return offset > 0 && offset < 2000
|
||||
}
|
||||
|
||||
const { showSlot, hideSlot, clearTimer } = (() => {
|
||||
let timer: any
|
||||
let timerInterval: any
|
||||
const clearTimer = () => {
|
||||
timer && clearTimeout(timer)
|
||||
timerInterval && clearInterval(timerInterval)
|
||||
timer = undefined
|
||||
timerInterval = undefined
|
||||
}
|
||||
const hideSlot = () => {
|
||||
clearTimer()
|
||||
show.value = false
|
||||
}
|
||||
const showSlot = () => {
|
||||
if (show.value === true) {
|
||||
return
|
||||
}
|
||||
clearTimer()
|
||||
// timer = setTimeout(() => {
|
||||
if (!miaoLazyRoot.value || isVisible(miaoLazyRoot.value) === false) {
|
||||
return
|
||||
}
|
||||
show.value = true
|
||||
timerInterval = setInterval(() => {
|
||||
if (show.value === false || miaoLazyRoot.value === undefined) {
|
||||
return
|
||||
}
|
||||
if (isVisible(miaoLazyRoot.value) === false) {
|
||||
hideSlot()
|
||||
}
|
||||
}, 1000)
|
||||
// })
|
||||
}
|
||||
return { showSlot, hideSlot, clearTimer }
|
||||
})()
|
||||
|
||||
onMounted(() => {
|
||||
if (show.value === false) {
|
||||
let options = {
|
||||
root: null, // 默认为视窗
|
||||
rootMargin: '0px', // 视窗的外边距
|
||||
threshold: 0.1 // 目标元素可见比例达到 10% 时触发回调
|
||||
threshold: 0
|
||||
};
|
||||
|
||||
let observer: IntersectionObserver | undefined = new IntersectionObserver((entries) => {
|
||||
if (entries[0].isIntersecting) {
|
||||
show.value = true
|
||||
showSlot()
|
||||
// miaoLazyRoot.value && observer?.unobserve(miaoLazyRoot.value)
|
||||
// observer = undefined
|
||||
} else {
|
||||
show.value = false
|
||||
hideSlot()
|
||||
}
|
||||
}, options);
|
||||
miaoLazyRoot.value && observer.observe(miaoLazyRoot.value);
|
||||
}
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
clearTimer()
|
||||
})
|
||||
</script>
|
||||
+14
-11
@@ -42,8 +42,8 @@
|
||||
}">
|
||||
<n-scrollbar ref="scrollbarRef">
|
||||
<transition-group name="dirItem">
|
||||
<miao-lazy-div v-for="(dir, index) in showData_directory" :key="dir.uid" :show="index < 20"
|
||||
min-height="50px">
|
||||
<miao-lazy-div v-for="(dir, index) in showData_directory" :key="dir.uid"
|
||||
:disableLazy="index < 20" min-height="50px">
|
||||
<miaoDirectoryItem :item="dir" :color="props.color" :selectedItem="selectedItem.value"
|
||||
@delete="handleItemDelete(dir)" @click="handleItemClick(dir)"
|
||||
@drag-start="handleItemDragStart" @rename="handleItemRename(dir)"
|
||||
@@ -51,7 +51,7 @@
|
||||
</miao-lazy-div>
|
||||
</transition-group>
|
||||
<transition-group name="dirItem">
|
||||
<miao-lazy-div v-for="(file, index) in showData_files" :key="file.uid" :show="index < 20"
|
||||
<miao-lazy-div v-for="(file, index) in showData_files" :key="file.uid" :disableLazy="index < 20"
|
||||
min-height="50px">
|
||||
<miaoDirectoryItem :item="file" :color="props.color" :selectedItem="selectedItem.value"
|
||||
@click="handleItemClick(file)" @download="handleItemDownload(file)"
|
||||
@@ -158,12 +158,13 @@ class SelectedItem {
|
||||
}
|
||||
// 保证内容仍然存在于dir中且各个元素不重复
|
||||
get value() {
|
||||
const _filterList = [...(currentDirectory.value?.directories ?? []), ...(currentDirectory.value?.files ?? [])]
|
||||
return uniq(this._selectedItem).filter(v => {
|
||||
if (currentDirectory.value === undefined) {
|
||||
return false
|
||||
}
|
||||
// @ts-ignore
|
||||
return [...currentDirectory.value?.directories, ...currentDirectory.value?.files].includes(v)
|
||||
return _filterList.includes(v)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -221,14 +222,16 @@ const setCurrentDirectory = async (virtualDirectory: VirtualDirectory) => {
|
||||
} else {
|
||||
virtualDirectory.update()
|
||||
}
|
||||
currentDirectories.value[0] !== virtualDirectory && selectedItem.clear()
|
||||
currentDirectories.value[0] = virtualDirectory
|
||||
nextTick(() => {
|
||||
scrollbarRef.value.scrollTo({
|
||||
top: 0,
|
||||
behavior: "instant"
|
||||
if (currentDirectories.value[0] !== virtualDirectory) {
|
||||
selectedItem.clear()
|
||||
nextTick(() => {
|
||||
scrollbarRef.value.scrollTo({
|
||||
top: 0,
|
||||
behavior: "instant"
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
currentDirectories.value[0] = virtualDirectory
|
||||
}
|
||||
|
||||
const reload = () => {
|
||||
|
||||
+34
-18
@@ -1,30 +1,33 @@
|
||||
<template>
|
||||
<div class="miaoImage" ref="rootRef">
|
||||
<n-scrollbar ref="NScrollbarRef">
|
||||
<div class="miaoImage-container">
|
||||
<div class="miaoImage-container-row" v-for="(src, index) in imageSrcList" :key="index">
|
||||
<img :src="src" class="miaoImage-container-row-image" loading="lazy"
|
||||
:class="activeImageIndex === index ? 'miaoImage-container-row-image-active' : ''"
|
||||
@click="activeImageIndex = index" draggable="false" />
|
||||
<miao-drop-handler @on-virtual-directory="handleDrop" @on-virtual-files="handleDrop">
|
||||
<div class="miaoImage" ref="rootRef">
|
||||
<n-scrollbar ref="NScrollbarRef">
|
||||
<div class="miaoImage-container">
|
||||
<div class="miaoImage-container-row" v-for="(src, index) in imageSrcList" :key="index">
|
||||
<img :src="src" class="miaoImage-container-row-image" loading="lazy"
|
||||
:class="activeImageIndex === index ? 'miaoImage-container-row-image-active' : ''"
|
||||
@click="activeImageIndex = index" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</n-scrollbar>
|
||||
<miao-mask :show="activeImageIndex !== -1" @click="activeImageIndex = -1" class="miaoImage-mask">
|
||||
<ChevronBack class="miaoImage-mask-btn miaoImage-mask-btn-back" @click="handleActiveImageIndexBack" />
|
||||
<img :src="imageSrcList[activeImageIndex]" class="miaoImage-mask-active" @click="e => e.stopPropagation()"
|
||||
draggable="false">
|
||||
<ChevronForward class="miaoImage-mask-btn miaoImage-mask-btn-forward"
|
||||
@click="handleActiveImageIndexForward" />
|
||||
</miao-mask>
|
||||
</div>
|
||||
</n-scrollbar>
|
||||
<miao-mask :show="activeImageIndex !== -1" @click="activeImageIndex = -1" class="miaoImage-mask">
|
||||
<ChevronBack class="miaoImage-mask-btn miaoImage-mask-btn-back" @click="handleActiveImageIndexBack" />
|
||||
<img :src="imageSrcList[activeImageIndex]" class="miaoImage-mask-active"
|
||||
@click="e => e.stopPropagation()" draggable="false">
|
||||
<ChevronForward class="miaoImage-mask-btn miaoImage-mask-btn-forward"
|
||||
@click="handleActiveImageIndexForward" />
|
||||
</miao-mask>
|
||||
</div>
|
||||
</miao-drop-handler>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import miaoMask from '@/components/miaoMask.vue';
|
||||
import miaoDropHandler from '@/components/miaoDropHandler.vue';
|
||||
import VirtualDirectory, { VirtualFile } from '@/class/VirtualDirectory'
|
||||
import { uniq } from 'lodash';
|
||||
import { nextTick, onMounted, ref } from 'vue'
|
||||
import { NScrollbar } from 'naive-ui';
|
||||
import miaoMask from '@/components/miaoMask.vue';
|
||||
import { ChevronBack, ChevronForward } from '@vicons/ionicons5'
|
||||
|
||||
const imageSuffixList = [
|
||||
@@ -82,6 +85,19 @@ const handleActiveImageIndexForward = (e: any) => {
|
||||
nextTick(scrollToActiveImage)
|
||||
}
|
||||
|
||||
const handleDrop = (vItems: (VirtualFile | VirtualDirectory)[]) => {
|
||||
if (vItems[0].type === 'directory') {
|
||||
// @ts-ignore
|
||||
currentDirectories.value = [...currentDirectories.value, ...vItems]
|
||||
} else {
|
||||
// @ts-ignore
|
||||
currentFiles.value = [...currentFiles, ...vItems]
|
||||
}
|
||||
vItems.forEach(v => {
|
||||
updateImageSrcList(v)
|
||||
})
|
||||
}
|
||||
|
||||
const updateImageSrcList = async (source: VirtualFile | VirtualDirectory) => {
|
||||
let srcList: string[]
|
||||
if (source.type === 'directory') {
|
||||
|
||||
Reference in new issue
Block a user