为什么 Cropper.js 在 Bootstraps 嵌套模型中使用时第二次尝试返回 null?

问题描述 投票:0回答:1

我想做以下事情:

  1. 弹出一个按钮
    firstModal
    ,其中包含提交表格。
  2. 在此表格中,有一个文档上传输入,有两个选项,第一个是正常输入文件上传,第二个是屏幕截图粘贴选项。
  3. 如果选择第二个选项,则捕获通过 CTRL+V 粘贴的剪贴板图像,并弹出
    secondModal
    并启动裁剪器以允许用户裁剪剪贴板粘贴图像的特定区域。
  4. 当用户单击裁剪按钮时,它应该将裁剪后的图像传输到输入文件(准备好表单提交)并显示小预览。

这个问题有一些相似之处,但它没有提供确切的工作答案:CropperJS getCroppedCanvas()在第二次初始化时返回 null

下面是我现在所在的 html 和 js 代码。似乎第一次尝试工作正常,但是当我关闭模态并重复该过程时,

getCroppedCanvas
返回 null,这可能是什么原因? 替代 JsFiddle:https://jsfiddle.net/51sL06w9/1/

function checkFileUpload() {
  var is_file = $("#isFile").is(":checked");
  var is_ss = $("#isSS").is(":checked");
  if (is_ss) {
    $("#inputSS").prop("disabled", false);
    $("#inputFile").prop("disabled", true);
  } else {
    $("#inputFile").prop("disabled", false);
    $("#inputSS").prop("disabled", true);
    document.getElementById("cropped-image").style.display = "none";
  }
}
checkFileUpload();
$(document).on("click", "#isFile,#isSS", function(e) {
  checkFileUpload();
});
const inputSS = document.getElementById("inputSS");
$(document).off("paste").on("paste", function(e) {
  var clipboardData = e.clipboardData || window.clipboardData || e.originalEvent.clipboardData;
  if ($("#isSS").is(":checked")) {
    inputSS.files = clipboardData.files;
    console.log("isSS checked and paste captured");
    var $modal = $("#secondModal");
    var cropper;
    var image = document.querySelector("#cropper-image");
    var files = inputSS.files;
    var done = function(url) {
      inputSS.value = "";
      image.src = url;
      $modal.modal("show");
    };
    var reader;
    var file;
    var url;
    if (files && files.length > 0) {
      file = files[0];
      if (URL) {
        done(URL.createObjectURL(file));
      } else if (FileReader) {
        reader = new FileReader();
        reader.onload = function(e) {
          done(reader.result);
        };
        reader.readAsDataURL(file);
      }
    }
    $modal.on("shown.bs.modal", function() {
      cropper = new Cropper(image, {
        viewMode: 3,
      });
    }).on("hidden.bs.modal", function() {
      cropper.destroy();
      cropper = null;
    });
    $("#crop").on("click", function() {
      var canvas;
      console.log(cropper);
      if (cropper) {
        canvas = cropper.getCroppedCanvas({
          width: 400,
          height: 400,
        });
        console.log(canvas);
        var resultImage = document.getElementById("cropped-image");
        resultImage.src = canvas.toDataURL();
        resultImage.style.display = "block";
        canvas.toBlob(blob => {
          const croppedFile = new File([blob], "croppedScreenShot.png");
          const dT = new DataTransfer();
          dT.items.add(croppedFile);
          inputSS.files = dT.files;
        });
      }
      $modal.modal("hide");
    });
  }
});
$("#firstModal").on("hidden.bs.modal", function() {
      document.getElementById("submitForm").reset();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://fengyuanchen.github.io/cropperjs/js/cropper.js"></script>
<link href="https://fengyuanchen.github.io/cropperjs/css/cropper.css" rel="stylesheet"/>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet"/>
<button type="button" class="btn btn-warning" data-toggle="modal" data-target="#firstModal">Update</button>
<div id="firstModal" class="modal" tabindex="-1" role="dialog">
  <form id="submitForm">
    <div class="modal-dialog" role="document">
      <div class="modal-content">
        <div class="modal-header">
          <h5 class="modal-title">Modal title</h5>
          <button type="button" class="close" data-dismiss="modal" aria-label="Close">
            <span aria-hidden="true">&times;</span>
          </button>
        </div>
        <div id="firstModalBody" class="modal-body">
          <div class="item form-group">
            <label class="col-form-label col-md-3 col-sm-3 label-align">Document<span class="required">*</span></label>
            <div id="s2File" class="col-md-9 col-sm-9">
              <div class="nested-blocks">
                <input type="radio" id="isFile" name="fileUploadRadio" value="1" class="form-radio" required="required" checked><label for="isFile">File Upload</label> <input type="file" id="inputFile" name="docFile" class="form-control has-feedback-left" value="" required>
              </div>
              <div class="nested-blocks">
                <input type="radio" id="isSS" name="fileUploadRadio" value="1" class="form-radio"><label for="isSS">ScreenShot Paste</label> <input type="file" id="inputSS" name="docFile" class="form-control has-feedback-left" value="" disabled style="background-color:#e9ecef;pointer-events:none">
              </div>
              <img id="cropped-image" src="" alt="SS" style="display:none;margin-top:10px;max-width:500px;max-height:200px">
            </div>
          </div>
        </div>
        <div class="modal-footer">
          <button type="button" class="btn btn-primary">Submit</button>
          <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
        </div>
      </div>
    </div>
  </form>
</div>
<div id="secondModal" class="modal" tabindex="-1" role="dialog">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title">Modal title</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
        <div class="img-container"><img id="cropper-image" src="" alt="SS"></div>
      </div>
      <div class="modal-footer">
        <div class="modal-footer">
          <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
          <button type="button" class="btn btn-primary" id="crop">Crop</button>
        </div>
      </div>
    </div>
  </div>
</div>

javascript bootstrap-modal cropper
1个回答
0
投票

我认为你的 JavaScript 代码是用 ajax 内容加载的(ajax 带来了 DOM),而不是在父 DOM 上。当您在动态 ajax 加载的内容上使用 JavaScript 时,您需要确保在模式关闭时卸载事件,以避免堆叠事件执行。

我检查了你的代码,你使用了委托事件,但是当你关闭模态时你没有卸载它们。因此,在第一次模态关闭时,cropper 为 null,当您启动第二轮时,js 事件将被堆叠,并运行两次并导致 canvas 返回 null。 解决方案:

  1. 卸载点击事件为
    $(document).off("click", "#isFile,#isSS");
  2. 卸载粘贴事件(您已经使用了 off() 但要卸载文档中附加的所有粘贴事件,最好指定 DOM id,如
    $(document).off("paste", "#firstModalBody");
  3. 您已取消绑定
    #crop
    上的点击事件,同样您还需要取消绑定显示/隐藏事件:
    $modal.unbind("shown.bs.modal");
    $modal.unbind("hidden.bs.modal");
© www.soinside.com 2019 - 2024. All rights reserved.