效果预览

思路

  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 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 混合使用;

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

Vue Snackbar 消息条队列显示,依次动画消失的实现的更多相关文章

  1. 前端基于VUE的v-charts的曲线显示

    目录 前端基于VUE的v-charts的曲线显示 1. 应用背景 2. 分析数据生产者生成 3. 取出数据消费者 4. 前端显示 4.1 安装V-charts插件 4.2 引入veline曲线插件 4 ...

  2. vue 圆形进度条组件解析

    项目简介 本组件是vue下的圆形进度条动画组件 自由可定制,几乎全部参数均可设置 源码简单清晰 面向人群 急于使用vue圆形进度条动画组件的同学.直接下载文件,拷贝代码即可运行. 喜欢看源码,希望了解 ...

  3. Android百度地图开发(五)公交线路详情搜索、多条线路显示

    一.公交线路详情检索 获取公交线路的详情主要分来两步,1.获取公交线路的Uid,2.通过Uid获取公交线路详情. 1.获取公交线路的Uid: /* * 获得公交线路图的Uid,并且根据系Uid发起公交 ...

  4. 让TextView里面的文字逐个显示的动画效果实现(1)

    最近使用TextView时想要实现里面的文字逐个显示的动画效果,就如同打字一样. 主要实现思想:新建一个TextView的派生类,先将要逐个显示的字符串保存变量 mOriginalStr 中,然后启动 ...

  5. HTML5效果:Canvas 实现圆形进度条并显示数字百分比

    实现效果 1.首先创建html代码 <canvas id="canvas" width="500" height="500" styl ...

  6. RabbitMQ基础概念(消息、队列、交换机)

    1.消息的确认 RabbitMQ需要对每一条发送的消息进行确认.消费者必须通过AMQP的basic.ack命令显式地向RabbitMQ发送一个确认,或者在订阅到队列的时候就将auto_ack参数设置为 ...

  7. 基于rabbitMQ 消息延时队列方案 模拟电商超时未支付订单处理场景

    前言 传统处理超时订单 采取定时任务轮训数据库订单,并且批量处理.其弊端也是显而易见的:对服务器.数据库性会有很大的要求,并且当处理大量订单起来会很力不从心,而且实时性也不是特别好 当然传统的手法还可 ...

  8. SpringBoot | 第三十八章:基于RabbitMQ实现消息延迟队列方案

    前言 前段时间在编写通用的消息通知服务时,由于需要实现类似通知失败时,需要延后几分钟再次进行发送,进行多次尝试后,进入定时发送机制.此机制,在原先对接银联支付时,银联的异步通知也是类似的,在第一次通知 ...

  9. 【mq读书笔记】消息消费队列和索引文件的更新

    ConsumeQueue,IndexFile需要及时更新,否则无法及时被消费,根据消息属性查找消息也会出现较大延迟. mq通过开启一个线程ReputMessageService来准时转发commitL ...

随机推荐

  1. [LC] 161. One Edit Distance

    Given two strings s and t, determine if they are both one edit distance apart. Note: There are 3 pos ...

  2. 前端-bootstrap-长期维护

     ###############    bootstrap简介     ################ Bootstrap是Twitter开源的基于HTML.CSS.JavaScript的前端框架. ...

  3. Android下的鉴权实现方案

    软件原理 不赘述,参考: 软件License认证方案的设计思路 License文件离线鉴权 机械指纹,不可逆的加密算法,如MD5 功能鉴权,可逆的不对称加密算法,服务端公钥加密,app端私钥解密,如R ...

  4. String的compareTo用法

    String的compareTo其实就是依次比较两个字符串ASC码.如果两个字符的ASC码相等则继续后续比较,否则直接返回两个ASC的差值.如果两个字符串完全一样,则返回0.来看一下代码. publi ...

  5. 蓝桥杯-PREV28-地宫取宝

    先自己用dp解了一遍,然后看了官方讲解视频是用记忆化搜索做的.感觉那位老师的方法比较容易实现(效率上和我的差不多的):记录一下三种方法. 动态规划 地宫取宝 1.195KB C++ 正确 100 15 ...

  6. django自带数据库sqlite

    python manage.py makemigrations # 记录关于models.py的所有改动,但是还没有作用的数据库文件中 python manage.py migrate # 把mode ...

  7. Web服务器的配置与管理

    Web服务器的配置与管理(2) 虚拟主机技术 在上篇博文中,我们已经利用IIS搭建好了一台Web服务器,并可以成功访问IIS中自带的默认站点,那么我们是否可以在这台服务器中再创建另外一个Web站点?也 ...

  8. ZOJ-1183-Scheduling Lectures

    可以用贪心求最小讲课次数,贪心策略也很好想,就是对于任意主题,能早讲就早讲.这种方案的讲课次数一定是最少的,但是不满意指标不一定是最小,然后再利用动态规划求在最少讲课次数前提下的最小不满意指标. 方法 ...

  9. [USACO5.1] Musical Themes

    后缀数组求最长重复且不重叠子串. poj 1743 传送门 洛谷 P2743 传送门 1.子串可以“变调”(即1 3 6和3 5 8视作相同).解决办法:求字符串相邻元素的差形成新串.用新字符串求解最 ...

  10. spring boot 创建定时任务

    @Scheduled默认创建的线程是单线程,任务的执行会受到上一个任务的影响,创建定时任务也比较简单 123456789101112 @Component@Configuration //1.主要用于 ...