消息通知无缝滚动
开发项目时候,有个需要是对于未读消息进行一个纵向的轮播,播到某条消息时,需要停留一会会。
1 <template> 2 <div class="module"> 3 <div class="list-wrap"> 4 <img class="vocal" src="@/assets/home/vocal.png" alt="" /> 5 <div class="notices-list-wrap"> 6 <div 7 class="notices-list-content" 8 :style="{transform: `translateY(${-(listActiveIndex * parseFloat(itemHeight))}px)`}" 9 > 10 <!-- 所有消息for循环 --> 11 <div class="text text-ellipsis" v-for="(notic, index) in state.list" :key="index"> 12 {{ notic.messageTitle }} 13 </div> 14 <!-- 为了无缝,需要重复第一条 --> 15 <div class="text text-ellipsis" v-for="(notic, index) in [state.list[0]].filter((one) => one)" :key="index"> 16 {{ notic.messageTitle }} 17 </div> 18 </div> 19 </div> 20 <img class="link" src="@/assets/home/link.png" alt="" @click="linkClick" /> 21 </div> 22 </div> 23 </template> 24 <script setup> 25 import {onMounted, reactive, ref, watch} from 'vue'; 26 const state = reactive({ 27 list: [], 28 }); 29 const isScroll = ref(true);// 是否允许滚动不暂停 30 const listActiveIndex = ref(-1); // 当前展示的下标 31 const itemHeight = '22px'; // 每条消息的高度,这个还可用于下面style作为样式变量 32 const transition = ref('all 0.5s ease'); 33 let timer = null; 34 const setTimer = () => { 35 timer && clearInterval(timer); 36 timer = setInterval(() => { 37 transition.value = 'all 0.5s ease'; 38 clearInterval(timer);
// 有些情况可能需要暂停不滚动,比如鼠标悬浮之类的,这个看具体业务
if(!isScroll.value&&listActiveIndex.value>-1){
this.setTimer();
return
}
39 listActiveIndex.value++; 40 /* setTimeout用于停留在某个消息上,设置的是停留1500ms */ 41 setTimeout(() => { 42 /* 这个是关键!!! 如果已经滚动最后一条,需要修改下标为0,这时候还需要把动画去掉,不然动画会错乱!!! */ 43 if (listActiveIndex.value === state.list.length) { 44 transition.value = 'all 0s ease'; 45 listActiveIndex.value = 0; 46 } 47 setTimer(); 48 }, 1500); 49 }, 500); 50 }; 51 const getlist = () => { 52 let title = '我是消息滚动'; 53 for (let i = 0; i < 5; i++) { 54 state.list.push({messageTitle: i + 1 + title}); 55 } 56 listActiveIndex.value = -1; 57 setTimer(); 58 }; 59 onMounted(() => { 60 getlist(); 61 }); 62 const itemClick = (item) => {}; 63 </script> 64 <style lang="less" scoped> 65 .module { 66 box-sizing: border-box; 67 background: green; 68 padding: 30px 0; 69 .list-wrap { 70 display: flex; 71 align-items: center; 72 width: 100%; 73 box-sizing: border-box; 74 height: 40px; 75 border-radius: 20px; 76 padding: 0 12px; 77 background: #fff; 78 img { 79 &.vocal { 80 width: 29px; 81 height: 21px; 82 margin-right: 7px; 83 } 84 &.link { 85 width: 20px; 86 height: 20px; 87 } 88 } 89 .notices-list-wrap { 90 flex: 1; 91 overflow: hidden; 92 height: v-bind(itemHeight); 93 .notices-list-content { 94 transition: v-bind(transition); 95 .text { 96 font-size: 14px; 97 font-weight: 400; 98 color: #303133; 99 line-height: v-bind(itemHeight); 100 } 101 } 102 } 103 } 104 } 105 </style>