requestanimationframe()内的函数调用次数太多,如何只调用一次?

时间:2018-03-26 01:08:44

标签: javascript jquery html observable requestanimationframe

我目前有一个脚本,我在其中跟踪元素的.offset()位置。当此元素到达窗口的顶部,左侧,底部或右侧边缘时,我需要调用一个函数,该函数只应调用一次,然后在下次到达窗口边缘时再次调用。 / p>

现在我有这个:

var exceededBounds = false

function checkPosition(element) {
 var pos = element.offset(); 
 var maxBoundsX = $(window).width();
 var maxBoundsY = $(window).height();
 var minBoundsX = 0
 var minBoundsY = 0

 // if the element hits one of the edges of the window
 if (pos.left >= maxBoundsX || pos.top >= maxBoundsY || pos.left <= minBoundsX || pos.top <= minBoundsY) {
  if (!exceededBounds) {
   exceededBounds = true
  }
  else {
   exceededBounds = false
  }
 }
 else {
  exceededBounds = exceededBounds;
 }
}

function something() {
 // do something here, which only happens once
}


function init() {
 checkPosition(element);
 if (exceededBounds) {
  something()
 }
  requestAnimationFrame(init);
}

requestAnimationFrame(init);

问题是,something()函数被多次调用,我相信由于requestanimationframe()的帧速率?我需要使用requestanimationframe,但是我只想在变量exceededBounds发生变化时调用something()函数。我想过尝试在这里实现某种观察,但是对于我真正需要的东西来说感觉太复杂了。

由于

2 个答案:

答案 0 :(得分:1)

你需要保留两个布尔值:

  • exceeding以了解您的元素目前是否已超出范围。
  • changed知道最后一次检查是否已经超过。

&#13;
&#13;
var element = $('#el');
var changed = false;
var exceeding = false;

function checkPosition(element) {
  var pos = element.offset();
  var maxBoundsX = $(window).width();
  var maxBoundsY = $(window).height();
  var minBoundsX = 0
  var minBoundsY = 0

  // if the element hits one of the edges of the window
  if (pos.left >= maxBoundsX || pos.top >= maxBoundsY || pos.left <= minBoundsX || pos.top <= minBoundsY) {
    if (!exceeding) {
      changed = true
    } else {
      changed = false;
    }
    exceeding = true;
  } else {
    if (exceeding) {
      changed = true;
    } else {
      changed = false;
    }
    exceeding = false;
  }
}

function something() {
  console.log('changed:', exceeding ? 'hidden' : 'visible');
  // do something here, which only happens once
}


function init() {
  checkPosition(element);
  if (changed) {
    something()
  }
  requestAnimationFrame(init);
}

requestAnimationFrame(init);
&#13;
#el {
  margin-top: calc(100vh - 30px);
  margin-bottom: 100vh;
}

#cont {
  width: 100vw;
  height: 100vh;
  overflow: auto;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="cont">
  <div id="el">Scroll me</div>
</div>
&#13;
&#13;
&#13;

现在,我不知道是什么原因导致你的元素在你的场景中移动,但不要那样轮询。相反,请听取可能导致此更改的事件。 E.G,在我的片段中,你会听到受限制的scroll事件。

&#13;
&#13;
var element = $('#el');
var changed = false;
var exceeding = false;

cont.onscroll = throttle(init);

function checkPosition(element) {
  var pos = element.offset();
  var maxBoundsX = $(window).width();
  var maxBoundsY = $(window).height();
  var minBoundsX = 0
  var minBoundsY = 0

  // if the element hits one of the edges of the window
  if (pos.left >= maxBoundsX || pos.top >= maxBoundsY || pos.left <= minBoundsX || pos.top <= minBoundsY) {
   // our if else blocks can also be replaced by
    changed = !exceeding;
    exceeding = true;
  } else {
    changed = !!exceeding;
    exceeding = false;
  }
}

function something() {
  console.log('changed:', exceeding ? 'hidden' : 'visible');
  // do something here, which only happens once
}


function init() {
  checkPosition(element);
  if (changed) {
    something()
  }
}
// wait for next screen refresh before triggering event's callback
function throttle(callback) {
  if (typeof callback !== 'function')
    throw 'A callback function must be passed';
  var active = false;
  var evt;
  function handler() {
    active = false;
    callback(evt);
  };
  return function handleEvent(e) {
    evt = e;
    if (!active) {
      active = true;
      requestAnimationFrame(handler);
    }
  };
}
&#13;
#el {
  margin-top: calc(100vh - 30px);
  margin-bottom: 100vh;
}

#cont {
  width: 100vw;
  height: 100vh;
  overflow: auto;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="cont">
  <div id="el">Scroll me</div>
</div>
&#13;
&#13;
&#13;

答案 1 :(得分:0)

如果元素曾经有exceededBounds,那么多次调用 ,除非你的something立即立即更改元素以使其在界限范围内 - 这就是如何递归调用requestAnimationFrame会起作用,它会不断被反复调用。

我建议改变something,以便立即改变元素,使其再次进入边界 - 然后,something只会运行一次(直到它再次超出界限)。