requestanimationframe() 中的函数调用次数过多,如何只调用一次?
Function within requestanimationframe() called too many times, how to call only once?
我目前有一个脚本,我在其中跟踪元素的 .offset() 位置。当这个元素到达window的上、左、下、右边缘时,我需要调用一个函数,该函数应该只调用一次,然后在下一次碰到边缘时再次调用window.
现在我有这个:
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() 函数。我想尝试在这里实现某种观察的东西,但感觉对于我实际需要的东西来说太复杂了。
谢谢
something() 如果元素曾经有 exceededBounds
,将 被多次调用,除非你的 something
立即更改元素,以便它是在范围内 - 这就是递归调用 requestAnimationFrame 的工作原理,它只会被一遍又一遍地调用。
我建议更改 something
以便立即更改元素以使其再次在范围内 - 然后,something
只会 运行 一次(直到它消失又出界了)。
您需要保留两个布尔值:
exceeding
了解您的元素当前是否越界。
changed
最后检查是否已经超标
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);
#el {
margin-top: calc(100vh - 30px);
margin-bottom: 100vh;
}
#cont {
width: 100vw;
height: 100vh;
overflow: auto;
}
<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>
现在,我不知道是什么导致您的元素在 您的 场景中移动,但不要那样轮询。相反,监听可能导致此更改的事件。例如,在我的代码片段中,您会收听受限的 scroll
事件。
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);
}
};
}
#el {
margin-top: calc(100vh - 30px);
margin-bottom: 100vh;
}
#cont {
width: 100vw;
height: 100vh;
overflow: auto;
}
<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>
我目前有一个脚本,我在其中跟踪元素的 .offset() 位置。当这个元素到达window的上、左、下、右边缘时,我需要调用一个函数,该函数应该只调用一次,然后在下一次碰到边缘时再次调用window.
现在我有这个:
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() 函数。我想尝试在这里实现某种观察的东西,但感觉对于我实际需要的东西来说太复杂了。
谢谢
something() 如果元素曾经有 exceededBounds
,将 被多次调用,除非你的 something
立即更改元素,以便它是在范围内 - 这就是递归调用 requestAnimationFrame 的工作原理,它只会被一遍又一遍地调用。
我建议更改 something
以便立即更改元素以使其再次在范围内 - 然后,something
只会 运行 一次(直到它消失又出界了)。
您需要保留两个布尔值:
exceeding
了解您的元素当前是否越界。changed
最后检查是否已经超标
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);
#el {
margin-top: calc(100vh - 30px);
margin-bottom: 100vh;
}
#cont {
width: 100vw;
height: 100vh;
overflow: auto;
}
<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>
现在,我不知道是什么导致您的元素在 您的 场景中移动,但不要那样轮询。相反,监听可能导致此更改的事件。例如,在我的代码片段中,您会收听受限的 scroll
事件。
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);
}
};
}
#el {
margin-top: calc(100vh - 30px);
margin-bottom: 100vh;
}
#cont {
width: 100vw;
height: 100vh;
overflow: auto;
}
<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>