简单的图片上传 删除 预览

前言

日常开发表单,经常会遇到图片上传需求。要求:选择图片上传后端、页面实时渲染缩略图、鼠标悬浮显示删除 / 预览按钮、点击放大预览、删除图片。

本篇使用 jQuery + FormData 实现,代码通俗易懂,适合前端新手。

要点:上传文件必须用 FormData,AJAX 需要关闭processDatacontentType

实现效果

  1. input file 选择图片,自动上传接口
  2. 上传成功,页面渲染图片缩略图
  3. 鼠标悬浮图片,淡出预览、删除图标
  4. 点击预览:弹窗放大图片
  5. 点击删除:删掉对应图片,更新视图
  6. 点击遮罩空白处关闭预览弹窗

HTML + CSS 完整结构

复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>图片上传预览删除</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <style>
        /* 多图上传外层 */
        .more_pic_box {
            width: 50%;
            display: flex;
            flex-direction: column;
        }
        /* 图片容器 */
        .img_box {
            width: 100%;
            height: 100px;
            border: 1px solid gray;
            display: flex;
            justify-content: start;
            align-items: center;
            gap: 10px;
        }
        .img_item {
            width: 80px;
            height: 80px;
            position: relative;
        }
        .img_item .img_content {
            width: 100%;
            height: 100%;
        }
        /* hover显示遮罩 */
        .img_item:hover .img_delete_show_box {
            opacity: 1;
        }
        .img_delete_show_box {
            width: 100%;
            height: 100%;
            display: flex;
            justify-content: center;
            align-items: center;
            position: absolute;
            right: 0;
            top: 0;
            z-index: 99;
            opacity: 0;
            transition: all 0.5s;
            background-color: rgba(0, 0, 0, 0.5);
            gap: 10px;
        }
        .img_delete,.img_show {
            width: 25px;
            height: 25px;
            cursor: pointer;
        }
        /* 预览弹窗 */
        .preview_modal {
            display: none;
            position: fixed;
            z-index: 999;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            justify-content: center;
            align-items: center;
            background-color: rgba(0, 0, 0, 0.3);
        }
        .previewImage {
            width: 30%;
        }
    </style>
</head>
<body>
    <!--图片预览弹窗-->
    <div class="preview_modal" onclick="previewCancel()">
        <img class="previewImage" id="previewImage" alt="Preview Image">
    </div>

    <br><br>
    <div class="more_pic_box">
        <input type="file" class="file_up" id="file_four">
        <div class="img_box" id="imgContainer"></div>
    </div>
</body>

JS 核心代码

复制代码
<script>
    //后端上传接口地址
    let url = 'http://yikatong.kuxia.top'
    //保存后端返回图片地址数组
    let pics_url_arr = []

    $(document).ready(function () {
        //页面初始化清空file输入框
        $('#file_four').val('')
    })

    //监听文件选择变化
    $('#file_four').change(function () {
        pics_upload(this)
    })

    /**
     * 图片上传函数
     * @param {DOM} el file dom元素
     */
    function pics_upload(el) {
        //没有选中文件直接返回
        if ($(el)[0].files.length === 0) {
            alert('请选择文件')
            return
        }
        //拿到选中文件对象
        let file_data = $(el)[0].files[0]
        //实例化FormData,专门用来传文件
        let pic_data = new FormData()
        pic_data.append('file', file_data)

        $.ajax({
            url: url + '/pc/common/upload',
            type: 'POST',
            data: pic_data,
            dataType: 'json',
            cache: false,
            processData: false, //文件上传必须关闭,不要处理data为字符串
            contentType: false, //不要自动设置请求头
            success: function (res) {
                if (res.code === 1) {
                    //上传成功,把图片地址存入数组
                    pics_url_arr.push(res.data.fullurl)
                    //渲染图片列表
                    render_pics(pics_url_arr)
                } else {
                    console.log(res.msg)
                }
            },
            error: function () {
                alert('上传失败')
            }
        })
    }

    /**
     * 渲染图片缩略图
     * @param {Array} data 图片url数组
     */
    function render_pics(data) {
        let str = ''
        $('#imgContainer').empty()
        if (data && data.length > 0) {
            //倒序循环,最新上传图片显示在最左边
            for (let i = data.length - 1; i >= 0; i--) {
                str += `
                <div class="img_item">
                    <div class="img_delete_show_box">
                        <img class="img_show" onclick='img_show("${data[i]}")' alt="">
                        <img class="img_delete" onclick='delete_pic(${i})' alt="">
                    </div>
                    <img class='img_content' src="${data[i]}" alt="">
                </div>
                `
            }
            $('#imgContainer').html(str)
        }
    }

    /**
     * 删除图片
     * @param {Number} index 数组下标
     */
    function delete_pic(index) {
        //根据下标删除数组一项
        pics_url_arr.splice(index, 1)
        render_pics(pics_url_arr)
        $('#file_four').val('')
    }

    //图片预览弹窗打开
    function img_show(img_url) {
        $('#previewImage').attr('src', img_url)
        $('.preview_modal').css('display', 'flex')
    }

    //点击遮罩关闭预览,只有点背景才关闭,点图片不关闭
    function previewCancel() {
        if (event.target.className === 'preview_modal') {
            $('.preview_modal').css('display', 'none')
        }
    }
</script>

核心逻辑大白话讲解

1、FormData 上传文件关键点

上传图片不能直接传对象,必须用FormData。 AJAX 两个配置不能忘

  • processData:false:不让 jQuery 把数据转成查询字符串

  • contentType:false:不让 jQuery 自动设置请求头,浏览器会自动带上 multipart/form‑data

    let pic_data = new FormData()
    pic_data.append('file', file_data)
    //file就是后端接口接收文件的字段名,后端要和这个名字对应

2、存储图片地址数组 pics_url_arr

后端上传成功返回图片完整 url,push 进数组。整个页面图片全部维护在这个数组

  • 新增图片:push
  • 删除图片:splice(下标,1)删掉数组对应项
  • 每次改动数组后调用render_pics()重新渲染页面,视图和数组保持同步。

这种思路叫数据驱动视图:不去操作 DOM 增删,修改数组,再重新渲染 HTML。

3、倒序渲染

复制代码
for (let i = data.length - 1; i >= 0; i--)

从数组最后向前循环,最新上传的图片显示在最左侧,符合用户习惯。

4、hover 悬浮遮罩效果

.img_item:hover .img_delete_show_box,鼠标悬浮外层,内部遮罩透明度从 0 变成 1,加transition实现淡入动画。

5、图片预览弹窗

弹窗默认隐藏,点击预览图标赋值图片 src,设置display:flex显示弹窗。

重点:previewCancel()做判断,只有点击外层遮罩背景才关闭弹窗,点击图片本身不会关闭。

踩坑记录

  1. 文件上传 AJAX 不写processData:falsecontentType:false,后端接收不到文件。
  2. input file 选择同一个文件不会触发 change 事件。因为 value 没有变化。
  3. 删除图片后最好重置file input$('#file_four').val('')
  4. 后端返回图片路径一定是完整地址,否则图片无法显示。
  5. onclick 传图片 url,如果路径包含特殊字符容易报错,实际项目可以做转义处理。

总结

整体流程:

  1. input 选择图片触发 change 事件
  2. 获取 file 对象,FormData 封装,ajax 上传后端
  3. 上传成功保存 url 到数组
  4. 根据数组渲染页面缩略图
  5. 删除操作修改数组,重新渲染视图
  6. 预览弹窗实现大图查看
相关推荐
ITresearchGuest20 分钟前
我用 AI 一小时写了一个世界杯数据可视化平台|前端 VibeCoding 初体验
前端·人工智能·信息可视化
慧一居士2 小时前
Vite项目中使用Less步骤,详细使用示例
前端·css
花间相见2 小时前
【LangChain组件03】—— LangChain Agents 执行与状态:工作流程与状态管理实战
java·前端·langchain
kyriewen2 小时前
面试官让我用 AI 重构一个 8 年陈的 React 组件——他说他不看代码,只看我会不会拆
前端·javascript·面试
计算机魔术师2 小时前
700吉瓦「幽灵用电」:美国AI数据中心的抢电闹剧正在失控
前端
IT_陈寒2 小时前
JavaScript数组排序踩的坑,差点让我加班到凌晨
前端·人工智能·后端
风骏时光牛马2 小时前
提示词工程:大模型交互的核心构建艺术
前端
今日无bug3 小时前
大模型的回答是怎么一个字一个字蹦出来的?前端流式输出解析
前端·llm·agent
计算机魔术师3 小时前
Anthropic 复盘 Claude 模型越权访问真实系统事件并改进对齐与安全措施
前端