• 4
  • 新人请关照

为什么使用了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);
}
阅读 386
评论 2019-03-25 提问
    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);
      }
        • 5.1k

        关键点是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 函数试下
            撰写回答

            登录后参与交流、获取后续更新提醒