likes
comments
collection
share

实现图片点击或拖拽上传前预览

作者站长头像
站长
· 阅读数 63

对于上传图片并预览的功能实现中,传统的方法中存在一种将图片上传成功并储存后返回一个 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
评论
请登录