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 相关文章推荐
关于juqery radio写法的兼容性问题(新老版本jquery)
Jun 14 Javascript
JS实现多物体缓冲运动实例代码
Nov 29 Javascript
javascript html实现网页版日历代码
Mar 08 Javascript
JavaScript是如何实现继承的(六种方式)
Mar 31 Javascript
AngularJS中$watch和$timeout的使用示例
Sep 20 Javascript
实例讲解DataTables固定表格宽度(设置横向滚动条)
Jul 11 Javascript
JavaScript实现图片本地预览功能【不用上传至服务器】
Sep 20 Javascript
node.js将MongoDB数据同步到MySQL的步骤
Dec 10 Javascript
微信小程序实现收藏与取消收藏切换图片功能
Aug 03 Javascript
layui select获取自定义属性方法
Aug 15 Javascript
Node.js系列之安装配置与基本使用(1)
Aug 30 Javascript
Jquery+AJAX实现无刷新上传并重命名文件操作示例【PHP后台接收】
May 29 jQuery
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 多维数组的排序问题 根据二维数组中某个项排序
2011/11/09 PHP
第三章 php操作符与控制结构代码
2011/12/30 PHP
PHP中substr函数字符串截取用法分析
2016/01/07 PHP
PHP图片水印类的封装
2017/07/06 PHP
Yii2框架操作数据库的方法分析【以mysql为例】
2019/05/27 PHP
thinkPHP5框架路由常用知识点汇总
2019/09/15 PHP
laravel框架查询数据集转为数组的两种方法
2019/10/10 PHP
Laravel自动生成UUID,从建表到使用详解
2019/10/24 PHP
Javascript 键盘keyCode键码值表
2009/12/24 Javascript
jquery 元素相对定位代码
2010/10/15 Javascript
JavaScript中pop()方法的使用教程
2015/06/09 Javascript
JS实现的自定义右键菜单实例二则
2015/09/01 Javascript
jQuery实现多级联动下拉列表查询框
2016/01/18 Javascript
浅谈js控制li标签排序问题 js调用php函数的方法
2016/10/16 Javascript
Node.js调用fs.renameSync报错(Error: EXDEV, cross-device link not permitted)
2017/12/27 Javascript
ES6学习笔记之map、set与数组、对象的对比
2018/03/01 Javascript
js+css实现打字效果
2020/06/24 Javascript
vue.js打包之后可能会遇到的坑!
2018/06/03 Javascript
使用JavaScript实现node.js中的path.join方法
2018/08/12 Javascript
[03:12]TI9战队档案 - Virtus Pro
2019/08/20 DOTA
Python部署web开发程序的几种方法
2017/05/05 Python
Pycharm设置界面全黑的方法
2018/05/23 Python
基于Python在MacOS上安装robotframework-ride
2018/12/28 Python
Django中如何防范CSRF跨站点请求伪造攻击的实现
2019/04/28 Python
pytorch 模拟关系拟合——回归实例
2020/01/14 Python
美国求婚钻戒网站:Super Jeweler
2016/08/27 全球购物
澳大利亚体育和露营装备在线/实体零售商:Find Sports
2020/06/03 全球购物
Java程序员面试题
2013/07/15 面试题
采购部岗位职责
2013/11/24 职场文书
大学生的四年学习自我评价
2013/12/13 职场文书
青年文明号口号
2014/06/17 职场文书
初婚初育证明范本
2015/06/18 职场文书
缅怀先烈主题班会
2015/08/14 职场文书
通知怎么写?
2019/04/17 职场文书
Python的这些库,你知道多少?
2021/06/09 Python
Linux系统下MySQL配置主从分离的步骤
2022/03/21 MySQL