JavaScript轮播图添加每页进度条 width属性设置报错解决方案
问题根因
你遇到的cannot set properties of undefined (setting 'width')错误来自几个核心问题:
document.getElementsByClassName('progress-line')返回的是包含所有匹配元素的类数组集合,不是单个DOM节点,集合本身没有style属性,直接访问elem.style自然会得到undefined- 进度条逻辑没有做重置处理:每次轮播切换时没有清空上一轮的进度定时器、没有把进度条宽度归零,会导致多个定时器冲突、进度条显示错乱
- 额外小问题:
timeLine函数定义时没有设置形参,但调用时传入了slide参数,属于冗余代码;进度条缺少固定定位,会跟随轮播动画移位。
修正后可运行代码
HTML部分
<div class="carousel"> <div class="progress-line"></div> <div class="carousel-item"> <div class="red"></div> </div> <div class="carousel-item"> <div class="green"></div> </div> <div class="carousel-item"> <div class="yellow"></div> </div> <div class="carousel-item"> <div class="violet"></div> </div> </div>
CSS部分
*{box-sizing: border-box;} .carousel { position: relative; width: 400px; height: 270px; overflow: hidden; } .carousel-item { display: none; flex-direction: column; position: absolute; width: 100%; height: 100%; border: none; } .progress-line { position: absolute; width: 0%; height: 2px; background-color: black; z-index: 9; top: 0; left: 0; } .active-carousel { display: flex; animation-name: slide-in; animation-duration: 1s; } @keyframes slide-in { 0% {display: none; bottom: 100%;} 1% {display: flex; bottom: 100%;} 100% {display: flex; bottom: 0%;} } .show-carousel { display: flex; animation-name: slide-out; animation-duration: 1.1s; } @keyframes slide-out { 0% {display: flex; bottom: 0%;} 99% {display: flex; bottom: -100%;} 100% {display: none; bottom: -100%;} } div {height: 100%;} .red {background-color: red;} .green {background-color: green;} .yellow {background-color: yellow;} .violet {background-color: violet;}
JS部分
window.onload = function() { var slides = document.getElementsByClassName('carousel-item'), progressBar = document.querySelector('.progress-line'), addActive = function(slide) {slide.classList.add('active-carousel')}, removeActive = function(slide) {slide.classList.remove('active-carousel')}, time = 3000, progressTimer = null, timeLine = function() { // 每次启动进度条前先清空旧状态 clearInterval(progressTimer); var width = 0; progressBar.style.width = '0%'; progressTimer = setInterval(function() { if(width >= 100) { clearInterval(progressTimer); } else { width++; progressBar.style.width = width + "%"; } }, time/100); }; addActive(slides[0]); timeLine(); // 初始化第一页时就启动进度条 setInterval(function () { for (var i = 0; i < slides.length; i++){ if (i + 1 == slides.length) { addActive(slides[0]); timeLine(); slides[0].style.zIndex = 3; slides[i].classList.add('show-carousel'); setTimeout(function() { slides[i].classList.remove('show-carousel'); },1000); setTimeout(removeActive, 500, slides[i]); break; } if (slides[i].classList.contains('active-carousel')) { slides[i].classList.add('show-carousel'); timeLine(); setTimeout(function() { slides[i].classList.remove('show-carousel'); },1000); slides[i].removeAttribute('style'); setTimeout(removeActive, 500, slides[i]); addActive(slides[i + 1]); break; } } }, time); }
关键修改点说明
- 把获取进度条的方式改成
document.querySelector('.progress-line'),直接拿到单个DOM元素,从根源解决原报错 - 新增全局变量存储进度条定时器ID,每次启动进度条前先清除旧定时器、重置进度条宽度为0,避免多定时器冲突导致的进度跳变问题
- 给进度条增加
top:0、left:0定位属性,固定在轮播容器顶部,不会跟随轮播项的进出动画移位 - 初始化加载第一页时就启动进度条,保证第一次轮播停留时也有正常的进度效果
- 移除了
timeLine函数调用时多余的传参,精简冗余逻辑
内容的提问来源于stack exchange,提问作者Khrisna Mahendra
相关产品推荐
相关产品推荐

