手写拖动上传组件(Vue3/React)

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"];
}

/**
 * @function React.Component
 * @description 拖动上传文件
 */
export default function DragUpload(props: PropsWithChildren<DragUploadProps>) {
  const { sx = {}, className, accept } = props;
  const [show, setShow] = useState(true);
  //   const [border];

  const onFileChange = (e: ChangeEvent<HTMLInputElement>) => {
    const files = e.target.files;
    handleFile(files);
  };

  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(files);
  };

  const handleFile = (files: FileList) => {
    console.log(files);
    setShow(false);
    Promise.resolve().then(() => {
      setShow(true);
    });
    props.onFileChange(files);
    // setTimeout(() => {
    //   setShow(true);
    // }, 0);
  };

  return (
    <label htmlFor="upload-id">
      {/* @ts-ignore */}
      <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>
  );
}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值