vue中实现文字无缝滚动效果

文字无缝滚动在开发大屏的时候会经常遇到。之前有用到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>