vue 一行显示的动态消息
动态消息上翻显示
效果图
特点:
- 重复的信息,只显示一次
- 全部信息显示完后,只在轮播最后一个消息队列
- 若最后一个消息队列只有一条信息,则停止轮播,不轮播
- 新的消息队列进入后,触发新的轮播
<template><div class="message-list"><divv-for="(message, index) in messagesShow":key="index":class="['message-item',{ translateYing: index == 0 && translateYing },]"><slot v-bind="message">{{message}}</slot></div></div>
</template><script>
export default {props: {translateY: {type: Number,default: 22,},// 推送的消息messages: {type: Array,required: true,default: () => [],},// 静态展示时长newShowTime: {type: Number,default: 8,},// 动画切换时长newChangeTime: {type: Number,default: 1,},// 下一条是否取最新的isNewNews: {type: Boolean,default: true,}},data() {return {messagesShow: [],messagesStack: [],translateYing: false,isInAnimatingProgress: false,newShowedEnums: {},}},watch: {messages: {handler(newVal = []) {this.addMessage(newVal)},immediate: true,},},created() {// 测试 工具window.messageListCom = thiswindow.addMessage = this.addMessage/** mock 生成数组 */function mockArr(count = 10, cb = (id) => ({ id })) {return new Array(count).fill(undefined).map((item, index) => cb(index, index))}window.mockArr = mockArrconsole.log('示例 mockArr(10,(id)=>id)',mockArr())},methods: {updateNewShowedEnums(item) {const identificationKey = itemif (!this.newShowedEnums[identificationKey]) {this.newShowedEnums[identificationKey] = truereturn true}// console.log('已收集过的', item)return false},getNextNew() {if (this.isNewNews) {return this.messagesStack.pop()}return this.messagesStack.shift()},newMessageEmit() {if (!this.isInAnimatingProgress) {console.log(`新消息触发了动画 => %O `)this.animate()}},animate() {if (this.messagesShow.length === 0 && this.messagesStack.length) {this.messagesShow.push(this.getNextNew())}if (this.messagesShow.length === 1) {this.isInAnimatingProgress = truethis.setTimeoutId = setTimeout(() => {// console.log(`测试定时器离开页面后,是否仍在执行:this.setTimeoutId`)if (!this.messagesStack.length) {if (this.isTwoTimesShowLastMessages && this.messages.length == 1) {// 如果已完整的展示最后的消息队列一次,切且该队列只有一条消息就不再轮播this.isInAnimatingProgress = falsereturn}console.log('第 n 次,展示最后消息队列')this.isTwoTimesShowLastMessages = truethis.messagesStack = [...this.messages]// 清空去重的标识,避免页面长时间停留导致过占用this.newShowedEnums = {}this.messagesStack.forEach(this.updateNewShowedEnums)}if (this.messagesStack.length) {this.messagesShow.push(this.getNextNew())this.animate()}}, this.newShowTime * 1000)}if (this.messagesShow.length >= 2) {this.translateYing = truethis.setTimeoutId2 = setTimeout(() => {// console.log(`测试定时器离开页面后,是否仍在执行:this.setTimeoutId2`)this.translateYing = falsethis.messagesShow.shift()this.animate()}, (this.newChangeTime + 0.5) * 1000)}},addMessage(newVal = []) {this.messagesUniques = newVal.filter(this.updateNewShowedEnums)if (this.messagesUniques.length) {if (this.isTwoTimesShowLastMessages) {// 整个信息栈结束过// 以前的队列已每条都展示过,则直接以最新消息开始轮播this.messagesStack = [...this.messagesUniques]} else if (!this.messagesStack.length) {// 以前的队列已每条都展示过,则直接以最新消息开始轮播this.messagesStack = [...this.messagesUniques]} else {this.messagesStack = this.messagesStack.concat(this.messagesUniques)this.isTwoTimesShowLastMessages = false}this.newMessageEmit()}},},beforeUnmount() {clearTimeout(this.setTimeoutId)clearTimeout(this.setTimeoutId2)},
}
</script><style scoped>
.message-list {width: 300px;height: 22px;overflow-y: hidden;line-height: v-bind(translateY + 'px');.message-item {&.translateYing {margin-top: v-bind((-translateY) + 'px');transition: v-bind(newChangeTime + 's');}}
}
</style>