日前,网页专题中经常会出现,无缝滚动的网页效果,这也已经成为广告门户网站的必有效果。先抛开这些不说,分析一下它的效果特征,一组图片反复地滚动而不像之前的marquee,总会有中断的一篇,这个效果从中也弥补了maruqee的bug,因此得到了用户的青睐。
无缝滚动这一效果分析其本质,即使用了一魔术中的障眼法,比如我想让一组图片向左滚动,则当这组图片的最后一张图片的右边滚动到显示区域的右边时,迅速设置这一组图片的left属性,使之变成0,从而能快速实现紧接着滚出时是第一张图片。同样,如果想让一组图片向右滚动,则当这组图片的第一张图片的左边滚动到显示区域的左边时,迅速设置这一组图片的left属性,使之变成这组图片的1/2位置处。技术要点:
1.这组图片在滚动之前设置成两组完全相同的html组成;
2.这组图片的父元素宽度必须足够宽,否则会出现图片折行问题;
3.滚动的是这组图片的父元素,而不是把每张图片进行设置;
4.如上所述使用的障眼法;
5.滚动方向其实就是与速度有关的一个参数;
6.主要用到元素的offsetWidth,offsetLeft两个属性;
7.显示图片的区域宽度必须小于所有图片的总宽度。
效果图:
代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>无缝滚动</title>
<style type="text/css">
div,
ul,
li {
margin: 0;
padding: 0;
}
#div1 {
margin: 100px auto 10px;
width: 720px;
height: 224px;
background-color: green;
position: relative;
overflow: hidden;
}
#div1 ul {
position: absolute;
left: 0;
top: 0;
}
#div1 ul li {
list-style: none;
float: left;
cursor: pointer;
}
img{
height: 224px;
}
#div2 {
text-align: center;
margin: 0 auto;
}
</style>
</head>
<body>
<div id="div1">
<ul>
<li>
<img src="img/1.jpg" />
</li>
<li>
<img src="img/2.jpg" />
</li>
<li>
<img src="img/3.jpg" />
</li>
<li>
<img src="img/4.jpg" />
</li>
<li>
<img src="img/5.jpg" />
</li>
<li>
<img src="img/6.jpg" />
</li>
<li>
<img src="img/7.jpg" />
</li>
<li>
<img src="img/8.jpg" />
</li>
<li>
<img src="img/9.jpg" />
</li>
<li>
<img src="img/10.jpg" />
</li>
</ul>
</div>
<div id="div2">
<input type="button" value="←" />
<input type="button" value="→" />
</div>
<script src="../js/jquery-1.11.1.min.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
var oDiv1 = document.getElementById('div1');
var oUl = oDiv1.children[0];
var aLi = oUl.children;
var speed = 2;
oUl.innerHTML += oUl.innerHTML;
oUl.style.width = aLi[0].offsetWidth * aLi.length + "px"; //设置ul的宽度,使它能够容纳所有的li,不至于li换行
var timer = setInterval(move, 30);
function move() {
//左滚动:如果ul滚动到其宽度的一半时,调整其左边距为0
if (oUl.offsetLeft < -oUl.offsetWidth / 2) {
oUl.style.left = "0";
}
//右滚动:如果ul滚动距离左边距大于0时,调整其左边距位置为其宽度的一半
if (oUl.offsetLeft > 0) {
oUl.style.left = -oUl.offsetWidth / 2 + "px";
}
oUl.style.left = oUl.offsetLeft + speed + "px";
}
oDiv1.onmouseover = function() {
clearInterval(timer);
};
oDiv1.onmouseout = function() {
timer = setInterval(move, 30);
};
var oDiv2 = document.getElementById('div2');
oDiv2.children[0].onclick = function() {
speed = -Math.abs(speed);
};
oDiv2.children[1].onclick = function() {
speed = Math.abs(speed);
};
</script>
</body>
</html>
至此,无缝滚动的效果就已完成,大家可以自行调试。
React版本的向上滚动hook
export interface ITimeRef {
timer: any
span: number
mouseEnter: boolean
}
// 滚动
export const useScroll = (timeRef: React.RefObject<ITimeRef>, containerRef: React.RefObject<HTMLDivElement>) => {
React.useEffect(() => {
;(timeRef.current as ITimeRef).timer = setInterval(() => {
if (containerRef.current) {
const chilrenDiv = containerRef.current.children[0] as HTMLDivElement
const pHeight = containerRef.current.offsetHeight
const cHeight = chilrenDiv.offsetHeight
if (cHeight - pHeight > 0) {
if (containerRef.current.children.length < 2) {
// 克隆一份子节点追加到父节点中
containerRef.current.appendChild(chilrenDiv.cloneNode(true))
}
// 滚动到底部
const bottom = cHeight * 2 - pHeight
let span = timeRef.current?.span || 0
if (!timeRef.current?.mouseEnter) {
span += 1
;(timeRef.current as ITimeRef).span = span
}
if (span <= bottom && !timeRef.current?.mouseEnter) {
if (span > cHeight) {
span = 0
;(timeRef.current as ITimeRef).span = span
}
for (let i = 0; i < containerRef.current.children.length; i += 1) {
const element = containerRef.current.children[i] as HTMLDivElement
element.style.transform = `translateY(-${span}px)`
}
}
}
}
}, 30)
// eslint-disable-next-line react-hooks/exhaustive-deps
return () => clearInterval((timeRef.current as ITimeRef).timer)
}, [containerRef, timeRef])
}