实现图片点击或拖拽上传前预览
对于上传图片并预览的功能实现中,传统的方法中存在一种将图片上传成功并储存后返回一个 url 的方式来预览图片,但是这种方式可能存在问题导致用户体验差,比如网速较慢等,导致无法及时预览😫。
本文通过两种主要的方式,在前端进行处理,实现在图片点击或拖拽上传到服务器前进行预览的功能,避免以上问题。
首先准备一下css与html
这里就不过多赘述了(ps:css现在也支持嵌套等写法了,详细用法请参考CSS Nesting,兼容性请参考 Nesting)

这是我准备的页面
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.wrapper {
margin: 0 auto;
transform: translateX(50%);
display: flex;
img {
width: 200px;
height: 200px;
border-radius: 10px;
background-color: #F6F6F6;
object-fit: fill;
margin-right: 10px;
display: none;
}
label {
input {
opacity: 0;
}
span {
display: inline-block;
user-select: none;
width: 200px;
height: 200px;
border-radius: 15px;
background-color: #F6F6F6;
text-align: center;
line-height: 200px;
}
}
}
</style>
</head>
<body>
<div class="wrapper">
<img src="" alt="">
<label>
<span class="uploadBox">点击或者拖动上传文件</span>
<!--限制一下上传的类型-->
<input type="file" accept=".png,jpg.jpeg,.gif">
</label>
</div>
</body>
</html>
界面展示

获取上传的文件
监听input的change事件直接获取到文件,监听文件在box中拖动以及放下获取到该文件,并阻止默认事件防止文件被打开或者下载。
const fileInput = document.querySelector("input");
const uploadBox = document.querySelector(".uploadBox");
const img = document.querySelector("img")
fileInput.addEventListener("change", (e) => handleFile(e.target.files[0]));
uploadBox.addEventListener("dragover", (e) => {
// 阻止拖动后打开文件
e.preventDefault();
})
uploadBox.addEventListener("drop", (e) => {
// 阻止拖动后打开文件
e.preventDefault();
// DataTransfer 对象用于保存拖动并放下(drag and drop)过程中的数据
handleFile(e.dataTransfer.files[0])
})
function handleFile(file) {
if (!file || !verifyFile(file)) return;
console.log(file)
}
// 简单校验一下文件
function verifyFile(file) {
const fileType = file.name.split(".").pop().toLowerCase();
const validTypes = ["png", "jpg", "jpeg", "gif"];
if (!validTypes.includes(fileType) || file.size > 1024 * 1024 * 10) {
alert("请上传小于10M的 png, jpg,jpeg,gif文件");
return false;
}
return true;
}
界面展示
此时点击或者拖动文件就可以获取该图片了

预览图片
dataUrl方式
........
function handleFile(file) {
if (!file || !verifyFile(file)) return;
createDateUrl(file)
}
........
function createDateUrl(file) {
const fileReader = new FileReader();
// 监听读取完成
fileReader.addEventListener("load",(e) => {
// 生成的dataUrl在这里
displayImg(e.target.result);
})
// 读取文件(所有的IO操作都是异步的)
fileReader.readAsDataURL(file);
}
function displayImg(url) {
console.log(url)
img.src = url;
img.style.display = "block";
}
Data URL,即前缀为 data:
协议的 URL,其允许内容创建者向文档中嵌入小文件
Data URL 由四个部分组成:前缀(data:
)、指示数据类型的 MIME 类型、如果非文本则为可选的 base64
标记、数据本身:
data:[<mediatype>][;base64],<data>
具体可参考dataUrl
界面展示

objectURl实现
........
function handleFile(file) {
if (!file || !verifyFile(file)) return;
createDateUrl(file)
}
........
function createObjectUrl(file) {
const url = URL.createObjectURL(file)
displayImg(url)
}
function displayImg(url) {
console.log(url)
img.src = url;
img.style.display = "block";
}
URL 静态方法创建一个用于表示参数中给出的对象的 URL 的字符串。
URL 的生命周期与其创建时所在窗口的 document 绑定在一起。新对象 URL 代表指定的 File
对象或 Blob
对象。
具体可参考 createObjectUrl
界面展示

两种方式对比
Data URL
优点:生成的 data URL
是文件的一个完整的 Base64 编码的字符串表示,可以直接用于 img
标签的 src
属性或其他需要文件数据的地方。
缺点:转换大文件为 Base64 可能会消耗较多的内存和 CPU 资源,因为需要读取整个文件内容并编码为一个长字符串。对于大文件,这可能导致性能问题。
Object URL
优点:使用 URL.createObjectURL()
创建的对象 URL 仅是一个指向文件的引用,不需要读取和存储文件的全部内容。这使得它处理大文件时更有效,速度更快,资源占用更低。
缺点:生命周期管理。当不再需要这些 URL 时,必须手动调用 URL.revokeObjectURL()
来释放内存。此外,它只能用于浏览器环境,因为它生成的是一个指向本地文件的引用。
全部代码
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.wrapper {
margin: 0 auto;
transform: translateX(50%);
display: flex;
img {
width: 200px;
height: 200px;
border-radius: 10px;
background-color: #F6F6F6;
object-fit: fill;
margin-right: 10px;
display: none;
}
label {
input {
position: absolute;
opacity: 0;
}
span {
display: inline-block;
user-select: none;
width: 200px;
height: 200px;
border-radius: 15px;
background-color: #F6F6F6;
text-align: center;
line-height: 200px;
}
}
}
</style>
</head>
<body>
<div class="wrapper">
<img src="" alt="">
<label>
<span class="uploadBox">点击或者拖动上传文件</span>
<!--限制一下上传的类型-->
<input type="file" accept=".png,jpg.jpeg,.gif">
</label>
</div>
</body>
<script>
const fileInput = document.querySelector("input");
const uploadBox = document.querySelector(".uploadBox");
const img = document.querySelector("img")
fileInput.addEventListener("change", (e) => handleFile(e.target.files[0]));
uploadBox.addEventListener("dragover", (e) => {
// 阻止拖动后打开文件
e.preventDefault();
})
uploadBox.addEventListener("drop", (e) => {
// 阻止拖动后打开文件
e.preventDefault();
// DataTransfer 对象用于保存拖动并放下(drag and drop)过程中的数据
handleFile(e.dataTransfer.files[0])
})
function handleFile(file) {
if (!file || !verifyFile(file)) return;
// createObjectUrl(file)
createDateUrl(file)
}
// 简单校验一下文件
function verifyFile(file) {
const fileType = file.name.split(".").pop().toLowerCase();
const validTypes = ["png", "jpg", "jpeg", "gif"];
if (!validTypes.includes(fileType) || file.size > 1024 * 1024 * 10) {
alert("请上传小于10M的 png, jpg,jpeg,gif文件");
return false;
}
return true;
}
function createDateUrl(file) {
const fileReader = new FileReader();
// 监听读取完成
fileReader.addEventListener("load",(e) => {
// 生成的dataUrl在这里
displayImg(e.target.result);
})
// 读取文件(所有的IO操作都是异步的)
fileReader.readAsDataURL(file);
}
function createObjectUrl(file) {
const url = URL.createObjectURL(file)
displayImg(url)
}
function displayImg(url) {
console.log(url)
img.src = url;
img.style.display = "block";
}
</script>
</html>
总结
本文介绍了两种较为常见的方法,供各位大佬食用😋,有不足的地方欢迎各位大佬指正。
转载自:https://juejin.cn/post/7376527773946200104