1

コンテナーの縦横比を一連の画像の縦横比と比較し、クラスのポートレートまたはランドスケープを画像に追加しようとしています。また、定義された許容範囲に基づいて、非常に高い/広い画像 (大きなパノラマなど) を検出しようとしています。ここで基本的な機能が動作しています(最初の 2 つの画像には、左上隅に「ズーム」ボタンがあります)。

今、私は関数を分割しようとしているので、ページのサイズを変更すると、スクリプトはすべての画像の比率 (var i_ratio) を再度計算するのではなく、これらを新しいコンテナーの比率 (var c_ratio) と比較するだけです。私の開発例はこちらです。

私の問題は、次の方法がわからないことだと思います。

  • 最初の関数が完了した後に 2 番目の関数が実行されるようにする
  • 最初の関数の i_ratio の値を次の関数に渡します

開発者の例では、i_ratio が 2 番目の関数内で定義されていないことを示すコンソール ログがありますが、ウィンドウのサイズを変更すると、値を取得するように見えます - 何が起こっているのかわかりません。

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

2 に答える 2

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

クラスを次のように設定します。

  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>');        
      }
    });
  }
于 2013-09-07T03:47:30.257 に答える