Javascript - 从文件上传创建画布图像元素

时间:2016-07-15 16:20:42

标签: javascript canvas html5-canvas

当用户上传图片时,我想用画布调整图片大小。您只需上传一张图片即可使用以下代码。但是如果您选择多个图像,画布项目不显示图像(仅在最后一个画布元素上),是否有人知道出了什么问题?

https://jsfiddle.net/4ycgqyau/

 function prepPreview(input) {
  var container = document.getElementById("preview");

  var files = jQuery(input).get(0).files;
  for (var i = 0; i < files.length; i++) {

    // create canvas element & resize image
    var canvasEl = document.createElement("canvas");
    canvasEl.id = 'canvas_' + i;
    canvasEl.width = "250";
    canvasEl.height = "140";
    container.appendChild(canvasEl);

    var canvas = document.getElementById('canvas_' + i);
    var context = canvas.getContext('2d');

    var reader = new FileReader();
    reader.onload = function(event) {
      var imageObj = new Image();
      imageObj.onload = function() {
        var wrh = imageObj.width / imageObj.height;
        var newWidth = canvas.width;
        var newHeight = newWidth / wrh;
        if (newHeight > canvas.height) {
          newHeight = canvas.height;
          newWidth = newHeight * wrh;
        }
        context.drawImage(imageObj, 0, 0, newWidth, newHeight);
      };
      imageObj.src = reader.result;
    }
    reader.readAsDataURL(files[i], 'canvas_' + i);
    console.log(files[i], 'canvas_' + i);

    // create input
    var input = document.createElement("input");
    input.type = "text";
    input.setAttribute('maxLength', 150);
    input.name = "caption[" + i + "]";
    container.appendChild(input);

    // create row around image/input
    var row = document.createElement("div");
    row.className = 'user-uploads__row';
    canvasEl.parentNode.insertBefore(row, canvasEl, input);
    row.appendChild(canvasEl);
    row.appendChild(input);
  }
}

3 个答案:

答案 0 :(得分:2)

JavaScript具有function-level范围,它意味着在function-block中创建的变量将在函数中具有范围。在for-loop中,正在创建block-level({//code}),其中变量的值在嵌套迭代中被覆盖,因此onload仅考虑最后一个画布,因为asynchronous性质事件

更简单的解决方案是使用Array#forEach,其中handler-function每个文件都有自己的scope

使用[].forEach.call使用必须迭代的array-like对象的数组原型

同样不是jQuery(input).get(0).files太丑了,因为你没有使用jQuery的任何内容,因此只能访问files的{​​{1}}属性

input
jQuery("#uploads").change(function() {
  prepPreview(this);
});

function prepPreview(input) {
  var container = document.getElementById("preview");
  var files = input.files;
  [].forEach.call(files, function(inp, i) {
    var canvasEl = document.createElement("canvas");
    canvasEl.id = 'canvas_' + i;
    canvasEl.width = "250";
    canvasEl.height = "140";
    container.appendChild(canvasEl);
    var canvas = document.getElementById('canvas_' + i);
    var context = canvas.getContext('2d');
    var reader = new FileReader();
    reader.onload = function(event) {
      var imageObj = new Image();
      imageObj.onload = function() {
        var wrh = imageObj.width / imageObj.height;
        var newWidth = canvas.width;
        var newHeight = newWidth / wrh;
        if (newHeight > canvas.height) {
          newHeight = canvas.height;
          newWidth = newHeight * wrh;
        }
        context.drawImage(imageObj, 0, 0, newWidth, newHeight);
      };
      imageObj.src = reader.result;
    }
    reader.readAsDataURL(files[i], 'canvas_' + i);
    var input = document.createElement("input");
    input.type = "text";
    input.setAttribute('maxLength', 150);
    input.name = "caption[" + i + "]";
    container.appendChild(input);
    var row = document.createElement("div");
    row.className = 'user-uploads__row';
    canvasEl.parentNode.insertBefore(row, canvasEl, input);
    row.appendChild(canvasEl);
    row.appendChild(input);
  });
}
.user-uploads__row {
  background: #fff;
  padding: 20px;
  border: 1px solid #888;
  margin: 20px;
}

Updated Fiddle

答案 1 :(得分:1)

答案 2 :(得分:1)

请查看此版本:https://jsfiddle.net/4ycgqyau/6/

您需要创建一个闭包环境来存储canvas,context,并将其传递给onload事件。 理解它的简单方法,如何创建一个闭包?

imageObj.onload = (function(canvas,context) {
          return function (){
             // write your code
          }})(canvas,context)