Vue Snackbar 消息条队列显示,依次动画消失的实现

vue

效果预览

思路

  1. 封装 Snackbar 组件;
  2. 在根路由页面下建立全局 Snackbar 控制器,统一管理 Snackbar;
  3. 通过事件通知全局 Snackbar 控制器显示消息;

实现

1. 封装 Snackbar 组件

project/src/components/snackbar.vue

<template>

<div class="component-snackbar" v-if="value">

<div class="snackbar-content">{{ message }}</div>

<div class="snackbar-close" v-if="closable" @click="close">关闭</div>

</div>

</template>

<script>

export default {

name: "component-snackbar",

props: {

value: Boolean, // 调用本组件v-model传入的值

message: String, // 消息内容

closable: { // 是否显示删除按钮

type: Boolean,

default: false

}

},

data: function() {

return {

showTime: 6000, // snackbar显示的时长

timer: null // 定时器

}

},

mounted() {

// 在 showTime 到期后自动关闭snackbar

this.timer = setTimeout(() => {

this.close()

}, this.showTime)

},

methods: {

close() {

// 清除定时器

clearTimeout(this.timer)

// 不能直接在组件中修改props中的数据,因此不能直接修改this.value = false

// 而是实现了在自定义组件中使用v-model,通过外传 input 事件通知调用者自动更新 v-model 传入的值

this.$emit('input', false)

}

}

}

</script>

<style lang="less">

.component-snackbar {

width: 400px;

height: 60px;

position: fixed;

right: 10px;

bottom: 10px;

display: flex;

flex-direction: row;

align-items: center;

border-radius: 8px;

background-color: #333333;

box-shadow: 2px 4px 6px 0 rgba(0,0,0,.4);

transition: transform 500ms ease-in;

.snackbar-content {

flex: 1;

overflow: hidden;

white-space: nowrap;

text-overflow: ellipsis;

padding: 0 16px;

}

.snackbar-close {

margin: 0 16px;

color: deeppink;

cursor: pointer;

}

}

</style>

2. 全局 Snackbar 控制器

注册事件总线 EventBus;

project/src/main.js

import Vue from 'vue'

import App from './App.vue'

import router from './router'

import store from './store'

Vue.config.productionTip = false

// 创建 Vue 的实例作为事件总线使用,将其挂载到 $eventBus 上,

// 即可在组件中直接使用 this.$eventBus.$emit() 和 this.$eventBus.$on() 来触发/监听事件

Vue.prototype.$eventBus = new Vue()

new Vue({

router,

store,

render: h => h(App)

}).$mount('#app')

全局 Snackbar 控制器

全局 Snackbar 控制器在根路由页面下监听 showSnackbar 事件,并维护一个消息列表,通过对事件的监听有序的推入、删除消息,从而达到控制 Snackbar 显示的目的;

project/src/App.vue

<template>

<div >

<router-view />

<!-- 全局 Snackbar 队列 -->

<!-- 根据当前 Snackbar 的 index 动态计算 Y 方向的位移,达到依次排列的目的 -->

<snackbar

v-model="item.show"

:style="{transform: 'translateY(' + -(60+10) * index + 'px)'}"

:message="item.content"

:closable="item.closable"

v-for="(item, index) in messages"

:key="item.id"

@input="onSnackbarClose($event, index)"></snackbar>

</div>

</template>

<script>

import Snackbar from './components/snackbar'

export default {

name: "app",

components: {

Snackbar

},

data: function() {

return {

messages: [] // 消息队列

}

},

mounted() {

// 全局 Snackbar 控制器事件监听

this.snackbarController()

},

methods: {

snackbarController() {

// 监听 showSnackbar 事件

this.$eventBus.$on('showSnackbar', data => {

// 将收到的message推入messages数组中

this.messages.push({

...data,

show: true

})

})

},

onSnackbarClose(value, index) {

// value 为 Snackbar 组件内部传递出来的

// index 为当前关闭 Snackbar 的 索引

// 删除已关闭的 Snackbar 对应的消息数据

this.messages.splice(index, 1)

}

}

}

</script>

<style lang="less">

* {

box-sizing: border-box;

}

body {

margin: 0;

padding: 0;

background-color: #212121;

color: #cecece;

font-size: 14px;

}

</style>

3. 调用Snackbar

这是一个模拟触发消息的页面;

project/src/views/snackbar.vue

<template>

<div class="view-snackbar">

<div class="wrap">

<input type="text" v-model="msg" class="msg-input" placeholder="说点什么...">

<div class="btn" @click="showMessage">显示消息</div>

</div>

</div>

</template>

<script>

export default {

name: 'view-snackbar',

data: function () {

return {

msg: ''

}

},

methods: {

showMessage() {

// 通过触发 showSnackbar 事件并传递消息参数,从而调用全局 Snackbar

this.$eventBus.$emit('showSnackbar', {

id: new Date().getTime(), // id 用于设置 Snackbar 在 v-for 循环中的 key 属性,避免排序混乱的问题

content: this.msg,

closable: true

})

}

}

}

</script>

<style lang="less">

.view-snackbar {

height: 100vh;

display: flex;

flex-direction: column;

justify-content: center;

align-items: center;

background-image: url(https://img.cc0.cn/pixabay/2019102201563350617.jpg/content);

background-repeat: no-repeat;

background-size: cover;

background-position: center;

.wrap {

width: 240px;

}

.msg-input {

width: 100%;

height: 40px;

color: inherit;

background-color: #333333;

border: 2px solid #444444;

border-radius: 8px;

outline: none;

padding: 0 8px;

}

.btn {

width: 120px;

margin: 20px auto;

padding: 8px 0;

text-align: center;

border-radius: 8px;

background-color: deeppink;

cursor: pointer;

user-select: none;

}

}

</style>

4. 总结

通过上述4步就实现了简单的 Vue Snackbar 消息条队列显示,并且依次动画消失,思路还是很清晰的,主要有3个要点:

  • 使用了全局控制器,并通过事件总线 $eventBus 传递消息;
  • 在自定义组件中使用 v-model 实现 Snackbar 的删除;
  • 利用 Snackbar 索引动态计算 Y 方向上的位移实现 Snackbar 的有序排列;

本教程旨在描述思路,实现比较简单,未做过多封装和定制,希望能帮到有需要的童鞋,如发现任何问题,或有更多实现方式,欢迎一起讨论!

5. 改善

可在本版基础上做更多完善,有兴趣的童鞋可以自己玩玩;

  • Snackbar 渐变出现/消失;
  • 多种高度的 Snackbar 混合使用;


本文出处:https://www.cnblogs.com/zhenfengxun/
本文链接:https://www.cnblogs.com/zhenfengxun/p/12452814.html

以上是 Vue Snackbar 消息条队列显示,依次动画消失的实现 的全部内容, 来源链接: utcz.com/z/378673.html

回到顶部