JS实现文件点击或者拖拽上传

news2025/4/13 11:11:08

B站看到了渡一大师课的切片,自己实现了一下,做下记录

效果展示

分为上传前、上传中和上传后

实现

分为两步

  1. 界面交互
  2. 网络请求

源码如下

upload.html

<!DOCTYPE html>
<html lang="zh-CN">
	<head>
		<meta charset="UTF-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>图片上传 Demo</title>
		<link rel="stylesheet" href="upload.css" />
	</head>
	<body>
		<h1>图片上传 Demo</h1>
		<div class="upload select">
			<div class="upload-select"><input type="file" accept="image/*" / ></div>
			<div class="upload-progress">
				<div class="upload-progress-bar"></div>
				<div class="upload-progress-text">文件上传中...</div>
				<button>取消</button>
			</div>
			<div class="upload-result">
				<button>删除</button>
				<img src="" alt="" class="preview" />
			</div>
		</div>

		<script src="upload.js"></script>
	</body>
</html>

upload.js

document.addEventListener('DOMContentLoaded', function () {
	const $ = document.querySelector.bind(document);
	const doms = {
		img: $('.preview'),
		container: $('.upload'),
		select: $('.upload-select'),
		selectFile: $('.upload-select input'),
		progress: $('.upload-progress'),
		cancelBtn: $('.upload-progress button'),
		delBtn: $('.upload-result button'),
	};
	// 备用方案,不利用input拖拽,将input设置为none
	// doms.select.ondragenter = function (e) {
	// 	e.preventDefault();
	// };

	// doms.select.ondragover = function (e) {
	// 	e.preventDefault();
	// };

	// doms.select.ondrop = function (e) {
	// 	e.preventDefault();
	// 	const file = e.dataTransfer.files[0];
	// 	if (!validateFile(file)) {
	// 		return;
	// 	}
	// 	doms.selectFile.files = e.dataTransfer.files;
	// 	doms.selectFile.onchange();
	// };

	// 切换三个子界面
	function showArea(areaName) {
		doms.container.className = `upload ${areaName}`;
	}
	// 设置进度
	function setProgress(value) {
		doms.progress.style.setProperty('--progress', value + '%');
	}
	// 取消上传
	let cancelUpload = null;
	function cancel() {
		cancelUpload && cancelUpload(); // 取消网络传输
		showArea('select');
		doms.selectFile.value = '';
	}

	// 上传文件的文件变化
	doms.selectFile.onchange = function () {
		if (this.files.length === 0) {
			return;
		}

		const file = this.files[0];
		console.log(file);
		if (!validateFile(file)) {
			return;
		}
		// 切换界面
		showArea('progress');
		// 显示预览图
		const reader = new FileReader();
		reader.onload = function (e) {
			doms.img.src = e.target.result;
		};
		reader.readAsDataURL(file); // 异步的,结果需要上边的监控拿到
		upload(
			file,
			function (val) {
				setProgress(val);
			},
			function (res) {
				showArea('result');
			},
		);
	};

	// 上传文件
	function upload(file, onProgress, onFinish) {
		const xhr = new XMLHttpRequest();
		xhr.onload = function () {
			const resp = JSON.parse(xhr.responseText);
			onFinish(resp);
		};
		xhr.upload.onprogress = function (e) {
			if (e.lengthComputable) {
				const percent = Math.round((e.loaded / e.total) * 100);
				onProgress(percent);
			}
		};
		xhr.open('POST', '/upload');
		const form = new FormData();
		form.append('avatar', file);
		xhr.send(form);
	}

	// 校验
	function validateFile(file) {
		const maxSize = 1024 * 1024 * 2;
		if (file.size > maxSize) {
			alert('文件大小不能超过2M');
			return false;
		}

		const allowTypes = ['image/jpeg', 'image/png', 'image/gif'];
		if (!allowTypes.includes(file.type)) {
			alert('文件类型只能是jpg、png、gif');
			return false;
		}
		return true;
	}

	doms.cancelBtn.onclick = doms.delBtn.onclick = cancel;
});

upload.css

body {
	font-family: Arial, sans-serif;
	margin: 0;
	padding: 0;
}
.upload {
	width: 400px;
	height: 400px;
	background-color: azure;
}

/* 通过属性控制子组件显示 */
/* 当父元素有 select 类时,只显示上传选择区域 */
.upload.select .upload-select {
	display: flex;
}

.upload.select .upload-progress,
.upload.select .upload-result {
	display: none;
}

/* 当父元素有 progress 类时,只显示进度条 */
.upload.progress .upload-progress {
	display: flex;
}

.upload.progress .upload-select,
.upload.progress .upload-result {
	display: none;
}

/* 当父元素有 result 类时,只显示结果区域 */
.upload.result .upload-result {
	display: flex;
}

.upload.result .upload-select,
.upload.result .upload-progress {
	display: none;
}

.upload-select {
	height: 100%;
	width: 100%;
	display: flex;
	justify-content: center;
	align-items: center;
	position: relative;
	background-image: url(./fileUplaod.svg);
	background-position: center;
	background-repeat: no-repeat;
}

/*  本身就支持拖拽 */
.upload-select input {
	display: block;
	width: 100%;
	height: 100%;
	opacity: 0;
	cursor: pointer;
}

.upload-progress {
	--progress: 0%;
	height: 100%;
	width: 100%;
	display: flex;
	flex-direction: column;
	justify-content: center;
	align-items: center;
}

.upload-progress-bar {
	width: var(--progress);
	height: 10px;
	background-color: #4caf50;
	transition: width 0.3s ease;
}

.upload-result {
	height: 100%;
	width: 100%;
	display: flex;
	flex-direction: column;
	justify-content: center;
}

.preview {
	max-width: 90%;
	max-height: 90%;
	width: auto;
	height: auto;
	/* 以下属性确保图片居中显示 */
	display: block;
	margin: 0 auto;
	/* 保持宽高比 */
	object-fit: contain;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2333773.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Centos7.9 升级内核,安装RTX5880驱动

系统镜像下载 https://vault.centos.org/7.9.2009/isos/x86_64/CentOS-7-x86_64-DVD-2009.iso 系统安装步骤省略 开始安装显卡驱动 远程登录查看内核 [root192 ~]# uname -a Linux 192.168.119.166 3.10.0-1160.el7.x86_64 #1 SMP Mon Oct 19 16:18:59 UTC 2020 x86_64 x8…

Xdocreport实现根据模板导出word

只使用freemaker生成简单的word文档很容易&#xff0c;但是当word文档需要插入动态图片&#xff0c;带循环数据&#xff0c;且含有富文本时解决起来相对比较复杂&#xff0c;但是使用Xdocreport可以轻易解决。 Xdocreport既可以实现文档填充也可以实现文档转换&#xff0c;此处…

当当平台商品详情接口设计与调用指南

当当平台商品详情接口设计与调用指南 接口名称 GET /api/product/detail 图书商品核心信息查询接口 请求参数说明 参数名称 类型 是否必填 说明 isbn string 是 国际标准书号(支持13位/10位) product_id string 否 平台内部商品编号&#xff08;与…

sql server分析表大小

使用自动存储过程查询 EXEC sp_spaceused YourTableName; rows&#xff1a;表中的行数。reserved&#xff1a;表占用的总空间&#xff08;包括数据和索引&#xff09;。data&#xff1a;表数据占用的空间。index_size&#xff1a;索引占用的空间。unused&#xff1a;未使用的空…

《AI大模型应知应会100篇》第13篇:大模型评测标准:如何判断一个模型的优劣

第13篇&#xff1a;大模型评测标准&#xff1a;如何判断一个模型的优劣 摘要 近年来&#xff0c;大语言模型&#xff08;LLMs&#xff09;在自然语言处理、代码生成、多模态任务等领域取得了显著进展。然而&#xff0c;随着模型数量和规模的增长&#xff0c;如何科学评估这些模…

【区块链安全 | 第三十七篇】合约审计之获取私有数据(一)

文章目录 私有数据访问私有数据实例存储槽Solidity 中的数据存储方式1. storage(持久化存储)定长数组变长数组2. memory(临时内存)3. calldata可见性关键字私有数据存储风险安全措施私有数据 私有数据(Private Data)通常指的是只对特定主体可见或可访问的数据,在区块链…

项目管理(高软56)

系列文章目录 项目管理 文章目录 系列文章目录前言一、进度管理二、配置管理三、质量四、风险管理五、真题总结 前言 本节主要讲项目管理知识&#xff0c;这些知识听的有点意思啊。对于技术人想创业&#xff0c;单干的都很有必要听听。 一、进度管理 二、配置管理 三、质量 四…

OpenCV边缘检测方法详解

文章目录 引言一、边缘检测基础概念边缘类型 二、OpenCV中的边缘检测方法1. Sobel算子2. Scharr算子3. Laplacian算子4. Canny边缘检测 三、性能比较与选择建议四、总结 引言 边缘检测是计算机视觉和图像处理中的基础技术&#xff0c;它能有效识别图像中物体的边界&#xff0c…

Linux:shell运行原理+权限

1.shell的运行原理 如果我们打开了命令终端或者是xshell进行远程登录服务器&#xff0c;就会看到命令行&#xff0c;如下图所示&#xff1a; 这个命令行本身也是系统中一个运行起来的程序&#xff0c;它用来接收用户的输入&#xff0c;帮用户来执行指令&#xff0c;将运行结果展…

【LeetCode Solutions】LeetCode 160 ~ 165 题解

CONTENTS LeetCode 160. 相交链表&#xff08;简单&#xff09;LeetCode 162. 寻找峰值&#xff08;中等&#xff09;LeetCode 164. 最大间距&#xff08;中等&#xff09;LeetCode 165. 比较版本号&#xff08;中等&#xff09; LeetCode 160. 相交链表&#xff08;简单&#…

Openssl升级至openssl9.8p1含全部踩坑内容

1、安装依赖包基础条件 yum install gcc yum install gcc-c yum install perl yum install perl-IPC-Cmd yum install pam yum install pam-devel sudo yum install perl-Data-Dumper 问题一&#xff1a;提示yum不可用 镜像源问题更换阿里源即可 wget -O /etc/yum.repos.d/…

二战蓝桥杯所感

&#x1f334; 前言 今天是2025年4月12日&#xff0c;第十六届蓝桥杯结束&#xff0c;作为二战的老手&#xff0c;心中还是颇有不甘的。一方面&#xff0c;今年的题目比去年简单很多&#xff0c;另一方面我感觉并没有把能拿的分都拿到手&#xff0c;这是我觉得最遗憾的地方。不…

查看手机在线状态,保障设备安全运行

手机作为人们日常生活中不可或缺的工具&#xff0c;承载着沟通、工作、娱乐等多种功能。保障手机设备的安全运行是我们每个人都非常重要的任务&#xff0c;而了解手机的在线状态则是其中的一环。通过挖数据平台提供的在线查询工具&#xff0c;我们可以方便快捷地查询手机号的在…

#关于数据库中的时间存储

✅ 一、是否根据“机器当前时区”得到本地时间再转 UTC&#xff1f; 结论&#xff1a;是的&#xff0c;但仅对 TIMESTAMP 字段生效。 数据库&#xff08;如 MySQL&#xff09;在插入 TIMESTAMP 类型数据时&#xff1a; 使用当前会话的时区&#xff08;默认跟随系统时区&#…

第16届蓝桥杯省赛python B组个人题解

文章目录 前言ABCDEFGH 前言 仅个人回忆&#xff0c;不保证正确性 貌似都是典题&#xff0c;针对python的长代码模拟题也没有&#xff0c;一小时速通了&#xff0c;希望不要翻车。 更新&#xff1a;B、G翻车了。。 A 答案&#xff1a;103 B 应该是按长度排序&#xff0c;然后…

lvs+keepalived+dns高可用

1.配置dns相关服务 1.1修改ip地址主机名 dns-master: hostnamectl hostname lvs-master nmcli c modify ens160 ipv4.method manual ipv4.addresses 10.10.10.107/24 ipv4.gateway 10.10.10.2 ipv4.dns 223.5.5.5 connection.autoconnect yes nmcli c up ens160dns-salve: h…

Spark RDD相关概念

Spark运行架构与核心组件 1.Spark运行梁构 spark运行架构包括master和slave两个主要部分。master负责管理整个集群的作业任务调度&#xff0c;而slave则负责实际执行任务。 dirver是Spark驱动器节点&#xff0c;负责执行Spark任务中的main方法&#xff0c;将用户程序转换成作业…

SD + Contronet,扩散模型V1.5+约束条件后续优化:保存Canny边缘图,便于视觉理解——stable diffusion项目学习笔记

目录 前言 背景与需求 代码改进方案 运行过程&#xff1a; 1、Run​编辑 2、过程&#xff1a; 3、过程时间线&#xff1a; 4、最终效果展示&#xff1a; 总结与展望 前言 机器学习缺点之一&#xff1a;即不可解释性。最近&#xff0c;我在使用stable diffusion v1.5 Co…

【ROS2】行为树:BehaviorTree

1、简介 与状态机不同,行为树强调执行动作,而不是状态之间的转换。 行为树是可组合的。可以重复使用简单的行为来构建复杂的行为。 在游戏领域,行为树已经比较流行了。主要用于维护游戏角色的各种动作和状态。 ROS2的导航框架Navigation2中引入了行为树来组织机器人的工作流…

《JVM考古现场(十八):造化玉碟·用字节码重写因果律的九种方法》

"鸿蒙初判&#xff01;当前因果链突破十一维屏障——全体码农修士注意&#xff0c;《JVM考古现场&#xff08;十八&#xff09;》即将渡劫飞升&#xff01;" 目录 上卷阴阳交缠 第一章&#xff1a;混沌初开——JVM因果律的量子纠缠 第二章&#xff1a;诛仙剑阵改—…