You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

cropper.js仅第二次上传调用destroy报removeChild为null错误如何解决

问题原因分析
  • 手动移除DOM未销毁实例:你在裁剪提交逻辑中直接调用$('.cropper-container').remove()删除了Cropper生成的容器节点,但没有调用实例的destroy方法销毁实例,也没有清空原图片元素上的cropper引用。第二次触发初始化时,图片元素上还保留着之前的cropper实例,但实例关联的DOM节点已经被你手动删除,调用destroy方法时要操作不存在的DOM节点就触发了Cannot read property 'removeChild' of null报错。
  • 销毁顺序错误:现有代码中你先清空了图片的src属性,再调用destroy方法,src清空后Cropper相关的关联结构已经被破坏,也会导致destroy执行异常。
  • 事件重复绑定:每次调用initCropper都会给裁剪按钮新增一个点击事件监听,多次初始化后点击一次提交会触发多次上传逻辑;同时每次上传都给图片新增load事件监听,也会导致initCropper被多次调用。
修复方案
  1. 调整销毁逻辑:优先判断图片上是否存在cropper实例,存在的话先调用destroy方法,销毁实例的同时它会自动清理生成的DOM节点,不需要你手动删除。
  2. 移除手动删除.cropper-container的代码,交给destroy方法处理。
  3. 事件绑定前先解绑旧的监听,避免重复绑定。
  4. 用完的Blob URL主动调用URL.revokeObjectURL释放内存。
修复后完整代码
const bannerInput = document.getElementById('id_edit_banner');
const avatarInput = document.getElementById('id_avatar');
// 全局保存cropper实例方便管理
let cropper = null;

function uploadPhoto(uploadElem) {
    let blobUrl = URL.createObjectURL(uploadElem.files[0]);
    const $dragImage = $('#drag-image');
    // 先解绑之前的load事件避免重复触发
    $dragImage.off('load').on('load', (e) => {
        // 用完就释放blobUrl
        URL.revokeObjectURL(blobUrl);
        initCropper();
    }).attr('src', blobUrl);
}

$(document).on('change', '#id_avatar', e => {
    uploadPhoto(avatarInput)
});

function initCropper() {
    var image = document.getElementById('drag-image');

    // 先判断是否有已存在的cropper实例,有就先销毁
    if (cropper) {
        cropper.destroy();
        cropper = null;
    }

    // 初始化新的cropper实例
    cropper = new Cropper(image, {
        aspectRatio: 1 / 1,
    });

    // 先解绑旧的点击事件避免重复绑定
    $('#crop-submit').off('click').on('click', function () {
        $('.update-img-container').addClass('d-none');
        cropper.getCroppedCanvas().toBlob(function (blob) {
            var formData = new FormData();
            formData.append('avatar', blob, 'avatar.jpg');
            formData.append('csrfmiddlewaretoken', $('input[name=csrfmiddlewaretoken]').val());
            $.ajax({
                url: `/update-avatar/`,
                method: "POST",
                data: formData,
                processData: false,
                contentType: false,
                success: function () {
                    // 上传成功后销毁实例
                    if (cropper) {
                        cropper.destroy();
                        cropper = null;
                    }
                },
                error: function () {
                    if (cropper) {
                        cropper.destroy();
                        cropper = null;
                    }
                }
            });
        });
    });
}

内容的提问来源于stack exchange,提问作者user14490044

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.21 15:36:02