需求📢:使列表无缝滚动,采用改变marginTop来实现滚动,还没写完就就出问题了
📍 代码如图所示, top值始终为0
❓:起初一头钻进了为什么setTop没生效,不明白为什么top一直为0,为什么setTop会没有生效?(心里暗暗想着一定是涉及到了js什么执行机制,只是我无法理清😵,好菜啊)
🤔:后来在useEffect中添加top依赖,由此top的值变化了。
🤔:对于图上代码分析下我当时的理解思路 ➡ 执行到useEffect的时候,开始第一次执行setScroll函数,top为0,nextTop为-5,执行到setTop后,top值更新为-5; 30ms后再执行setScroll,理所当然觉得第二次拿到的值是top的最新值。但结果不是,沉思…依稀记得,以前也是这么写的,咋就不对呢
🧐:百度去…
📍 闭包(我没看出来我🙊)
📍 解决方法
1️⃣ useEffect第二个参数传入top依赖
缺点:计时器重复的挂载和清除
useEffect(() => {
timer.current = setInterval(setScroll, 30);
return () => {
clearInterval(timer.current);
};
}, [top]);
2️⃣ 使用useRef(对象的引用),将top值赋给ref.current, setScroll中使用ref.current
const timer: any = useRef();
const [top, setTop] = useState<number>(0)
const step = -5
const count: any = useRef(); // here📌
count.current = top // here📌
const setScroll = () => {
const deviceScroll = document.getElementById('deviceScroll');
if (deviceScroll) {
const nextTop = count.current + step; // here📌
setTop(nextTop);
deviceScroll.style.marginTop = `${nextTop}px`;
console.log(nextTop, top, 'iiii');
}
};
📍 咱需求还是得继续完成(换成使用scrollTop啦)
version 1 👇
const timer: any = useRef();
const setScroll = () => {
const rawElem = document.getElementById('deviceScroll');
const cloneElm = document.getElementById('cloneElm');
const scrollBox = document.getElementById('deviceContainer');
if (rawElem && cloneElm && scrollBox) {
if (cloneElm.offsetHeight - scrollBox.scrollTop <= 0) scrollBox.scrollTop -= rawElem.offsetHeight;
else {
scrollBox.scrollTop += 1
}
}
};
useEffect(() => {
// 滚动
const rawElem = document.getElementById('deviceScroll');
const cloneElm = document.getElementById('cloneElm');
if (cloneElm && rawElem) {
cloneElm.innerHTML = rawElem.innerHTML;
}
timer.current = setInterval(setScroll, 30);
return () => {
clearInterval(timer.current);
};
}, []);
version 2 👇
import { useEffect, useRef } from 'react';
type ElmType = {
raw: string;
clone: string;
box: string;
};
const useScroll = (speed = 30, elm: ElmType, deps = []) => {
const timer: any = useRef();
const { raw, clone, box } = elm;
const setScroll = () => {
const rawElem = document.getElementById(raw);
const cloneElm = document.getElementById(clone);
const scrollBox = document.getElementById(box);
// 向上无缝滚动
if (rawElem && cloneElm && scrollBox) {
if (cloneElm.offsetHeight - scrollBox.scrollTop <= 0)
scrollBox.scrollTop -= rawElem.offsetHeight;
else {
// ⚠ 发现scrollTop + 1有时候不起作用,不会滚动,可以每次scrollTop + 2, 步数大于1就会生效
scrollBox.scrollTop += 1;
}
}
// 向左无缝滚动
// if (rawElem && cloneElm && scrollBox) {
// if (cloneElm.offsetWidth - scrollBox.scrollLeft <= 0) {
// scrollBox.scrollLeft -= rawElem.offsetWidth;
// } else {
// scrollBox.scrollLeft += 2;
// }
// }
};
useEffect(() => {
if (timer.current) clearInterval(timer.current);
const rawElem = document.getElementById(raw);
const cloneElm = document.getElementById(clone);
if (cloneElm && rawElem) {
cloneElm.innerHTML = rawElem.innerHTML;
}
timer.current = setInterval(setScroll, speed);
return () => {
clearInterval(timer.current);
};
}, deps);
};
export default useScroll;