perf: tiện ích render-gate (dừng vòng lặp vẽ khi ngoài màn hình/đổi tab)
This commit is contained in:
@@ -0,0 +1,39 @@
|
|||||||
|
// src/app/lib/render-gate.ts
|
||||||
|
// Chỉ cho phép vòng lặp vẽ (rAF/setAnimationLoop) chạy khi phần tử nằm trong vùng nhìn
|
||||||
|
// VÀ tab đang hiển thị. Gọi onChange(active) mỗi khi trạng thái đổi. Trả về hàm dọn dẹp.
|
||||||
|
export function createRenderGate(
|
||||||
|
element: Element,
|
||||||
|
onChange: (active: boolean) => void,
|
||||||
|
): () => void {
|
||||||
|
let onScreen = false;
|
||||||
|
let visible = typeof document === "undefined" ? true : !document.hidden;
|
||||||
|
let last = false;
|
||||||
|
|
||||||
|
const emit = () => {
|
||||||
|
const next = onScreen && visible;
|
||||||
|
if (next !== last) {
|
||||||
|
last = next;
|
||||||
|
onChange(next);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const io = new IntersectionObserver(
|
||||||
|
(entries) => {
|
||||||
|
onScreen = entries.some((entry) => entry.isIntersecting);
|
||||||
|
emit();
|
||||||
|
},
|
||||||
|
{ threshold: 0.01 },
|
||||||
|
);
|
||||||
|
io.observe(element);
|
||||||
|
|
||||||
|
const onVisibility = () => {
|
||||||
|
visible = !document.hidden;
|
||||||
|
emit();
|
||||||
|
};
|
||||||
|
document.addEventListener("visibilitychange", onVisibility);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
io.disconnect();
|
||||||
|
document.removeEventListener("visibilitychange", onVisibility);
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user