js实现跑马灯效果
使用CSS动画实现跑马灯
通过CSS的@keyframes和animation属性实现横向滚动的文字效果,适用于简单场景。
<style>
.marquee {
width: 100%;
overflow: hidden;
white-space: nowrap;
box-sizing: border-box;
}
.marquee span {
display: inline-block;
padding-left: 100%;
animation: marquee 10s linear infinite;
}
@keyframes marquee {
0% { transform: translateX(0); }
100% { transform: translateX(-100%); }
}
</style>
<div class="marquee">
<span>这是需要滚动的文字内容</span>
</div>
使用JavaScript动态计算位置
通过定时器动态修改元素位置,适合需要精确控制滚动速度和暂停等复杂交互的场景。
function createMarquee(element, speed = 50) {
const container = document.querySelector(element);
const content = container.innerHTML;
container.innerHTML = `<div class="marquee-inner">${content}</div>`;
const inner = container.querySelector('.marquee-inner');
let position = 0;
const timer = setInterval(() => {
position--;
if (-position >= inner.offsetWidth) {
position = container.offsetWidth;
}
inner.style.transform = `translateX(${position}px)`;
}, speed);
return {
stop: () => clearInterval(timer)
};
}
// 使用示例
const marquee = createMarquee('.marquee-container');
// marquee.stop(); 停止滚动
双向循环滚动实现
实现内容首尾相接的无限循环效果,视觉效果更流畅。

function createInfiniteMarquee(selector) {
const container = document.querySelector(selector);
const content = container.innerHTML;
container.innerHTML = `<div class="marquee-wrapper">${content}${content}</div>`;
const wrapper = container.querySelector('.marquee-wrapper');
let animationId;
let position = 0;
const step = () => {
position -= 1;
if (-position >= wrapper.scrollWidth/2) {
position = 0;
}
wrapper.style.transform = `translateX(${position}px)`;
animationId = requestAnimationFrame(step);
};
animationId = requestAnimationFrame(step);
return {
stop: () => cancelAnimationFrame(animationId)
};
}
响应式跑马灯组件
封装成可复用的Vue组件,支持动态内容和响应式尺寸。
Vue.component('marquee', {
template: `
<div class="marquee-container" ref="container">
<div class="marquee-content" :style="contentStyle">
<slot></slot>
</div>
</div>
`,
props: {
speed: { type: Number, default: 1 },
direction: { type: String, default: 'left' }
},
data() {
return {
position: 0,
animationId: null,
containerWidth: 0,
contentWidth: 0
};
},
computed: {
contentStyle() {
return {
transform: `translateX(${this.position}px)`
};
}
},
mounted() {
this.initSize();
window.addEventListener('resize', this.initSize);
this.startAnimation();
},
beforeDestroy() {
window.removeEventListener('resize', this.initSize);
cancelAnimationFrame(this.animationId);
},
methods: {
initSize() {
this.containerWidth = this.$refs.container.offsetWidth;
this.contentWidth = this.$refs.container.querySelector('.marquee-content').scrollWidth;
},
startAnimation() {
const step = () => {
this.position -= this.speed;
if (-this.position >= this.contentWidth) {
this.position = this.containerWidth;
}
this.animationId = requestAnimationFrame(step);
};
this.animationId = requestAnimationFrame(step);
}
}
});
性能优化建议
使用transform代替left/top定位,触发GPU加速提升性能

对于大量内容的跑马灯,考虑使用Canvas渲染替代DOM操作
监听页面可见性变化,当页面不可见时暂停动画节省资源
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
cancelAnimationFrame(animationId);
} else {
animationId = requestAnimationFrame(step);
}
});






