无法在addEventListener / Creating Object Array中定义Object的值

时间:2017-08-18 13:51:41

标签: javascript html arrays javascript-objects

我想要达到这样的目标:

  1. 获取元素具有相同的类(querySelectorAll
  2. 使用这些元素href attr获取链接。
  3. 使用这些链接检查这些远程图像'高度和宽度。
  4. 将它们打包为对象并推送它声明的数组。
  5. 但是,我无法从img.addEventListener("load", function(){})获取值 如果我在该函数外检查console.log(this.naturalWidth)undefined,那么值就在那里。

    现在,我在StackOverflow上打开了近20个关于" JS Scope"但它对我的情况没有意义。

    注意:我试图在没有jquery的情况下使

    var pselemgroup = document.querySelectorAll(pselemgroupname);
    
    for(var j = 0; j < pselemgroup.length; j++){
    
        var obj = new Object();
        var href = pselemgroup[j].href;
    
        var img = new Image();
        img.src = pselemgroup[j].href;
        img.addEventListener("load", function(){
            obj = {
                src: href,
                w: this.naturalWidth,
                h: this.naturalHeight
            };
            console.log(obj);
        });
        //pselemgroup[j].dataset.index = j;
        galleryElements.push(obj);
    }
    

    这也与实际问题无关,但是: 当我尝试获取href值时,我收到有关href的错误。

    一小时后,我了解到querySelectorAll返回NodeList,而不是Array。所以我也试过了:

    [].slice.call(document.querySelectorAll(pselemgroupname));

    并更改了一些代码:

    pselemgroup[j]["href"]

    但没有运气。

    谢谢。

    编辑:

    所以当我在加载函数中使用galleryElements.push(obj)时它会起作用,但是,我的最终目标是创建一个包含对象的数组。

    像:

    var items = [
        {
            src: "foo",
            w: "bar",
            h: "baz"
         },
        {
            src: "foo",
            w: "bar",
            h: "baz"
         },
    ]
    

    我可以访问像items[0].src这样的对象但是我。无法以相同的方式访问我的galleryElements[]数组对象。我得到错误说:

    undefined.src
    

1 个答案:

答案 0 :(得分:0)

你问题的一部分原因是你不了解eventlistener的工作方式以及你的对象何时被填充。

Eventlisteners以异步方式运行,因此,您不能假设您在回调中填充的对象在该范围之外填充。

一种简单的方法是使用Promise对象。

您可以轻松地将代码更改为以下

// loads the image and resolves when ready, containing the information you wanted to receive from the image
function loadImageFromUrlAsync( url, text ) {
  return new Promise( (resolve, reject) => {
    let image = new Image();
    image.src = url;
    image.addEventListener('load', () => resolve({
      title: text,
      width: image.naturalWidth,
      height: image.naturalHeight
    } ) );
  });
}

function loadAllImagesBySelectorAsync( selector ) {
  return new Promise( (resolve, reject) => {
    let elements = document.querySelectorAll( selector ),
      loaders = [], gallery = [];
    for (let element of elements) {
      // after the image is loaded the result gets pushed in your gallery
      loaders.push( 
        loadImageFromUrlAsync( element.href, element.innerText )
        .then( result => gallery.push(result) )
      );
    }
    // this will only go into resolve after all images are loaded
    Promise.all( loaders ).then( () => {
      resolve( gallery );
    });
  });
}

loadAllImagesBySelectorAsync('.image-link').then( gallery => {
  // writes the content of the gallery to the result div
  document.querySelector('#result').innerHTML = gallery
    .map( item => `${item.width}px + ${item.height}px for ${item.title}` )
    .join('<br />');
});
<a class="image-link" href="https://tse4.mm.bing.net/th?id=OIP.x0SJKpQsIUBt0asGiBa-iwEsDh&pid=15.1&P=0&w=232&h=175">Image 1</a>
<a class="image-link" href="https://tse2.mm.bing.net/th?id=OIP.wFyOf5HQmlo2j9p39nTbogEsC7&pid=15.1&P=0&w=279&h=175">Image 2</a>
<a class="image-link" href="https://tse2.mm.bing.net/th?id=OIP.SV38MmYJt0TbuZpJMM1mtwEsDI&pid=15.1&P=0&w=255&h=171">Image 3</a>
<a class="image-link" href="https://tse1.mm.bing.net/th?id=OIP.s2uDayjT1fqnoT921zfsQwDhEs&pid=15.1&P=0&w=300&h=300">Image 4</a>
<a class="image-link" href="https://tse3.mm.bing.net/th?id=OIP.cZ12zxh0UKEsf3Y1_GaReQDHEs&pid=15.1&P=0&w=300&h=300">Image 5</a>

<div id="result"></div>

但是如果您不想对当前代码进行如此广泛的更改,我们也可以像这样更改它,在这种情况下,您将拥有一个带有回调函数,该函数将在加载所有图像后调用

我试着评论代码中的变化,希望这样就够了

function loadMyGallery(pselemgroupname, callback) {
  // move all variable declaration per function
  // to the top, as var is function scoped
  var pselemgroup = document.querySelectorAll(pselemgroupname),
    j, img, galleryElements = [];

  for (j = 0; j < pselemgroup.length; j++) {

    img = new Image();
    img.src = pselemgroup[j].href;
    img.addEventListener("load", function( href ) {
      // push in the load method
      galleryElements.push({
        title: this.src,
        width: this.naturalWidth,
        height: this.naturalHeight
      });
      // call the callback when you loaded as many images as you found in the pselemgroup.length
      if (galleryElements.length === pselemgroup.length) {
        callback( galleryElements );
      }
      // bind img as the this context
    }.bind(img));
  }
  if (pselemgroup.length === 0) {
    // no elements
    setTimeout( callback, 0 );
  }
}

// load the gallery
loadMyGallery( '.image-link', ( gallery ) => {
  // writes the content of the gallery to the result div
  document.querySelector('#result').innerHTML = gallery
    .map( item => `${item.width}px + ${item.height}px for ${item.title}` )
    .join('<br />');
});
<a class="image-link" href="https://tse4.mm.bing.net/th?id=OIP.x0SJKpQsIUBt0asGiBa-iwEsDh&pid=15.1&P=0&w=232&h=175">Image 1</a>
<a class="image-link" href="https://tse2.mm.bing.net/th?id=OIP.wFyOf5HQmlo2j9p39nTbogEsC7&pid=15.1&P=0&w=279&h=175">Image 2</a>
<a class="image-link" href="https://tse2.mm.bing.net/th?id=OIP.SV38MmYJt0TbuZpJMM1mtwEsDI&pid=15.1&P=0&w=255&h=171">Image 3</a>
<a class="image-link" href="https://tse1.mm.bing.net/th?id=OIP.s2uDayjT1fqnoT921zfsQwDhEs&pid=15.1&P=0&w=300&h=300">Image 4</a>
<a class="image-link" href="https://tse3.mm.bing.net/th?id=OIP.cZ12zxh0UKEsf3Y1_GaReQDHEs&pid=15.1&P=0&w=300&h=300">Image 5</a>

<div id="result"></div>