为什么使用了FOR循环读不到toDataURL?

新手上路,请多包涵

要读取某网页,然后将这个网页的图片做裁剪处理,单个图片处理没有任何问题,但是只要把FOR循环放进去,用来批量处理所有图片,就无法读到图片了。

要处理的网站:https://mbd.baidu.com/newspag...

for (var i=0;i<document.getElementsByClassName('contentImg linexRBS').length;i++)
{

var tupianwidth=document.getElementsByClassName('contentImg linexRBS')[i].offsetWidth;
var tupianheight=document.getElementsByClassName('contentImg linexRBS')[i].offsetHeight;
tupianheight=tupianheight-20;


var targetImg = new Image();
targetImg.crossOrigin = '';


targetImg.src =document.getElementsByClassName('contentImg linexRBS')[i].getElementsByTagName("img")[0].src;

targetImg.onload = (function(){

var canvas = document.createElement('canvas');  

canvas.width = tupianwidth;
canvas.height= tupianheight;

var cxt = canvas.getContext('2d');

cxt.drawImage(targetImg,0,0);



var clipImage = canvas.toDataURL("image/png",1); 
document.getElementsByClassName('contentImg linexRBS')[i].getElementsByTagName("img")[0].src=clipImage;

})(i);
}
阅读 3.2k
4 个回答
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>图片裁剪</title>
    <script>
        document.addEventListener('DOMContentLoaded', function () {
            let arrImg = document.getElementsByClassName('contentImg');
            let len = arrImg.length;
            for (let i = 0; i < len; i++) {
                let targetImg = new Image();
                targetImg.src = arrImg[i].src;
                targetImg.onload = function () {
                    let tupianwidth = arrImg[i].offsetWidth;
                    let tupianheight = arrImg[i].offsetHeight;
                    tupianwidth = arrImg[i].offsetWidth-110;
                    tupianheight = tupianheight - 110;
                    let canvas = document.createElement('canvas');
                    canvas.width = tupianwidth;
                    canvas.height = tupianheight;
                    let cxt = canvas.getContext('2d');
                    cxt.drawImage(targetImg, 0, 0);
                    let clipImage = canvas.toDataURL("image/png", 1);
                    arrImg[i].src = clipImage;
                };
            }
        });
    </script>
</head>
<body>
    <img class="contentImg" src="1.jpg" alt="">
    <img class="contentImg" src="1.jpg" alt=""> 
    <img class="contentImg" src="1.jpg" alt="">
</body>
</html>

问题提的很好,

主要问题在于,图片onload使用和匿名函数自执行这块。因为你已经使用了canvas,必然会处理兼容性问题,所以完全可以使用let 节省大量代码和充分发挥let的块级作用域优势。

以上代码仅供参考,注意三点:

1.我用的本地图片,如果你是网上图片需要处理跨域。

2.注意性能,比如预先存储 let len = arrImg.length等。

3.尽量使用ES6简化代码。

希望我的回答对你有用,加油!

你这代码问题太多,一大堆的基础问题,好好学一下基础吧。。。

var arrDom = Array.prototype.slice.call(document.getElementsByClassName('contentImg linexRBS'));
var i, dom;
var tupianwidth, tupianheight;
var targetImg;
for(i=0; i<arrDom.length; i++)
{
    dom = arrDom[i];

    tupianwidth  = dom.offsetWidth;
    tupianheight = dom.offsetHeight;
    tupianheight = tupianheight-20;

    targetImg = new Image();
    targetImg.crossOrigin = '';

    targetImg.src = dom.getElementsByTagName("img")[0].src;

    targetImg.onload = (function($dom, $width, $height){

        return function(){
            var canvas = document.createElement('canvas');

            canvas.width = $width;
            canvas.height= $height;

            var ctx = canvas.getContext('2d');
            ctx.drawImage(this, 0, 0);

            $dom.getElementsByTagName("img")[0].src = canvas.toDataURL("image/png", 1);
        };

    })(dom, tupianwidth, tupianheight);
}

关键点是2个:

  1. onload必须指定为函数
  2. 注意变量的取值时机(闭包的相关知识)

(ps:代码里确实还有比较多的问题 例如document.getElementsByClassName返回的是nodelist 不应该用这个的长度作为数组变量,非常影响性能;并且代码的简写和规范都存在一些问题)
简单做个修改如下(只改最核心的保证实现效果 规范相关的自行加强吧。。。):

for (var i = 0; i < document.getElementsByClassName('contentImg linexRBS').length; i++) {
  var contImg = document.getElementsByClassName('contentImg linexRBS')[i]

  // 1.onload必须指定为function  这里立即执行函数的返回不是一个function,要做修改
  var targetImg = new Image();
  targetImg.crossOrigin = '';
  targetImg.src = contImg.getElementsByTagName("img")[0].src;
  targetImg.onload = (function (num,contImg,targetImg) {
    //2. 使用闭包后 注意变量生成的时机,注意对比下哪些变量需要放到闭包里
    return function (){
      var tupianwidth = contImg.offsetWidth;
      var tupianheight = contImg.offsetHeight;
      tupianheight = tupianheight - 200;

      var canvas = document.createElement('canvas');
      canvas.width = tupianwidth;
      canvas.height = tupianheight;

      var cxt = canvas.getContext('2d');
      cxt.drawImage(targetImg, 0, 0);
      var clipImage = canvas.toDataURL("image/png", 1);
      document.getElementsByClassName('contentImg linexRBS')[num].getElementsByTagName("img")[0].src = clipImage;
    }
  })(i,contImg,targetImg);
}

循环点击i取值问题常用的三种解决办法,不包括 let

for(var i = 0; i < li.length; i++){
    li[i].onclick = (function(i){ // 传参
        return function(){ // 返回一个函数,闭包
            alert(i);
        };
    })(i);
};

for(var i = 0; i < li.length; i++){
    (function(i){ // 形成自己的作用域
        li[i].onclick = function(){
            alert(i)
        }
    })(i)
};

for(var i = 0; i < li.length; i++){
    li[i].index=i; //给每个对象分别绑定一个属性作为标识
    li[i].onclick = function(){
        alert(this.index)
    }
};
所以你的 targetImg.onload 函数里面载加个 return 函数试下
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题