码海无涯系列,写给自己的注释
码海无涯–实现一个“欺骗式”的图片滚动(js)

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#demo {
overflow: auto;/* 实际使用时,要改为hidden,以隐藏滚动条*/
width: 300px;
border: 1px dashed #ccc;
background: #fff;
margin: 0 auto;
}
#indemo {
float: left;
width: 900%;
/* 这个很重要,要把它设置的大一点,否则你可以试试*/
}
#demo1,
#demo2 {
float: left
}
#demo2 {
margin-left: 5px;
}
img {
height: 200px;
border: 3px double #000;
width: auto;
padding: 5px;
}
.img1 {
background-color: pink;
}
.img2 {
background-color: #cf2828;
}
.img3 {
background-color: #916060;
}
</style>
</head>
<body>
<div id="demo">
<div id="indemo">
<div id="demo1">
<a target=_blank href=https://google.com><img class="img1" src=https://via.placeholder.com/150></a>
<a target=_blank href=https://google.com><img class="img2" src=https://via.placeholder.com/150></a>
<a target=_blank href=https://google.com><img class="img3" src=https://via.placeholder.com/150></a>
</div>
<div id="demo2"></div>
</div>
</div>
<script>
var speed = 20; //时间为20ms
var tab = document.getElementById("demo");
var tab1 = document.getElementById("demo1");
var tab2 = document.getElementById("demo2");
tab2.innerHTML = tab1.innerHTML; // 偷懒,复制demo的html语句给demo2
function Marquee() {
if (tab2.offsetWidth - tab.scrollLeft <= 0) {
// 当 tab2.offsetWidth - tab.scrollLeft <= 0
// offsetWidth 即不包括外边距(margin)的宽
// scrollLeft 即滚动条到元素左边的距离
// tab2.offsetWidth - tab.scrollLeft 即demo2(后面放图片的容器)总宽减去demo离左边的值
// tab2.offsetWidth 表示滚动容器中内容的总宽度,即 demo2 的宽度。
// tab.scrollLeft 表示滚动容器的当前水平滚动位置。
// tab2.offsetWidth 是固定不变的(即 demo2 的宽)
// tab.scrollLeft 其最大值则为demo2 的宽(因为demo的大小是里面的内容撑起来的, 可能会大点)
// 当tab.scrollLeft达到最大值时(即等于大于demo2的宽),意味着内容滚动到最左边,此时相减则 tab2.offsetWidth - tab.scrollLeft <= 0
// 所以,tab2.offsetWidth - tab.scrollLeft 表示内容的末尾距离滚动容器左侧的距离。当这个距离小于等于 0 时,说明滚动已经到达了末尾,此时我们希望将滚动位置重新设置为初始位置,实现循环滚动的效果。
// 具体来说,如果 tab2.offsetWidth - tab.scrollLeft 小于等于 0,表示内容已经完全滚动出了可视区域,此时我们将 tab.scrollLeft 重置为 0,重新从左侧开始滚动,形成循环。否则,我们继续将 tab.scrollLeft 增加,实现滚动效果。
// 这样的设置可以确保滚动不会无限制地继续,而是在内容末尾处重新开始,从而实现了无缝循环滚动。
// if (tab2.offsetWidth - tab.scrollLeft <= 0)这样的写法令人困惑,不如直接使用tab.scrollLeft >= tab2.offsetWidth
tab.scrollLeft = 0; // 滚动到末尾时重置为0,实现循环效果
} else {
tab.scrollLeft++;
// tab.scrollLeft++; 表示将 tab 元素的水平滚动位置向右移动一个像素。这行代码是在检测到内容未完全滚动出可视区域时执行的,即 tab2.offsetWidth - tab.scrollLeft 大于 0 的情况。
// 通过递增 tab.scrollLeft,实现了内容向左滚动的效果。整个代码的逻辑是不断地在 setInterval 定时器中执行 Marquee 函数,而 Marquee 函数中根据滚动位置和内容宽度的关系来判断是继续向右滚动还是重新回到最左侧开始滚动,从而实现了水平滚动的效果。
// 总体来说,tab.scrollLeft++; 表示不断向右滚动一个像素,以实现水平滚动效果。
}
}
var MyMar = setInterval(Marquee, speed); // 使用JS的setInterval内置定时函数,执行Marquee,按照指定的时间间隔(以毫秒为单位)来触发,本例为20ms(传入的参数为:Marquee, speed)
tab.onmouseover = function () {
clearInterval(MyMar); // 鼠标移入时清除定时器,暂停滚动
};
tab.onmouseout = function () {
MyMar = setInterval(Marquee, speed); // 鼠标移出时重新启动定时器,恢复滚动
};
// 初始调用一次Marquee函数,启动滚动
Marquee();
</script>
</body>
</html>