位置: 文档库 > JavaScript > JS和Canvas实现图片的预览压缩和上传功能

JS和Canvas实现图片的预览压缩和上传功能

DivineDragon 上传于 2022-04-11 03:22

YPE html>

《JS和Canvas实现图片的预览压缩和上传功能》

在Web开发中,图片处理是常见的需求场景,尤其是移动端或表单提交类应用中,用户上传图片前往往需要预览、压缩以优化性能。传统方案依赖后端处理,但前端通过JavaScript结合Canvas API,可实现完整的图片预览、压缩和上传功能,减少服务器压力并提升用户体验。本文将详细阐述如何利用原生JS和Canvas实现这一流程,涵盖从文件选择、预览生成、压缩处理到最终上传的全过程。

一、基础准备:HTML结构与文件选择

实现图片处理的第一步是构建一个简单的HTML界面,包含文件选择输入框和预览区域。以下是一个基础示例:


    
    图片预览压缩上传
    


    
预览图

关键点说明:

  • input type="file" 设置 accept="image/*" 限制用户只能选择图片文件。
  • 预览区域使用 img 标签,初始为空,后续通过JS动态填充。
  • 上传按钮初始禁用,待图片处理完成后启用。

二、图片预览:FileReader与临时URL

当用户选择文件后,需立即显示预览图。这可通过 FileReader API读取文件内容,生成Data URL并赋值给 imgsrc 属性实现。

document.getElementById('fileInput').addEventListener('change', function(e) {
    const file = e.target.files[0];
    if (!file) return;

    const reader = new FileReader();
    reader.onload = function(event) {
        const previewImg = document.getElementById('preview');
        previewImg.src = event.target.result;
        // 启用上传按钮
        document.getElementById('uploadBtn').disabled = false;
    };
    reader.readAsDataURL(file);
});

流程解析:

  1. 监听 change 事件获取用户选择的文件。
  2. 创建 FileReader 实例,通过 readAsDataURL 方法读取文件。
  3. onload 回调中,将生成的Data URL(如 data:image/jpeg;base64,...)赋给预览图。
  4. 预览成功后启用上传按钮。

三、图片压缩:Canvas的缩放与质量调整

直接上传原图可能导致文件过大,影响加载速度。通过Canvas可对图片进行压缩,核心步骤包括:

  1. 创建 Image 对象加载预览图。
  2. 根据目标尺寸计算缩放比例。
  3. 使用Canvas绘制缩放后的图片,并通过 toDataURL 输出压缩后的Data URL。
function compressImage(file, maxWidth, maxHeight, quality, callback) {
    const reader = new FileReader();
    reader.onload = function(event) {
        const img = new Image();
        img.onload = function() {
            // 计算缩放比例
            let width = img.width;
            let height = img.height;
            if (width > maxWidth) {
                height = (maxWidth / width) * height;
                width = maxWidth;
            }
            if (height > maxHeight) {
                width = (maxHeight / height) * width;
                height = maxHeight;
            }

            // 创建Canvas并绘制缩放后的图片
            const canvas = document.createElement('canvas');
            canvas.width = width;
            canvas.height = height;
            const ctx = canvas.getContext('2d');
            ctx.drawImage(img, 0, 0, width, height);

            // 输出压缩后的Data URL
            const compressedDataUrl = canvas.toDataURL('image/jpeg', quality);
            callback(compressedDataUrl);
        };
        img.src = event.target.result;
    };
    reader.readAsDataURL(file);
}

参数说明:

  • maxWidth/maxHeight:限制图片的最大宽高。
  • quality:JPEG压缩质量(0-1),值越低文件越小但画质越差。
  • callback:压缩完成后回调,返回压缩后的Data URL。

调用示例:

document.getElementById('fileInput').addEventListener('change', function(e) {
    const file = e.target.files[0];
    compressImage(file, 800, 800, 0.7, function(compressedDataUrl) {
        document.getElementById('preview').src = compressedDataUrl;
        // 此处可存储compressedDataUrl用于上传
    });
});

四、图片上传:FormData与AJAX请求

压缩后的图片需上传至服务器。传统方式是将Data URL转为Blob对象,再通过 FormData 发送。以下是完整实现:

function dataURLtoBlob(dataUrl) {
    const arr = dataUrl.split(',');
    const mime = arr[0].match(/:(.*?);/)[1];
    const bstr = atob(arr[1]);
    let n = bstr.length;
    const u8arr = new Uint8Array(n);
    while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
    }
    return new Blob([u8arr], { type: mime });
}

document.getElementById('uploadBtn').addEventListener('click', function() {
    const previewImg = document.getElementById('preview');
    if (!previewImg.src) return;

    // 将Data URL转为Blob
    const blob = dataURLtoBlob(previewImg.src);

    // 创建FormData并添加文件
    const formData = new FormData();
    formData.append('image', blob, 'compressed.jpg');

    // 发送AJAX请求
    const xhr = new XMLHttpRequest();
    xhr.open('POST', '/upload', true);
    xhr.onload = function() {
        if (xhr.status === 200) {
            alert('上传成功!');
        } else {
            alert('上传失败:' + xhr.statusText);
        }
    };
    xhr.send(formData);
});

关键点:

  • dataURLtoBlob 函数将Data URL解析为Blob对象,便于上传。
  • FormData 用于构建表单数据,模拟文件上传。
  • 通过 XMLHttpRequest 发送POST请求,服务器端需处理 multipart/form-data 格式。

五、完整流程整合

将预览、压缩、上传整合为一个完整功能,代码如下:

// script.js
document.addEventListener('DOMContentLoaded', function() {
    const fileInput = document.getElementById('fileInput');
    const previewImg = document.getElementById('preview');
    const uploadBtn = document.getElementById('uploadBtn');

    fileInput.addEventListener('change', handleFileSelect);
    uploadBtn.addEventListener('click', handleUpload);

    function handleFileSelect(e) {
        const file = e.target.files[0];
        if (!file) return;

        // 显示原始预览
        const reader = new FileReader();
        reader.onload = function(event) {
            previewImg.src = event.target.result;
        };
        reader.readAsDataURL(file);

        // 压缩图片并更新预览
        compressImage(file, 800, 800, 0.7, function(compressedDataUrl) {
            // 此处可存储compressedDataUrl供后续上传使用
            // 为简化示例,直接更新预览图
            previewImg.src = compressedDataUrl;
        });

        uploadBtn.disabled = false;
    }

    function compressImage(file, maxWidth, maxHeight, quality, callback) {
        const reader = new FileReader();
        reader.onload = function(event) {
            const img = new Image();
            img.onload = function() {
                let width = img.width;
                let height = img.height;
                if (width > maxWidth) {
                    height = (maxWidth / width) * height;
                    width = maxWidth;
                }
                if (height > maxHeight) {
                    width = (maxHeight / height) * width;
                    height = maxHeight;
                }

                const canvas = document.createElement('canvas');
                canvas.width = width;
                canvas.height = height;
                const ctx = canvas.getContext('2d');
                ctx.drawImage(img, 0, 0, width, height);

                const compressedDataUrl = canvas.toDataURL('image/jpeg', quality);
                callback(compressedDataUrl);
            };
            img.src = event.target.result;
        };
        reader.readAsDataURL(file);
    }

    function dataURLtoBlob(dataUrl) {
        const arr = dataUrl.split(',');
        const mime = arr[0].match(/:(.*?);/)[1];
        const bstr = atob(arr[1]);
        let n = bstr.length;
        const u8arr = new Uint8Array(n);
        while (n--) {
            u8arr[n] = bstr.charCodeAt(n);
        }
        return new Blob([u8arr], { type: mime });
    }

    function handleUpload() {
        if (!previewImg.src) return;

        const blob = dataURLtoBlob(previewImg.src);
        const formData = new FormData();
        formData.append('image', blob, 'compressed.jpg');

        const xhr = new XMLHttpRequest();
        xhr.open('POST', '/upload', true);
        xhr.onload = function() {
            if (xhr.status === 200) {
                alert('上传成功!');
            } else {
                alert('上传失败:' + xhr.statusText);
            }
        };
        xhr.send(formData);
    }
});

六、优化与扩展

1. 多图片处理:通过循环处理多个文件,动态生成预览图和上传按钮。

2. 进度显示:使用 xhr.upload.onprogress 显示上传进度。

xhr.upload.onprogress = function(e) {
    if (e.lengthComputable) {
        const percent = Math.round((e.loaded / e.total) * 100);
        console.log('上传进度:' + percent + '%');
    }
};

3. 移动端适配:添加触摸事件支持,优化小屏幕显示。

4. 错误处理:捕获文件读取、图片加载、网络请求等环节的异常。

七、总结

本文通过原生JS和Canvas API实现了图片的预览、压缩和上传功能,核心步骤包括:

  1. 使用 FileReader 读取文件并预览。
  2. 通过Canvas动态缩放图片并调整质量。
  3. 将Data URL转为Blob,利用 FormData 上传。

该方案完全在前端完成图片处理,减轻服务器负担,适用于需要快速响应的场景。开发者可根据实际需求调整压缩参数、支持更多图片格式或集成到现有框架中。

关键词:JavaScript、Canvas、图片预览、图片压缩、文件上传、FileReader、FormData、AJAX

简介:本文详细介绍了如何使用JavaScript和Canvas API实现图片的预览、压缩和上传功能。从HTML结构搭建、文件选择与预览、Canvas压缩处理到最终上传,覆盖了完整流程,并提供了代码示例和优化建议,适合前端开发者参考。

《JS和Canvas实现图片的预览压缩和上传功能.doc》
将本文的Word文档下载到电脑,方便收藏和打印
推荐度:
点击下载文档