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 eval函数深入认识
Feb 21 Javascript
JavaScript和ActionScript的交互实现代码
Aug 01 Javascript
jquery实现简单易懂的图片展示小例子
Nov 21 Javascript
基于JQuery实现的Select级联
Jan 27 Javascript
javascript中函数作为参数调用的方法
Feb 09 Javascript
基于jquery实现省市联动效果
Nov 23 Javascript
Bootstrap中表单控件状态(验证状态)
Aug 04 Javascript
原生javascript实现的ajax异步封装功能示例
Nov 03 Javascript
JavaScript获取用户所在城市及地理位置
Apr 21 Javascript
JS实现将二维数组转为json格式字符串操作示例
Jul 12 Javascript
详解keep-alive + vuex 让缓存的页面灵活起来
Apr 19 Javascript
在vue项目中promise解决回调地狱和并发请求的问题
Nov 09 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
MySQL修改密码方法总结
2008/03/25 PHP
解析PHP汉字转换拼音的类
2013/06/18 PHP
分享php邮件管理器源码
2016/01/06 PHP
jquery+thinkphp实现跨域抓取数据的方法
2016/10/15 PHP
JQuery 文本框回车跳到下一个文本框示例代码
2013/08/30 Javascript
Jquery焦点与失去焦点示例应用
2014/06/10 Javascript
js实现百度联盟中一款不错的图片切换效果完整实例
2015/03/04 Javascript
jQuery实现冻结表格行和列
2015/04/29 Javascript
javascript封装简单实现方法
2015/08/11 Javascript
JavaScript中关于for循环删除数组元素内容时出现的问题
2016/11/21 Javascript
vue.js父组件使用外部对象的方法示例
2017/04/25 Javascript
javascript中mouseenter与mouseover的异同
2017/06/06 Javascript
vuejs父子组件之间数据交互详解
2017/08/09 Javascript
Three.js利用dat.GUI如何简化试验流程详解
2017/09/26 Javascript
关于JavaScript语句后面的分号问题
2017/12/07 Javascript
element-ui中select组件绑定值改变,触发change事件方法
2018/08/24 Javascript
webpack HappyPack实战详解
2019/10/08 Javascript
vuex管理状态 刷新页面保持不被清空的解决方案
2019/11/11 Javascript
一个Python最简单的接口自动化框架
2018/01/02 Python
利用Python+Java调用Shell脚本时的死锁陷阱详解
2018/01/24 Python
使用apidocJs快速生成在线文档的实例讲解
2018/02/07 Python
Python编译为二进制so可执行文件实例
2019/12/23 Python
带你彻底搞懂python操作mysql数据库(cursor游标讲解)
2020/01/06 Python
详解Anaconda安装tensorflow报错问题解决方法
2020/11/01 Python
Pandas直接读取sql脚本的方法
2021/01/21 Python
python爬虫scrapy基于CrawlSpider类的全站数据爬取示例解析
2021/02/20 Python
美国男女折扣服饰百货连锁店:Stein Mart
2017/05/02 全球购物
一套.net面试题及答案
2016/11/02 面试题
技校教师求职简历的自我评价
2013/10/20 职场文书
高中毕业自我鉴定
2013/12/13 职场文书
校园安全检查制度
2014/02/03 职场文书
我爱我的祖国演讲稿
2014/05/04 职场文书
会计演讲稿范文
2014/05/23 职场文书
英语教育专业自荐信
2014/05/29 职场文书
煤矿安全生产工作总结
2015/08/13 职场文书
浅谈Python类的单继承相关知识
2021/05/12 Python