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 相关文章推荐
JavaScript实现twitter puddles算法实例
Dec 06 Javascript
Jquery uploadify上传插件使用详解
Jan 13 Javascript
JS锚点的设置与使用方法
Sep 05 Javascript
JS常用函数和常用技巧小结
Oct 15 Javascript
AngularJS中如何使用echart插件示例详解
Oct 26 Javascript
微信小程序开发之入门实例教程篇
Mar 07 Javascript
ES6新特性之数组、Math和扩展操作符用法示例
Apr 01 Javascript
js中的事件委托或是事件代理使用详解
Jun 23 Javascript
ionic3实战教程之随机布局瀑布流的实现方法
Dec 28 Javascript
django简单的前后端分离的数据传输实例 axios
May 18 Javascript
antd design table更改某行数据的样式操作
Oct 31 Javascript
vue3不同环境下实现配置代理
May 25 Vue.js
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
用PHP实现WEB动态网页静态
2006/10/09 PHP
PHP实现的超长文本分页显示功能示例
2018/06/04 PHP
PHP日志LOG类定义与用法示例
2018/09/06 PHP
解密效果
2006/06/23 Javascript
JavaScript 编写匿名函数的几种方法
2010/02/21 Javascript
node.js中的fs.fchmod方法使用说明
2014/12/16 Javascript
HTML页面,测试JS对C函数的调用简单实例
2016/08/09 Javascript
Bootstrap table 定制提示语的加载过程
2017/02/20 Javascript
bootstrap表单按回车会自动刷新页面的解决办法
2017/03/08 Javascript
ionic环境配置及问题详解
2017/06/27 Javascript
Vue的MVVM实现方法
2017/08/16 Javascript
详解Vue中localstorage和sessionstorage的使用
2017/12/22 Javascript
layer.close()关闭进度条和Iframe窗的方法
2018/08/17 Javascript
vue 使用 v-model 双向绑定父子组件的值遇见的问题及解决方案
2021/03/01 Vue.js
[02:58]魔廷新尊——痛苦女王至宝语音台词节选
2020/06/14 DOTA
使用Python抓取模板之家的CSS模板
2015/03/16 Python
利用python将json数据转换为csv格式的方法
2018/03/22 Python
python读取大文件越来越慢的原因与解决
2019/08/08 Python
Django微信小程序后台开发教程的实现
2020/06/03 Python
绝对令人的惊叹的CSS3折叠效果(3D效果)整理
2012/12/30 HTML / CSS
HTML5+CSS3实现机器猫
2016/10/17 HTML / CSS
Sephora丝芙兰菲律宾官方网站:购买化妆品和护肤品
2017/04/05 全球购物
台湾森森购物网:U-mall
2017/10/16 全球购物
Desigual德国官网:在线购买原创服装
2018/03/27 全球购物
希腊香水和化妆品购物网站:Parfimo.gr
2019/10/03 全球购物
思想汇报范文
2013/11/04 职场文书
《落花生》教学反思
2014/02/25 职场文书
股东协议书
2014/04/14 职场文书
《歌唱二小放牛郎》教学反思
2014/04/19 职场文书
爱心捐助活动总结
2015/05/09 职场文书
2015年度内部审计工作总结
2015/05/20 职场文书
2015年语文教学工作总结
2015/05/25 职场文书
2016高考冲刺决心书
2015/09/23 职场文书
2016暑期师德培训心得体会
2016/01/09 职场文书
Python3 类型标注支持操作
2021/06/02 Python
CSS实现两列布局的N种方法
2021/08/02 HTML / CSS