消息通知无缝滚动

发布时间 2023-03-30 14:05:32作者: 蛙仔

开发项目时候,有个需要是对于未读消息进行一个纵向的轮播,播到某条消息时,需要停留一会会。

 

 

 

  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 
 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);
 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>