Cropper JS:Positioning/size Bootstrap 模态内的问题

Cropper JS : Positioning/size issue inside Bootstrap modal

这是输出屏幕,图像未正确定位,尺寸在 bootstrap 模态内。

我正在尝试使用 'avatar' 更新部分中的 'cropper.js' 插件 project.I 添加相关的 CSS 和 JS 文件也使用 jquery该插件运行良好。我的问题是 bootstrap 模态中的图像 positioning/size。它显示在小和左中间。我正在努力使它们的尺寸、位置和响应输出都很好。我尝试的是为这个问题添加 below.Any 帮助,非常感谢。

我做了什么:

main.js 用于 initializing/uploading 的文件并使用裁剪插件裁剪图像

(function (factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as anonymous module.
    define(['jquery'], factory);
  } else if (typeof exports === 'object') {
    // Node / CommonJS
    factory(require('jquery'));
  } else {
    // Browser globals.
    factory(jQuery);
  }
})(function ($) {

  'use strict';

  var console = window.console || { log: function () {} };

  function CropAvatar($element) {
    this.$container = $element;

    this.$avatarView = this.$container.find('.avatar-view');
    this.$avatar = this.$avatarView.find('img');
    this.$avatarModal = this.$container.find('#avatar-modal');
    this.$avatarModal1 = this.$container.find('#avatar-modal1');
    this.$loading = this.$container.find('.loading');

    this.$avatarForm = this.$avatarModal1.find('.avatar-form');
    this.$avatarUpload = this.$avatarForm.find('.avatar-upload');
    this.$avatarSrc = this.$avatarForm.find('.avatar-src');
    this.$avatarData = this.$avatarForm.find('.avatar-data');
    this.$avatarInput = this.$avatarForm.find('.avatar-input');
    this.$avatarSave = this.$avatarForm.find('.avatar-save');
    this.$avatarBtns = this.$avatarForm.find('.avatar-btns');

    this.$avatarWrapper = this.$avatarModal.find('.avatar-wrapper');
    this.$avatarPreview = this.$avatarModal.find('.avatar-preview');

    this.init();
  }

  CropAvatar.prototype = {
    constructor: CropAvatar,

    support: {
      fileList: !!$('<input type="file">').prop('files'),
      blobURLs: !!window.URL && URL.createObjectURL,
      formData: !!window.FormData
    },

    init: function () {
      this.support.datauri = this.support.fileList && this.support.blobURLs;

      if (!this.support.formData) {
        this.initIframe();
      }

      this.initTooltip();
      this.initModal();
      this.addListener();
    },

    addListener: function () {
      this.$avatarView.on('click', $.proxy(this.click, this));

      this.$avatarInput.on('change', $.proxy(this.change, this));
      //this.$avatarInput.on('change', $.proxy(this.click, this));

      this.$avatarForm.on('submit', $.proxy(this.submit, this));
      this.$avatarBtns.on('click', $.proxy(this.rotate, this));
    },

    initTooltip: function () {
      this.$avatarView.tooltip({
        placement: 'bottom'
      });
    },


    initPreview: function () {
      var url = this.$avatar.attr('src');

      this.$avatarPreview.html('<img src="' + url + '">');
    },

    initIframe: function () {
      var target = 'upload-iframe-' + (new Date()).getTime();
      var $iframe = $('<iframe>').attr({
            name: target,
            src: ''
          });
      var _this = this;

      // Ready ifrmae
      $iframe.one('load', function () {

        // respond response
        $iframe.on('load', function () {
          var data;

          try {
            data = $(this).contents().find('body').text();
          } catch (e) {
            console.log(e.message);
          }

          if (data) {
            try {
              data = $.parseJSON(data);
            } catch (e) {
              console.log(e.message);
            }

            _this.submitDone(data);
          } else {
            _this.submitFail('Image upload failed!');
          }

          _this.submitEnd();


        });
      });

      this.$iframe = $iframe;
      this.$avatarForm.attr('target', target).after($iframe.hide());
    },
     initModal: function () {
      this.$avatarModal.modal({
        show: false
      });
    },


    click: function () {
      this.$avatarModal.modal('show');
      this.initPreview();
    },
    change: function () {
      //alert("changed");
      this.$avatarModal.modal('show');
             this.initPreview();

      var files;
      var file;

      if (this.support.datauri) {
        files = this.$avatarInput.prop('files');

        if (files.length > 0) {
          file = files[0];

          if (this.isImageFile(file)) {
            if (this.url) {
              URL.revokeObjectURL(this.url); // Revoke the old one
            }



            this.url = URL.createObjectURL(file);
            this.startCropper();

          }
        }
      } else {
        file = this.$avatarInput.val();

        if (this.isImageFile(file)) {
          //alert("changed");
          this.syncUpload();
        }
      }
    },


    isImageFile: function (file) {
      if (file.type) {
        return /^image\/\w+$/.test(file.type);
      } else {
        return /\.(jpg|jpeg|png|gif)$/.test(file);
      }
    },

    startCropper: function () {
      var _this = this;

      if (this.active) {
        this.$img.cropper('replace', this.url);
      } else {
        this.$img = $('<img src="' + this.url + '">');
        this.$avatarWrapper.empty().html(this.$img);
        this.$img.cropper({
          //aspectRatio: 1,
          aspectRatio: 1,
          preview: this.$avatarPreview.selector,
          crop: function (e) {
            var json = [
                  '{"x":' + e.x,
                  '"y":' + e.y,
                  '"height":' + e.height,
                  '"width":' + e.width,
                  '"rotate":' + e.rotate + '}'
                ].join();

            _this.$avatarData.val(json);
             $("#output").html("("+e.width+","+e.height+")");
          }
        });

      this.active = true;
      }

      this.$avatarModal.one('hidden.bs.modal', function () {
        _this.$avatarPreview.empty();
        _this.stopCropper();
      });
    },

    stopCropper: function () {
      if (this.active) {
        this.$img.cropper('destroy');
        this.$img.remove();
        this.active = false;
      }
    },

    syncUpload: function () {
      this.$avatarSave.click();
    },

    alert: function (msg) {
      var $alert = [
            '<div class="alert alert-danger avatar-alert alert-dismissable">',
              '<button type="button" class="close" data-dismiss="alert">&times;</button>',
              msg,
            '</div>'
          ].join('');

      this.$avatarUpload.after($alert);
    }
  };

  $(function () {
    return new CropAvatar($('#crop-avatar'));
  });

}); 

主页 - HTML查看页面

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Image Cropping with Cropper JS</title>
  <link rel="stylesheet" href="css/bootstrap.min.css">
  <link rel="stylesheet" href="css/cropper.min.css">
  <link rel="stylesheet" href="css/cropper.css">
  <link rel="stylesheet" href="css/styles.css">

</head>
<body>
  <div class="container" id="crop-avatar">

    <!-- Current avatar -->
    <div class="avatar-view" title="Change the avatar">
      <img src="img/img.jpg" alt="Avatar">
    </div>

    <div id="avatar-modal1">
    <form class="avatar-form" action="crop.php" enctype="multipart/form-data" method="post">

      <!-- Upload image and data -->
                <div class="avatar-upload">
                  <input type="hidden" class="avatar-src" name="avatar_src">
                  <input type="hidden" class="avatar-data" name="avatar_data">
                  <label for="avatarInput">Upload</label>
                  <input type="file" class="avatar-input" id="avatarInput" name="avatar_file">
                </div>
    <!-- Cropping modal -->
    <div class="modal fade" id="avatar-modal" aria-hidden="true" aria-labelledby="avatar-modal-label" role="dialog" tabindex="-1">
      <div class="modal-dialog modal-lg">
        <div class="modal-content">

            <div class="modal-header">
              <button type="button" class="close" data-dismiss="modal">&times;</button>
              <h4 class="modal-title" id="avatar-modal-label">Change Image</h4>
            </div>
            <div class="modal-body">
              <div class="avatar-body">



                <!-- Crop and preview -->
                <div class="row">
                  <div class="col-md-9">
                    <div class="avatar-wrapper"> </div>
                  </div>
                  <div class="col-md-3">
                    <div class="avatar-preview preview-lg" style="border-radius:90px !important;"></div>
                    <!-- <div class="avatar-preview preview-md"></div>
                    <div class="avatar-preview preview-sm"></div>-->
                    <br>
                    <h5>Output value(width,height)</h5>
                    <div id="output"></div>



                  </div>
                </div>

                <div class="row avatar-btns">
                  <!--<div class="col-md-9">
                    <div class="btn-group">
                      <button type="button" class="btn btn-primary" data-method="rotate" data-option="-90" title="Rotate -90 degrees">Rotate Left</button>
                      <button type="button" class="btn btn-primary" data-method="rotate" data-option="-15">-15deg</button>
                      <button type="button" class="btn btn-primary" data-method="rotate" data-option="-30">-30deg</button>
                      <button type="button" class="btn btn-primary" data-method="rotate" data-option="-45">-45deg</button>
                    </div>
                    <div class="btn-group">
                      <button type="button" class="btn btn-primary" data-method="rotate" data-option="90" title="Rotate 90 degrees">Rotate Right</button>
                      <button type="button" class="btn btn-primary" data-method="rotate" data-option="15">15deg</button>
                      <button type="button" class="btn btn-primary" data-method="rotate" data-option="30">30deg</button>
                      <button type="button" class="btn btn-primary" data-method="rotate" data-option="45">45deg</button>
                    </div>
                  </div>
                  <div class="col-md-3">
                    <button type="submit" class="btn btn-primary btn-block avatar-save">Done</button>
                  </div>-->
                </div>
              </div>
            </div>

        </div>
      </div>
    </div><!-- /.modal -->

  </form>
  </div>
    <!-- Loading state -->
     <div class="loading" aria-label="Loading" role="img" tabindex="-1"></div>
  </div>

  <script src="js/jquery.min.js"></script>
  <script src="js/bootstrap.min.js"></script>
  <script src="js/cropper.min.js"></script>
  <script src="js/main.js"></script>
</body>
</html>

我想通了,

问题

Bootstrap 模式内容(CSS 和元素)在我们像上面那样初始化时没有完全加载

解决方案

(1) 。首先准备 Bootstrap 模态内容,然后使用 bootstrap-模态事件方法加载事件。

(2) 。根据使用情况使用延迟或移除延迟

查看下面来自 https://github.com/fengyuanchen/cropperjs#notes

的注释

备注

  1. cropper 的大小继承自图像父元素(wrapper)的大小,所以一定要用可见的块元素包裹图像。

    如果您在模态中使用剪裁器,您应该在模态完全显示后初始化剪裁器。否则,您将无法获得正确的裁剪器。

  2. 输出的裁剪数据基于原始图像尺寸,因此您可以使用它们直接裁剪图像。

  3. 如果您尝试在跨源图像上启动裁剪器,请确保您的浏览器支持 HTML5 CORS 设置属性,并且您的图像服务器支持 Access-Control-Allow -Origin 选项(参见 HTTP 访问控制 (CORS))。

Class 模态淡入淡出对我来说是个问题,删除淡入淡出效果非常好。

如果想保持淡入淡出效果,使用setTimeout初始化cropper,所以$('#yourModal').modal('show');初始化裁剪器的函数的 setTimeout。

Arnab Chaudhuri 的回答中提到了这一点:

If you are using cropper in a modal, you should initialize the cropper after the modal shown completely. Otherwise, you will not get a correct cropper.