Vue3版本
<script setup lang="ts">
import { reactive, nextTick } from "vue";
import { useMainStore } from "../../../store";
const store = useMainStore();
const props = defineProps<{ accept?: string }>();
const emits = defineEmits<{ (e: "fileChange", value: File): void }>();
const data = reactive({
borderColor: "#000",
file: null as File,
show: true,
});
const handleFile = (file: File) => {
console.log(file);
data.file = file;
emits("fileChange", file);
};
const preventDefaultEvent = (e: DragEvent) => {
e.preventDefault();
data.borderColor = "#000";
};
const onDragOver = (e: DragEvent) => {
console.log("OVER", store.themeColor);
e.preventDefault();
data.borderColor = store.themeColor;
};
const onDrop = (e: DragEvent) => {
data.borderColor = "#000";
e.stopPropagation();
e.preventDefault();
const files = e.dataTransfer.files;
const file = files[0];
if (!file) {
return;
}
handleFile(file);
};
const onFileChange = (e: Event) => {
data.show = false;
handleFile((e.target as HTMLInputElement).files[0]);
nextTick(() => {
data.show = true;
});
};
</script>
<template>
<label for="upload-id">
<div
class="upload-container flex"
:style="{ borderColor: data.borderColor }"
@dragleave="preventDefaultEvent"
@dragenter="preventDefaultEvent"
@dragover="onDragOver"
@drop="onDrop"
ref="select_frame"
>
<p>{{ data.file?.name }}</p>
</div>
<input v-if="data.show" @change="onFileChange" :accept="props.accept" style="display: none" type="file" name="" id="upload-id" />
</label>
</template>
<style scoped lang="less">
@import "../../../assets/style/theme.less";
.upload-container {
width: 400px;
height: 200px;
background-color: #eee;
border-radius: 6px;
border: 1px dashed;
}
.upload-container:hover {
border-color: @primary !important;
}
</style>
React版本
import { Box, SxProps, Theme } from "@mui/material";
import { ChangeEvent, InputHTMLAttributes, PropsWithChildren, useState } from "react";
interface DragUploadProps {
onFileChange: (files: FileList) => void;
sx?: SxProps<Theme>;
className?: string;
accept?: InputHTMLAttributes<HTMLInputElement>["accept"];
}
export default function DragUpload(props: PropsWithChildren<DragUploadProps>) {
const { sx = {}, className, accept } = props;
const [show, setShow] = useState(true);
const onFileChange = (e: ChangeEvent<HTMLInputElement>) => {
const files = e.target.files;
handleFile(files);
};
const preventDefaultEvent = (e: DragEvent) => {
e.preventDefault();
};
const onDragOver = (e: DragEvent) => {
console.log("OVER", "store.themeColor");
e.preventDefault();
};
const onDrop = (e: DragEvent) => {
e.stopPropagation();
e.preventDefault();
const files = e.dataTransfer.files;
const file = files[0];
if (!file) {
return;
}
handleFile(files);
};
const handleFile = (files: FileList) => {
console.log(files);
setShow(false);
Promise.resolve().then(() => {
setShow(true);
});
props.onFileChange(files);
};
return (
<label htmlFor="upload-id">
{}
<Box
onDragLeave={preventDefaultEvent}
onDragEnter={preventDefaultEvent}
onDragOver={onDragOver}
onDrop={onDrop}
sx={{ borderRadius: 1.5, border: "1px dashed", ...sx }}
className={"pointer " + className}
>
{props.children}
{show && <input onChange={onFileChange} accept={accept} style={{ display: "none" }} type="file" name="" id="upload-id" />}
</Box>
</label>
);
}