【问题标题】:Store values from each loop and use in another function存储每个循环中的值并在另一个函数中使用
【发布时间】:2013-09-11 05:39:25
【问题描述】:

我正在尝试将容器的纵横比与一系列图像的纵横比进行比较,并为图像添加一个类纵向或横向。此外,我正在尝试根据定义的容差检测非常高/宽的图像(如大全景图)。我的基本功能可以正常工作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();
  });
});

【问题讨论】:

  • 请在您的问题中包含用于函数的javascript
  • 相关代码已包含,谢谢。
  • 好吧,你知道你可以将参数传递给函数吗?您似乎在使用全局变量在函数之间共享数据,这使您的代码不太灵活和易于理解。
  • @plalx 是的,我工作中的 js 人说我也应该先这样做,但是我尝试时一直打破它(我刚开始使用 jquery),你知道任何好的链接这解释了如何做到这一点?我在网上找不到任何东西,也许我在寻找错误的东西

标签: jquery each


【解决方案1】:

几个问题 - 这将未经测试,因此您可能需要稍作调整以使其正确

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

Get Images 逻辑可以调整成这样:

// 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 到:

  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);
  }

将类设置为:

  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>');        
      }
    });
  }

【讨论】:

  • 谢谢!我从这段代码中学到了很多东西。有几个我能够修复的语法错误。你想让我用更正的代码更新你的答案吗?不确定 SO 礼仪 :) 如果不是,你可以在这里找到工作代码 houseofyum.co.uk/static/gallery/index5.html
  • 我刚刚做了一些更新,也许我抓住了它们?如果没有,请在此处发布,我可以更新。检查我的编辑历史,确保我们发现了相同的问题。
  • @daviestar - 在您的网站上,您的 big_image 逻辑在此行失败:$(this).after('&lt;div class="big_image"&gt;&lt;img src="'+$img.attr('src')+'"&gt;&lt;/div&gt;');:$img is not defined
  • 除了你的第一个代码 sn-p 之外,你得到了所有这些 - 用 } 关闭 this.onload
  • @daviestar - 已更新。谢谢! (并查看我之前的评论)
【解决方案2】:

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

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();
        };
    }
});

当为图像触发onload 事件时,它将依次调用imageRatios()setClass()

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-20
  • 1970-01-01
  • 2018-07-24
  • 2022-01-26
  • 1970-01-01
  • 1970-01-01
  • 2015-03-27
相关资源
最近更新 更多