Vue Snackbar 消息条队列显示,依次动画消失的实现
Posted zhenfengxun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue Snackbar 消息条队列显示,依次动画消失的实现相关的知识,希望对你有一定的参考价值。
Vue Snackbar 消息条队列显示,依次动画消失的实现
效果预览
思路
- 封装 Snackbar 组件;
- 在根路由页面下建立全局 Snackbar 控制器,统一管理 Snackbar;
- 通过事件通知全局 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 id="app">
<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 混合使用;
以上是关于Vue Snackbar 消息条队列显示,依次动画消失的实现的主要内容,如果未能解决你的问题,请参考以下文章
Android:MVVM 是不是可以显示来自 ViewModel 的消息(toast/snackbar 等)
在 RecyclerView 中配置 ItemTouchHelper 以使 Snackbar 被显示的另一个 Snackbar 解散