存储每个循环的值并在另一个函数中使用

时间:2013-09-07 03:17:32

标签: jquery each

我正在尝试将容器的纵横比与一系列图像的纵横比进行比较,并为图像添加类纵向或横向。此外,我试图根据定义的容差检测非常高/宽的图像(如大全景图)。我的基本功能正常here(前两个图像的左上角有一个“缩放”按钮)。

现在,我正在尝试拆分该功能,因此当我调整页面大小时,脚本不再计算所有图像的比例(var i_ratio),它只是将这些与新容器比率(var)进行比较c_ratio)。我的开发示例是here

我想我的问题是我不知道如何:

  • 确保第二个功能在第一个功能完成后运行
  • 将i_ratio中的值从第一个函数传递到下一个

在开发示例中,有一个控制台日志,显示i_ratio在第二个函数中未定义,但是当您调整窗口大小时,它似乎得到一个值 - 不确定发生了什么。

// Get window aspect ratio
var container = $('.main');
var c_ratio = container.width() / container.height();
var i_ratio;

function imageRatios() {
  // Get original dimensions of image (IE8+)
  if (this.naturalWidth) {
    i_width = this.naturalWidth;
    i_height = this.naturalHeight;
  } else {
  // Get original dimensions of image with JQuery
    i_width = this.width;
    i_height = this.height;
  }
  i_ratio = i_width / i_height;
  // Don't allow images to get bigger than their original size
  $(this).css('max-width', i_width).css('max-height', i_height);
}

function setClass() {
  console.log('number of images: '+images.length+', i_ratio from imageRatios function: '+i_ratio);
  // Add ratio classes    
  if (c_ratio > i_ratio) {
    $(this).parent('li').removeClass('landscape').addClass('portrait');
  } else {
    $(this).parent('li').removeClass('portrait').addClass('landscape');
  }
  // Identify long/tall panoramas and add zoom button
  tolerance = c_ratio / i_ratio;
  if (tolerance < 0.3 || tolerance > 5) {
    $(this).after('<div class="zoom">&#xf065;</div>');
  } else {
    $(this).remove('.zoom');
  }
  // Show/hide zoomed image
  var img = $(this);
  $(this).next('.zoom').click(function() {
    if (img.siblings('.big_image').size() > 0) {
      $('.big_image').remove();
    } else {
      $(this).after('<div class="big_image"><img src="'+$img.attr('src')+'"></div>');        
    }
  });
}

// Get images
var images = $('.main img');
images.each(function(i) {
  if (this.complete) {
    imageRatios.call(this);
    setClass();
  } else {
    this.onload = imageRatios;
    setClass();
  }
});

// Update ratio class on resize
$(window).on("throttledresize", function() {
  var c_ratio = container.width() / container.height();
  images.each(function() {
    setClass();
  });
});

2 个答案:

答案 0 :(得分:1)

有几个问题 - 这将是未经测试的,因此您可能需要调整一下以使其正确

  • 初始化图像时,在设置卸载处理程序后立即调用setClass。处理程序是异步的,因此立即调用setClass将导致您在控制台中看到未定义的值。
  • 图像比率都存储在同一个变量中。您需要调整它以按图像存储它们
  • 调用setClass时,调用setClass时没有设置上下文,因此this将成为全局对象

获取图像逻辑可以调整为:

// Get images
var images = $('.main img');
images.each(function(i) {
  if (this.complete) {
    imageRatios.call(this, i);
    setClass.call(this, i);   // <== call with image as the context and pass its index
  } else {
    // Wrap the calls to imageRatios & setClass in the callback so
    // they can be called sequentially
    this.onload = function() {
      imageRatios.call(this, i);
      setClass.call(this, i); // <== call with image as the context and pass its index
    };
  }
});

限制调整大小可以修改为:

// Update ratio class on resize
$(window).on("throttledresize", function() {
  c_ratio = container.width() / container.height(); // <== remove var - needs to be available to other functions in this closure (already declared at top)
  // TODO: Just need to update class, not recalculate image ratios on resize
  images.each(function(i) {
    setClass.call(this,i);   // <== call with image as the context and pass its index
  });
});

imageRatios to:

  var i_ratio = [];         // <== use an array of values indexes will match image indexes

  function imageRatios(i) { // <== change to accept an index
    var i_width, i_height;  // <== declare as local variables

    // Get original dimensions of image (IE8+)
    if (this.naturalWidth) {
      i_width = this.naturalWidth;
      i_height = this.naturalHeight;
    } else {
    // Get original dimensions of image with JQuery
      i_width = this.width;
      i_height = this.height;
    }
    i_ratio[i] = i_width / i_height;  // <== set the ratio using the passed in index
    // Don't allow images to get bigger than their original size
    $(this).css('max-width', i_width).css('max-height', i_height);
  }

setClass为:

  function setClass(i) {  // <== Change to accept an index
    var tolerance; // <== Declare as local variable
    console.log('number of images: '+images.length+', i_ratio from imageRatios function: '+i_ratio);
    // Add ratio classes    
    if (c_ratio > i_ratio[i]) { // <== Use the index to get the right ratio
      $(this).parent('li').removeClass('landscape').addClass('portrait');
    } else {
      $(this).parent('li').removeClass('portrait').addClass('landscape');
    }
    // Identify long/tall panoramas and add zoom button
    tolerance = c_ratio / i_ratio[i]; // <== Use the index to get the right ration
    if (tolerance < 0.3 || tolerance > 5) {
      $(this).after('<div class="zoom">&#xf065;</div>');
    } else {
      $(this).remove('.zoom');
    }
    // Show/hide zoomed image
    var img = $(this);
    $(this).next('.zoom').click(function() {
      if (img.siblings('.big_image').size() > 0) {
        $('.big_image').remove();
      } else {
        $(this).after('<div class="big_image"><img src="'+$img.attr('src')+'"></div>');        
      }
    });
  }

答案 1 :(得分:0)

未定义值的问题来自此代码

images.each(function (i) {
    if (this.complete) {
        imageRatios.call(this);
        setClass();
    } else {
        this.onload = imageRatios;
        setClass();
    }
});

将每个图像的onload回调设置为imageRatios,然后调用setClass()但是它不会等到onload事件被触发后才能继续setClass尝试这样的事情

images.each(function (i) {
    if (this.complete) {
        imageRatios.call(this);
        setClass();
    } else {
        this.onload = function () {
            imageRatios();
            setClass();
        };
    }
});

在为图片触发imageRatios()事件时,将按此顺序调用setClass()然后调用onload