首页 Banner 不是简单的「几张图轮播」,而是「大图 + 侧边导航 + 自动播放 + 手动介入」的复合组件。本文用 JS原生代码实现一条无依赖、可复用、可扩展的影视轮播链路,涵盖数据驱动、事件委托、状态管理三大核心技能。
效果预览

一、数据约定
把后端返回的列表抽象成统一结构:
js
// data.js
const data = [
{
title: "三十而已",
desc: "话题爽剧!姐姐飒气挑战",
img: "https://puui.qpic.cn/media_img/lena/PICgthm4a_580_1680/0",
bg: "rgb(25,117,180)"
},
// ... 更多对象
]
title
:导航主标题desc
:副标题,用于 hover 提示img
:大图地址bg
:背景色,与大图同步切换
二、html骨架
html
<div class="content">
<div class="top-nav"></div>
<div class="imgs" id="imgs">
</div>
<div class="side-bar" id="side-bar">
<a href="#" class="cnhz"> <img src="./img/all.png"> 猜你会追</a>
<a href="#" class="zbtj"> <img src="./img/tj.png"> 重磅推荐</a>
</div>
</div>
三、js链式渲染三步走
1.初始化:生成大图与导航
js
const imgs = document.getElementById('imgs')
const sideBar = document.getElementById('side-bar')
let activeImg = null
let activeNav = null
for (let i = 0; i < data.length; i++) {
const item = data[i]
// 大图 a 标签
const tagA = document.createElement('a')
tagA.href = '#'
tagA.style.backgroundColor = item.bg
tagA.style.backgroundImage = `url(${item.img})`
imgs.appendChild(tagA)
// 导航 a 标签
const tagNav = document.createElement('a')
tagNav.href = '#'
tagNav.className = 'nav'
tagNav.title = `${item.title}: ${item.desc}`
tagNav.innerHTML = `<span>${item.title}</span> ${item.desc}`
sideBar.appendChild(tagNav)
// 第一个元素默认激活
if (i === 0) {
tagA.className = 'active'
tagNav.className = 'active'
activeImg = tagA
activeNav = tagNav
}
}
一次循环同时生成两张「a」:左侧大图与右侧导航,减少遍历次数。
2.鼠标介入:hover 即切换
js
tagNav.onmouseenter = function () {
clearInterval(t) // 暂停自动播放
// 取消旧活跃
activeNav.className = 'nav'
activeImg.className = ''
// 激活当前
this.className = 'active'
tagA.className = 'active'
// 更新指针
activeNav = this
activeImg = tagA
}
使用
onmouseenter
而非onmouseover
,避免子元素冒泡导致频繁触发。
3.自动播放:定时器 + 索引循环
js
function move() {
// 取消旧活跃
activeNav.className = 'nav'
activeImg.className = ''
// 找到下一个
const index = Array.from(imgs.children).indexOf(activeImg)
const nextIndex = (index + 1) % data.length
// 激活下一个
activeImg = imgs.children[nextIndex]
activeNav = sideBar.children[nextIndex + 2] // 跳过两个标题
activeImg.className = 'active'
activeNav.className = 'active'
}
let t = setInterval(move, 3000)
nextIndex = (index + 1) % data.length
实现首尾循环;nextIndex + 2
跳过「猜你会追」和「重磅推荐」两个标题节点。
四、边界与优化细节
1.鼠标离开继续自动播放
js
tagNav.onmouseleave = () => {
t = setInterval(move, 3000)
}
2.背景色同步切换
大图 a
的 backgroundColor
直接读取 item.bg
,避免额外计算。
3.长文字截断
CSS 设置 white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
,hover 时通过 title
属性展示完整标题。
4.无闪烁切换
display: none ↔ block
瞬间完成,背景图预加载,肉眼无闪屏。