vue中实现文字无缝滚动效果
- Vue
- 2025-06-25
- 28热度
文字无缝滚动在开发大屏的时候会经常遇到。之前有用到marquee,但是它的效果有点差强人意,之后找到了一款非常好用的插件-vue-seamless-scroll。它不仅可以上下左右滚动,还可以实现单步停顿。基本上会符合我们的需求。如果有特殊的需求,可以自行封装自己的组件。
下面就介绍几种文字无缝滚动的方法,给大家提供多种思路参考。如果没有特别需求的话,还是vue-seamless-scroll 简单方便,滚动又丝滑。
vue-seamless-scroll
安装依赖:vue2与vue3略有不同
//vue2
npm install vue-seamless-scroll --save
//vue3
npm install vue3-seamless-scroll --save
全局引入组件
//vue2
import scroll from 'vue-seamless-scroll'
Vue.use(scroll)
//vue3
import { createApp } from 'vue';
import App from './App.vue';
import vue3SeamlessScroll from "vue3-seamless-scroll";
const app = createApp(App);
app.use(vue3SeamlessScroll);
app.mount('#app');
组件使用,配置相关属性
主要是控制外层容器的高度。如果希望有更多的配置,可以去官网查看,总有你需要的。官网地址:https://chenxuan0000.github.io/vue-seamless-scroll/zh/guide/
vue2示例:
<template>
<vue-seamless-scroll :data="listData" class="seamless-warp">
<div class="item">
<li v-for="(item, index) in listData" :key="index">
<span class="title" v-text="item.title"></span>
<span class="date" v-text="item.date"></span>
</li>
</div>
</vue-seamless-scroll>
</template>
<style scoped>
.seamless-warp {
height: 229px;
overflow: hidden;
}
</style>
<script>
export default {
data() {
return {
listData: [
{ title: "无缝滚动第一行无缝滚动第一行", date: "2017-12-16" },
{ title: "无缝滚动第二行无缝滚动第二行", date: "2017-12-16" },
{ title: "无缝滚动第三行无缝滚动第三行", date: "2017-12-16" },
{ title: "无缝滚动第四行无缝滚动第四行", date: "2017-12-16" },
{ title: "无缝滚动第五行无缝滚动第五行", date: "2017-12-16" },
{ title: "无缝滚动第六行无缝滚动第六行", date: "2017-12-16" },
{ title: "无缝滚动第七行无缝滚动第七行", date: "2017-12-16" },
{ title: "无缝滚动第八行无缝滚动第八行", date: "2017-12-16" },
{ title: "无缝滚动第九行无缝滚动第九行", date: "2017-12-16" },
],
};
},
};
</script>
vue3示例:
<template>
<vue3-seamless-scroll :list="state.list" class="scroll" :step="0.5" hover="true">
<div class="item" v-for="(item, index) in state.list" :key="index">
<span>{{ item.title }}</span>
<span>{{ item.date }}</span>
</div>
</vue3-seamless-scroll>
</template>
<script setup>
import { ref, reactive, onMounted } from "vue";
const state = reactive({
list: [
{ title: "无缝滚动第一行无缝滚动第一行", date: "2017-12-16" },
{ title: "无缝滚动第二行无缝滚动第二行", date: "2017-12-16" },
{ title: "无缝滚动第三行无缝滚动第三行", date: "2017-12-16" },
{ title: "无缝滚动第四行无缝滚动第四行", date: "2017-12-16" },
{ title: "无缝滚动第五行无缝滚动第五行", date: "2017-12-16" },
{ title: "无缝滚动第六行无缝滚动第六行", date: "2017-12-16" },
{ title: "无缝滚动第七行无缝滚动第七行", date: "2017-12-16" },
{ title: "无缝滚动第八行无缝滚动第八行", date: "2017-12-16" },
{ title: "无缝滚动第九行无缝滚动第九行", date: "2017-12-16" },
],
});
</script>
<style lang="less" scoped>
.scroll {
height: 200px;
width: 500px;
margin: 100px auto;
overflow: hidden;
}
.scroll .item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 3px 0;
}
</style>
相关配置如下图:

css动画实现无缝滚动
这个方法不是一个太有效的方法,第一屏还滚动还比较丝滑,但是循环时会出现空白现象,体感不太好。适合新手练练CSS动画。https://wxa.wxs.qq.com/tmpl/lz/base_tmpl.html
<template>
<div class="b_list">
<div class="b_scroll">
<div class="b_item" v-for="(item, index) in newsList" :key="acindex">
<div class="content">
<div class="title">{{ item.title }}</div>
<div class="des">{{ item.description }}</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "scrolling",
data() {
return {
newsList: [
{ id: 1, title: "第一条", description: "第一条消息的内容。" },
{ id: 2, title: "第二条", description: "第二条消息的内容。" },
{ id: 3, title: "第三条", description: "第三条消息的内容。" },
{ id: 4, title: "第四条", description: "第四条消息的内容。" },
],
};
},
methods: {},
};
</script>
<style lang="less" scoped>
@keyframes scrollTop {
0% {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
100% {
-webkit-transform: translate3d(0, -300px, 0);
transform: translate3d(0, -300px, 0);
}
}
.b_list {
height: 100px;
overflow: hidden;
border: 1px solid #000;
}
.b_scroll {
-webkit-animation: 10s scrollTop linear infinite normal;
animation: 10s scrollTop linear infinite normal;
}
</style>
使用scrollTop方法向上滚动
这个方法的缺点是循环不了,到底就不动了。哪位宝子可以偿试循环滚动下哈哈。思路是:复制一个分身,放在本体后面,这样首尾就会衔接起来,当分身滚动到底部时回到顶部,此时呢,本体刚好替代分身的位置继续滚动,开始下一波循环,看起来效果就是无缝滚动。
<template>
<div class="b_list">
<div class="b_scroll" id="list" style="height: 100px; overflow: hidden">
<div class="b_item" v-for="(item, index) in newsList" :key="index">
<div class="content">
<div class="title">{{ item.title }}</div>
<div class="des">{{ item.description }}</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "scrolling",
data() {
return {
newsList: [
{ id: 1, title: "第一条", description: "第一条消息的内容。" },
{ id: 2, title: "第二条", description: "第二条消息的内容。" },
{ id: 3, title: "第三条", description: "第三条消息的内容。" },
{ id: 4, title: "第四条", description: "第四条消息的内容。" },
],
scrollInterval: null,
scrollTop: 0,
};
},
mounted() {
this.scrolltolowerOne();
},
methods: {
scrolltolowerOne() {
this.scrollInterval = setInterval(() => {
let div = document.getElementById("list");
if (div) {
if (div.scrollTop + div.offsetHeight >= div.scrollHeight) {
this.scrollTop = 0;
} else {
this.scrollTop += 1;
}
div.scrollTop = this.scrollTop;
} else {
clearInterval(this.scrollInterval);
this.scrollInterval = null;
}
}, 50);
},
},
};
</script>
鼠标悬停时暂停滚动并且可以鼠标滚轮滚动
同上,只循环一扁。但是可以悬停,可以手动上下滚动。
<template>
<div id="container" @mouseover="stopScroll" @mouseout="resumeScroll">
<div id="content">
<!-- 内容 -->
<div class="news_name" v-for="(item, index) in newsList" :key="item.id">
<div class="content">
<div class="title">{{ item.title }}</div>
<div class="des">{{ item.description }}</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
container: null, // DOM元素
isHovered: false, //滚动
scrollInterval: null, // 定时器
newsList: [
{ id: 1, title: '第一条', description: '第一条消息的内容。' },
{ id: 2, title: '第二条', description: '第二条消息的内容。' },
{ id: 3, title: '第三条', description: '第三条消息的内容。' },
{ id: 4, title: '第四条', description: '第四条消息的内容。' },
{ id: 5, title: '第五条', description: '第五条消息的内容。' },
{ id: 6, title: '第六条', description: '第六条消息的内容。' },
{ id: 7, title: '第七条', description: '第七条消息的内容。' },
{ id: 8, title: '第八条', description: '第八条消息的内容。' }]
};
},
mounted() {
this.container = document.getElementById('container');
this.startScroll();
},
methods: {
startScroll() {
if (!this.isHovered) {
this.scrollInterval = setInterval(() => {
this.container.scrollTop += 1; // 向上滚动的速度
// // 获取指定区域的高度
const elementHeight = this.container.clientHeight;
// 获取指定区域内文档内容的总高度
const contentHeight = this.container.scrollHeight;
// 获取指定区域的滚动位置
const scrollPosition = this.container.scrollTop;
// 计算滚动条距离底部的距离
const distanceToBottom = contentHeight - elementHeight - scrollPosition;
if (distanceToBottom === 0) { this.container.scrollTop = 0; }
}, 50); // 滚动间隔,单位毫秒
}
},
// 当鼠标指针进入后触发
stopScroll() {
this.isHovered = true;
clearInterval(this.scrollInterval);
this.container.addEventListener('wheel', this.handleWheel);
},
// 根据鼠标滚轮事件的滚动距离,将滚动容器的滚动位置向上或向下调整一定的距离
handleWheel(event) {
this.container.scrollTop += event.deltaY * 0.2;
// 阻止浏览器对滚轮事件的默认处理方式
event.preventDefault();
},
// 当鼠标指针离开时触发
resumeScroll() {
this.isHovered = false;
this.container.removeEventListener('wheel', this.handleWheel);
this.startScroll();
}
}
};
</script>
<style scoped>
#container {
width: 100%;
height: calc(100% - 21px);
/* overflow-y: auto; */
overflow-y: hidden;
}
#content {
height: 200px;
/* 模拟内容比容器高的情况 */
}
</style>
单条跳着滚动
这个主要是针对单个item向上跳着滚动,且循环滚动。动画效果还需要再优化一下,目前是有点生硬的。
<template>
<div class="wrapper">
<div
:class="{ anim: animate }"
@mouseenter="stop()"
@mouseleave="up()"
class="unreadMsg"
>
<div class="news_name" v-for="(item, index) in newsList" :key="item.id">
<div class="content">
<div class="title">{{ item.title }}</div>
<div class="des">{{ item.description }}</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "scrolling",
data() {
return {
timer: null,
animate: false,
newsList: [
{ id: 1, title: "第一条", description: "第一条消息的内容。" },
{ id: 2, title: "第二条", description: "第二条消息的内容。" },
{ id: 3, title: "第三条", description: "第三条消息的内容。" },
{ id: 4, title: "第四条", description: "第四条消息的内容。" },
],
};
},
mounted() {
this.scrollUp(); // 开启滚动效果
},
beforeDestroy() {
this.stop();
},
methods: {
// 滚动动画
scrollUp() {
// 每个消息展示10s
this.timer = setInterval(() => {
this.animate = true;
// 向上滚动的时候需要添加动画
setTimeout(() => {
this.newsList.push(this.newsList[0]); // 将数组的第一个元素添加到数组最后一个
this.newsList.shift(); // 删除数组的第一个元素
this.animate = false;
}, 500);
}, 5000);
},
// 鼠标移上去停止
stop() {
clearInterval(this.timer);
},
// 鼠标离开继续
up() {
this.scrollUp();
},
},
};
</script>
<style lang="less" scoped>
.wrapper {
height: 132px;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
border: 1px solid #ccc;
}
.unreadMsg {
overflow: hidden;
height: 132px;
text-align: center;
.news_name {
line-height: 30px;
transition: top 0.5s;
transition-delay: 10s;
.content {
width: 384px;
height: 132px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
overflow: hidden;
word-wrap: break-word;
background: #fff;
border-radius: 8px;
border: 1px solid #000;
box-sizing: border-box;
.title {
padding-right: 12px;
margin-bottom: 8px;
color: rgba(0, 0, 0, 0.88);
font-size: 16px;
line-height: 1.5;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.des {
font-size: 14px;
cursor: pointer;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
}
}
}
.anim {
transition: all 0.5s;
margin-top: -110px;
}
</style>