vue从零实现一个消息通知组件的方法详解


Posted in Javascript onMarch 16, 2020

本文实例讲述了vue从零实现一个消息通知组件的方法。分享给大家供大家参考,具体如下:

利用vue从零实现一个消息通知组件

平时,我们肯定用过类似element-ui,antd等一些UI框架,感受它们带给我们的便利。但当我们的需求或者设计这些框架内置的相差太大,用起来,就会觉得特别别扭,这时候,就有必要自己来重新造轮子。

重新造轮子,有几个好处,1.所有代码都是服务你的业务,没有太多用不上的东西。2.代码是由自己维护,而不是第三方,方便维护。3.提升自己的视野,让自己站在更高的角度来看问题。

好了,那话不多说,开始我们的组件开发吧!

文件目录的组件

工欲善其事,必先利其器,要想实现一个组件,一个好的目录结构,即可以划分职责,不同模块处理不同的逻辑!

我的目录结果是这样的:
vue从零实现一个消息通知组件的方法详解

接下来,我们依次对notification.vue, notify.js, index.js三个文件作介绍。

notification.vue

notification.vue是一个负责消息通知组件的视觉呈现,里面的逻辑很简单。

<template>
 <transition name="fade" @after-enter="handleAfterEnter">
  <div class="notification" :style="style" v-show="visible">
   <span class="notification__content">
    {{content}}
   </span>
   <span class="notification__btn" @click="handleClose">{{btn}}</span>
  </div>
 </transition>
</template>
<script>
export default {
 name: 'Notification',
 props: {
  content: {
   type: String,
   required: true
  },
  btn: {
   type: String,
   default: '关闭'
  }
 }
}
</script>
<style lang="less" scoped>
.fade-enter-active, .fade-leave-active{
 transition: opacity 1s;
}
.fade-enter, .fade-leave-to{
 opacity: 0;
}
.notification{
 display: flex;
 background-color: #303030;
 color: rgba(255, 255, 255, 1);
 align-items: center;
 padding: 20px;
 position: fixed;
 min-width: 280px;
 box-shadow: 0 3px 5px -1px rgba(0, 0, 0, 0.2), 0px 6px 10px 0px rgba(0, 0, 0, 0.3);
 flex-wrap: wrap;
 transition: all 0.3s;
 &__content{
  padding: 0;
 }
 &__btn{
  color: #ff4081;
  padding-left: 24px;
  margin-left: auto;
  cursor: pointer;
 }
}
</style>

notify.js

notify.js是一个处理消息通知组件的逻辑部分,其主要作用是暴露一个notify的方法出去。代码如下:

import Vue from 'vue'
import Notification from './notification'

const NotificationConstructor = Vue.extend(Notification)

const instances = []
let seed = 1
const removeInstance = (instance) => {
 if (!instance) return
 const len = instances.length
 const index = instances.findIndex(ins => instance.id === ins.id)

 instances.splice(index, 1)

 if (len <= 1) return
 const removeHeight = instance.height
 for (let i = index; i < len - 1; i++) {
  instances[i].verticalOffset = parseInt(instances[i].verticalOffset) - removeHeight - 16
 }
}
const notify = (options = {}) => {
 if (Vue.prototype.$isServer) return
 // 获取vue实例
 let instance = new NotificationConstructor({
  propsData: options,
  data() {
   return {
    verticalOffset: 0,
    timer: null,
    visible: false,
    height: 0
   }
  },
  computed: {
   style() {
    return {
     position: 'fixed',
     right: '20px',
     bottom: `${this.verticalOffset}px`
    }
   }
  },
  mounted() {
   this.createTimer()
   this.$el.addEventListener('mouseenter', () => {
    if (this.timer) {
     this.clearTimer(this.timer)
    }
   })
   this.$el.addEventListener('mouseleave', () => {
    if (this.timer) {
     this.clearTimer(this.timer)
    }
    this.createTimer()
   })
  },
  updated() {
   this.height = this.$el.offsetHeight
  },
  beforeDestroy() {
   this.clearTimer()
  },
  methods: {
   createTimer() {
    this.timer = setTimeout(() => {
     this.visible = false
     document.body.removeChild(this.$el)
     removeInstance(this)
     this.$destroy()
    }, options.timeout || 3000)
   },
   clearTimer() {
    if (this.timer) {
     clearTimeout(this.timer)
    }
   },
   handleClose() {
    this.visible = false
    document.body.removeChild(this.$el)
    removeInstance(this)
    this.$destroy(true)
   },
   handleAfterEnter() {
    // eslint-disable-next-line no-debugger
    this.height = this.$el.offsetHeight
   }
  }
 })

 const id = `notification_${seed++}`
 instance.id = id
 // 生成vue中的$el
 instance = instance.$mount()
 // 将$el中的内容插入dom节点中去
 document.body.appendChild(instance.$el)
 instance.visible = true

 // eslint-disable-next-line no-unused-vars
 let verticalOffset = 0

 instances.forEach(item => {
  verticalOffset += item.$el.offsetHeight + 16
 })

 verticalOffset += 16
 instance.verticalOffset = verticalOffset

 instances.push(instance)

 return instance
}

export default notify

index.js

index.js主要是对notification.vue组件实现注册,notify方法的挂载。代码如下:

import Notification from './notification'
import notify from './notify'

export default (Vue) => {
 Vue.component(Notification.name, Notification)
 Vue.prototype.$notify = notify
}

在main.js引入

import Notification from './components/notification'
Vue.use(Notification)

使用

this.$notify({
 content: 'Hello'
})

效果

vue从零实现一个消息通知组件的方法详解

希望本文所述对大家vue.js程序设计有所帮助。

Javascript 相关文章推荐
基于Jquery制作的幻灯片图集效果打包下载
Feb 12 Javascript
动感效果的TAB选项卡jquery 插件
Jul 09 Javascript
Vue.js实现拖放效果的实例
Sep 30 Javascript
Javascript 动态改变imput type属性
Nov 01 Javascript
html5 canvas 详细使用教程
Jan 20 Javascript
jQuery 循环遍历改变a标签的href(实例讲解)
Jul 12 jQuery
解决Jstree 选中父节点时被禁用的子节点也会选中的问题
Dec 27 Javascript
Vue常见面试题整理【值得收藏】
Sep 20 Javascript
vue开发环境配置跨域的方法步骤
Jan 16 Javascript
vuex state中的数组变化监听实例
Nov 06 Javascript
微信小程序实现列表滚动头部吸顶的示例代码
Jul 12 Javascript
JavaScript实现动态留言板
Mar 16 #Javascript
vue中的双向数据绑定原理与常见操作技巧详解
Mar 16 #Javascript
js+canvas实现纸牌游戏
Mar 16 #Javascript
微信小程序利用button控制条件标签的变量问题
Mar 15 #Javascript
JS apply用法总结和使用场景实例分析
Mar 14 #Javascript
javascript事件循环event loop的简单模型解释与应用分析
Mar 14 #Javascript
原生js实现ajax请求和JSONP跨域请求操作示例
Mar 14 #Javascript
You might like
如何将一个表单同时提交到两个地方处理
2006/10/09 PHP
PHP无限分类代码,支持数组格式化、直接输出菜单两种方式
2011/05/18 PHP
yii通过小物件生成view的方法
2016/10/08 PHP
详解php语言最牛掰的Laravel框架
2017/11/20 PHP
PHP+Redis开发的书签案例实战详解
2019/07/09 PHP
PhpStorm2020 + phpstudyV8 +XDebug的教程详解
2020/09/17 PHP
jquery中的on方法使用介绍
2013/12/29 Javascript
一个简单的jquery的多选下拉框(自写)
2014/05/05 Javascript
JavaScript学习笔记之JS函数
2015/01/22 Javascript
javascript中call apply 的应用场景
2015/04/16 Javascript
JS实现跟随鼠标立体翻转图片的方法
2015/05/04 Javascript
JQuery boxy插件在IE中边角图片不显示问题的解决
2015/05/20 Javascript
Node.js包管理器Yarn的入门介绍与安装
2016/10/17 Javascript
JS实现线性表的顺序表示方法示例【经典数据结构】
2017/04/11 Javascript
Bootstrap 表单验证formValidation 实现远程验证功能
2017/05/17 Javascript
JavaScript寄生组合式继承实例详解
2018/01/06 Javascript
理解 JavaScript EventEmitter
2018/03/29 Javascript
微信小程序实现人脸识别
2018/05/25 Javascript
VUE 实现复制内容到剪贴板的两种方法
2019/04/24 Javascript
JQuery Ajax如何实现注册检测用户名
2020/09/25 jQuery
vue使用element-ui实现表单验证
2020/12/13 Vue.js
[03:19]2016国际邀请赛中国区预选赛第四日TOP10镜头集锦
2016/07/01 DOTA
[01:07:19]DOTA2-DPC中国联赛 正赛 CDEC vs XG BO3 第一场 1月19日
2021/03/11 DOTA
windows 10下安装搭建django1.10.3和Apache2.4的方法
2017/04/05 Python
Python 查看文件的编码格式方法
2017/12/21 Python
Python推导式简单示例【列表推导式、字典推导式与集合推导式】
2018/12/04 Python
使用OpenCV实现仿射变换—平移功能
2019/08/29 Python
Django Xadmin多对多字段过滤实例
2020/04/07 Python
基于opencv的selenium滑动验证码的实现
2020/07/24 Python
python爬虫构建代理ip池抓取数据库的示例代码
2020/09/22 Python
python利用appium实现手机APP自动化的示例
2021/01/26 Python
CSS3弹性盒模型开发笔记(一)
2016/04/26 HTML / CSS
Ruby如何实现动态方法调用
2012/11/18 面试题
投标单位介绍信
2014/01/09 职场文书
校运会新闻稿
2015/07/17 职场文书
技术转让协议书
2016/03/19 职场文书