feat: 添加miaoDropHandler組件用於統一處理drop事件,格式化代碼

This commit is contained in:
539943419 committed 2024-08-15 13:05:21 +08:00
1 parent 0c501c800b
commit 2b378b0343
7 files changed
+892 -653

No files matched your search

@@ -1,116 +1,169 @@
<template>
<div class="miao-item" draggable="true" ref="itemRef" @dragstart="handleDragStart">
<div class="item-main">
<div class="item-main-front" :style="{ backgroundColor: props.color }"></div>
<Icon class="item-main-icon"></Icon>
<div class="item-main-info">
<div class="item-main-info-name">
{{ name }}
</div>
<div class="item-main-info-date" v-if="time">
{{ time }}
</div>
</div>
<n-dropdown trigger="click" :options="dropDownOptions" @select="handleDropdownSelect">
<div class="item-main-option" @click="e=>e.stopPropagation()">
<EllipsisVertical class="item-main-option-icon" />
</div>
</n-dropdown>
</div>
</div>
<div
class="miao-item"
draggable="true"
ref="itemRef"
@dragstart="handleDragStart">
<div class="item-main">
<div
class="item-main-front"
:style="{ backgroundColor: props.color }"></div>
<Icon class="item-main-icon"></Icon>
<div class="item-main-info">
<div class="item-main-info-name">
{{ name }}
</div>
<div class="item-main-info-date" v-if="time">
{{ time }}
</div>
</div>
<n-dropdown
trigger="click"
:options="dropDownOptions"
@select="handleDropdownSelect">
<div
class="item-main-option"
@click="(e) => e.stopPropagation()">
<EllipsisVertical class="item-main-option-icon" />
</div>
</n-dropdown>
</div>
</div>
</template>
<script setup lang="ts">
import VirtualDirectory, { VirtualFile } from '@/class/VirtualDirectory'
import {
DocumentText,
FileTray,
Help,
Image,
LogoChrome,
LogoCss3,
LogoJavascript,
LogoVue,
PlayCircle,
EllipsisVertical,
Disc
} from '@vicons/ionicons5'
import { computed, ref } from 'vue'
import dateFormatter from '@/hooks/dateFormatter'
// import useDataBus from '@/hooks/useDataBus'
import { NDropdown } from 'naive-ui'
import VirtualDirectory, { VirtualFile } from '@/class/VirtualDirectory';
import { DocumentText, FileTray, Help, Image, LogoChrome, LogoCss3, LogoJavascript, LogoVue, PlayCircle, EllipsisVertical, Disc } from '@vicons/ionicons5';
import { computed, ref } from 'vue';
import dateFormatter from '@/hooks/dateFormatter';
import useDataBus from '@/hooks/useDataBus';
import { NDropdown } from 'naive-ui';
// const dataBus = useDataBus()
const dataBus = useDataBus()
const props = defineProps<{
item: VirtualDirectory | VirtualFile
name?: string
color: string
}>()
const emit = defineEmits<{
download: []
delete: []
dragStart: []
}>()
const props = defineProps<{
item: VirtualDirectory | VirtualFile
name?: string
color:string
dragStart: [event: DragEvent, item: VirtualDirectory | VirtualFile]
}>()
const itemType = ref<'file' | 'directory'>(props.item.type)
const name = props.name ?? props.item.name
const time = computed(()=>{
return dateFormatter(new Date(props.item.stats.mtimeMs), "yyyy-MM-dd hh:mm:ss");
const time = computed(() => {
return dateFormatter(
new Date(props.item.stats.mtimeMs),
'yyyy-MM-dd hh:mm:ss'
)
})
const dropDownOptions = computed(()=> {
const options = [{
label: '删除',
key: 'delete'
}]
if(itemType.value === 'file'){
options.push(...[
{
label: '下载',
key: 'download',
}
])
const dropDownOptions = computed(() => {
const options = [
{
label: '删除',
key: 'delete'
}
]
if (itemType.value === 'file') {
options.push(
...[
{
label: '下载',
key: 'download'
}
]
)
}
return options
})
const handleDropdownSelect = (key: 'download' | 'delete') => {
if(key === 'download'){
if (key === 'download') {
emit('download')
} else if (key === 'delete') {
emit('delete')
}
}
const Icon = computed(()=>{
try{
if(props.item.type === 'directory') {
const Icon = computed(() => {
try {
if (props.item.type === 'directory') {
return FileTray
} else if(props.item.type === 'file') {
} else if (props.item.type === 'file') {
const aft = props.item.name.split('.').at(-1)?.toLowerCase()
if(!aft){
throw(1)
}else if(['txt', 'doc', 'docs', 'docx', 'xls', 'xlsx'].includes(aft)){
if (!aft) {
throw 1
} else if (
['txt', 'doc', 'docs', 'docx', 'xls', 'xlsx'].includes(aft)
) {
return DocumentText
}else if(['mp3', 'wav', 'ape', 'acc', 'ogg', 'flac'].includes(aft)){
} else if (
['mp3', 'wav', 'ape', 'acc', 'ogg', 'flac'].includes(aft)
) {
return Disc
}else if(['.xbm','.tif','pjp','.svgz','jpg','jpeg','ico','tiff','.gif','svg','.jfif','.webp','.png','.bmp','pjpeg','.avif'].includes(aft)){
} else if (
[
'.xbm',
'.tif',
'pjp',
'.svgz',
'jpg',
'jpeg',
'ico',
'tiff',
'.gif',
'svg',
'.jfif',
'.webp',
'.png',
'.bmp',
'pjpeg',
'.avif'
].includes(aft)
) {
return Image
}else if(['mp4', 'm2v', 'mkv'].includes(aft)){
} else if (['mp4', 'm2v', 'mkv'].includes(aft)) {
return PlayCircle
}else if(['js', 'jsx', 'ts', 'tsx'].includes(aft)){
} else if (['js', 'jsx', 'ts', 'tsx'].includes(aft)) {
return LogoJavascript
}else if(['html'].includes(aft)){
} else if (['html'].includes(aft)) {
return LogoChrome
}else if(['css', 'scss', 'less'].includes(aft)){
} else if (['css', 'scss', 'less'].includes(aft)) {
return LogoCss3
}else if(['vue'].includes(aft)){
} else if (['vue'].includes(aft)) {
return LogoVue
}
return DocumentText
}
}catch{
} catch {
return Help
}
})
const itemRef = ref()
const handleDragStart = () => {
dataBus.set('dragData', [ props.item ])
const handleDragStart = (event: DragEvent) => {
emit('dragStart', event, props.item)
// dataBus.set('dragData', [props.item])
}
</script>
@@ -138,7 +191,7 @@ const handleDragStart = () => {
.item-main-front {
height: 100%;
width: 10px;
border-radius: 7px 0 0 7px ;
border-radius: 7px 0 0 7px;
background-color: rgb(0, 0, 0);
}
.item-main-icon {
@@ -176,17 +229,18 @@ const handleDragStart = () => {
color: #000;
transition: color 0.15s;
}
&:hover, &:active {
&:hover,
&:active {
background-color: #8b8b8b;
.item-main-option-icon {
color: #FFF;
color: #fff;
}
}
}
&:hover, &:active {
&:hover,
&:active {
background-color: #d2d2d2;
}
}
}
</style>
+106
View File
@@ -0,0 +1,106 @@
<template>
<div
class="container"
@dragover="handleDragOver"
@dragleave="handleDragLeave"
@drop="handleDrop">
<slot></slot>
<miao-mask v-model:show="showMask"></miao-mask>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import miaoMask from './miaoMask.vue'
import VirtualDirectory, { VirtualFile } from '@/class/VirtualDirectory'
import config from '@/config'
import useDataBus from '@/hooks/useDataBus'
const dataBus = useDataBus()
const { uploadSizeLimit } = config
const emit = defineEmits<{
onFiles: [files: File[]]
onVirtualFiles: [vFiles: VirtualFile[]]
onVirtualDirectory: [vDirectory: VirtualDirectory[]]
}>()
const showMask = ref<number>(0)
// File類型的數據可能爲文件夾,通過FileReader進行判斷
const isFile = (file: File) =>
new Promise((resolve) => {
const reader = new FileReader()
reader.onload = () => {
resolve(true)
reader.abort()
}
reader.onerror = () => {
resolve(false)
reader.abort()
}
reader.readAsText(file)
})
/**
* 只保留文件,移去文件夹
* @param {File[]} files
*/
const removeDirectory = async (files: File[]) => {
let index = 0
while (index < files.length) {
const currentFile = files[index]
const _isFile = await isFile(currentFile)
if (_isFile) {
index += 1
continue
} else {
files.splice(index, 1)
continue
}
}
}
const handleDragOver = async (event: DragEvent) => {
showMask.value += 1
event.preventDefault()
}
const handleDragLeave = async () => {
showMask.value = 0
}
const handleDrop = async (event: DragEvent) => {
showMask.value = 0
event.preventDefault()
event.stopPropagation()
// todo: uploadSize的限制不應該在這裏
const files = [...(event.dataTransfer?.files ?? [])].filter(
(file) => file.size < uploadSizeLimit
)
await removeDirectory(files)
const virtualFiles: VirtualFile[] = dataBus.pop('dragData_vFiles')
const virtualDirectory: VirtualDirectory[] = dataBus.pop(
'dragData_vDirectory'
)
// console.log({ virtualDirectory, virtualFiles })
if (files && files.length) {
emit('onFiles', files)
}
if (virtualFiles && virtualFiles.length) {
emit('onVirtualFiles', virtualFiles)
}
if (virtualDirectory && virtualDirectory.length) {
emit('onVirtualDirectory', virtualDirectory)
}
}
</script>
<style lang="scss" scoped>
.container {
width: 100%;
height: 100%;
position: relative;
}
</style>
+1 -1
View File
@@ -2,7 +2,7 @@
<transition name="transition">
<div class="mask-body" ref="maskBodyRef" v-show="showMask">
<div @click="e=>e.stopPropagation()">
<slot> {{}} </slot>
<slot></slot>
</div>
</div>
</transition>