从零开始实现Vue简单的Toast插件


Posted in Javascript onDecember 03, 2018

前言

一直都觉得vue的插件生涩难懂,但是又很好奇,在看了几篇文章,试着写了写之后觉得也没那么难,本文主要实现一个简单的Toast插件,方便迁移到不同的项目中,用来全局提示、警告一些信息。

概述:

在前端项目中,有时会需要通知、提示一些信息给用户,尤其是在后台系统中,操作的正确与否,都需要给与用户一些信息。

1. 实例

在Vue组件的methods内,调用如下代码

this.$toast({
 content: "可自动关闭",
 autoClose: true
})

在页面的右侧会出现一个Toast弹框,多次点击时,会依照顺序进行显示,并且Toast可自动关闭,具体效果如图。

从零开始实现Vue简单的Toast插件

代码地址:Github UI-Library

2. 原理

代码结构

将Toast插件分为两个部分:

  • Toast组件本身,包含本身的dom结构以及data,并在其生命周期完成在页面中的挂载与销毁;
  • 在组件外构建一层代理并提供相关方法用于调用、并控制多个Toast在页面中显示的顺序。

Toast方法

为了能够通过this.$toast({...})调用Toast组件,须在Vue的prototype上添加一个方法,如下

let instances = []
let initIndex = 0
Vue.prototype.$toast = (options = {}) => {
 /* 创建一个Toast组件的实例 */
 let instance = generateInstance(options)
 /* 将单个toast存入队列中 */ 
 instances.push(instance)
}

当调用该方法时,通过generateInstance创建一个Toast组件的实例,并将其放入instances,统一管理。

/* 构造单个toast */
const ToastConstructor = Vue.extend(Toast)
const verticalOffset = 16
function generateInstance(options) {
 // 利用ToastConstructor创建一个Toast的实例
 let instance = new ToastConstructor({
 propsData: options
 }).$mount(document.createElement('div'))
 if (typeof options.onClose === 'function') instance.onClose = options.onClose
 //计算instance verticalOffset
 let id = 'toast_' + initIndex++
 instance.id = id
 // 初始化Toast在空间中的垂直偏移量
 instance.verticalOffset = initVerticalOffset(instance.position)
 //监听组件close
 instance.$once('toastClose', function () {
 const curInstance = this
 // 当Toast组件关闭时,重新计算垂直方向的偏移量
 updateVerticalOffset(curInstance)
 typeof curInstance.onClose === 'function' && curInstance.onClose()
 })
 return instance;
}

generateInstance函数中,首先利用ToastConstructor构造函数创建一个Toast组件的实例,并通过propsData传入属性值,同时通过$mount(document.createElement('div'))渲染该组件。

ToastConstructor是通过Vue.extend创造Toast组件的构造函数,关于这部分的具体原理,可以参考
基于Vue构造器创建Form组件的通用解决方案。

/* 初始化每个toast对象在页面中的垂直属性 */
function initVerticalOffset(position) {
 // 筛选同一方向的Toast组件
 let typeInstances = instances.filter(item => item.position === position)
 // 计算偏移量
 return typeInstances.reduce((sum, elem) => 
  (elem.$el.offsetHeight + sum + verticalOffset), 
  verticalOffset)
}

之后当某个Toast关闭时,需要更新所有Toast实例在页面中偏移量

/* 更新每个toast对象在页面中的垂直属性 */
function updateVerticalOffset(removeInstance) {
 let index = 0
 let removeHeight = removeInstance.verticalOffset
 instances.find((elem, i) => {
 if (elem.id === removeInstance.id) index = i
 })
 // 删除关闭的Toast组件
 instances.splice(index, 1)
 // 更新在删除位置之后的组件的位置
 for (; index < instances.length; ++index) {
 if (instances[index].position === removeInstance.position) {
  [instances[index].verticalOffset, removeHeight] = 
  [removeHeight, instances[index].verticalOffset]
 }
 }
}

以上完成了Toast组件的创建、如何在页面中初始化、更新的位置。

Toast组件

组件的功能比较简单,只需要展示信息,以及具备自动关闭、手动关闭两个功能,属性也要包括Toast的类型、位置、内容等。

组件的生命周期

let instance = new ToastConstructor({
 propsData: options
}).$mount(document.createElement('div'))

当Toast组件$mount调用时,会触发mounted的生命周期

mounted() {
 // 挂载Toast在页面中
 document.body.appendChild(this.$el);
 // 需要自动关闭时,调用startTimer
 if (this.autoClose) this.startTimer();
},
beforeDestroy() {
 this.stopTimer();
 this.$el.removeEventListener("transitionend", this.destroyElement);
},
destroyed() {
 // 注销
 this.$el.parentNode.removeChild(this.$el);
}

自动关闭

需要自动时,就要在利用setTimeout完成该功能,并在注销时clearTimeout掉,防止泄露。

startTimer() {
 if (this.duration > 0) {
 this.timer = setTimeout(() => {
  if (!this.closed) {
  this.close();
  }
 }, this.duration);
 }
},
stopTimer() {
 if (this.timer) clearTimeout(this.timer);
}

3. 使用

进一步将其封装成Vue的插件

export default {
 install (Vue) {
 Vue.prototype.$toast = (options = {}) => {...}
 }
}

并且对所需要传入的必需属性,做处理异常处理

export default {
 install (Vue) {
 Vue.prototype.$toast = (options = {}) => {...}
 }
}

4. 总结
通过封装一个Toast插件,提取不同业务之间公共的部分,减少业务的工作量。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
JavaScript 事件属性绑定带参数的函数
Mar 13 Javascript
js 面向对象的技术创建高级 Web 应用程序
Feb 25 Javascript
JS实现淡蓝色简洁竖向Tab点击切换效果
Oct 06 Javascript
jQuery弹簧插件编写基础之“又见弹窗”
Dec 11 Javascript
jQuery插件zTree实现获取当前选中节点在同级节点中序号的方法
Mar 08 Javascript
基于JavaScript实现的顺序查找算法示例
Apr 14 Javascript
JS利用cookies设置每隔24小时弹出框
Apr 20 Javascript
vue 开发一个按钮组件的示例代码
Mar 27 Javascript
JS 数组随机洗牌的实例代码
Sep 12 Javascript
trackingjs+websocket+百度人脸识别API实现人脸签到
Nov 26 Javascript
js核心基础之闭包的应用实例分析
May 11 Javascript
详解微信小程序动画Animation执行过程
Sep 23 Javascript
使用NestJS开发Node.js应用的方法
Dec 03 #Javascript
写gulp遇到的ES6问题详解
Dec 03 #Javascript
使用mpvue搭建一个初始小程序及项目配置方法
Dec 03 #Javascript
JS基于Location实现访问Url、重定向及刷新页面的方法分析
Dec 03 #Javascript
koa2实现登录注册功能的示例代码
Dec 03 #Javascript
react-router 路由切换动画的实现示例
Dec 03 #Javascript
Vue.js 中的 v-model 指令及绑定表单元素的方法
Dec 03 #Javascript
You might like
php过滤所有恶意字符(批量过滤post,get敏感数据)
2014/03/18 PHP
PHP伪静态Rewrite设置之APACHE篇
2014/07/30 PHP
JavaScript的Cookies
2008/01/16 Javascript
prototype 中文参数乱码解决方案
2009/11/09 Javascript
一个js拖拽的效果类和dom-drag.js浅析
2010/07/17 Javascript
javascript下利用arguments实现string.format函数
2010/08/24 Javascript
JS实现静止元素自动移动示例
2014/04/14 Javascript
jQuery 3.0中存在问题及解决办法
2016/07/15 Javascript
jQuery的图片轮播插件PgwSlideshow使用详解
2016/08/11 Javascript
AngularJS控制器controller给模型数据赋初始值的方法
2017/01/04 Javascript
浅谈jquery拼接字符串效率比较高的方法
2017/02/22 Javascript
详解Eslint 配置及规则说明
2018/09/10 Javascript
Iview Table组件中各种组件扩展的使用
2018/10/20 Javascript
了解javascript中变量及函数的提升
2019/05/27 Javascript
微信小程序实现蓝牙打印
2019/09/23 Javascript
详解JavaScript 的执行机制
2020/09/18 Javascript
vue打开子组件弹窗都刷新功能的实现
2020/09/21 Javascript
[03:42]2014DOTA2西雅图国际邀请赛7月9日TOPPLAY
2014/07/09 DOTA
[32:07]完美世界DOTA2联赛PWL S3 LBZS vs Rebirth 第一场 12.16
2020/12/17 DOTA
python使用PythonMagick将jpg图片转换成ico图片的方法
2015/03/26 Python
Python实现SMTP发送邮件详细教程
2021/03/02 Python
python实现的正则表达式功能入门教程【经典】
2017/06/05 Python
详解python中 os._exit() 和 sys.exit(), exit(0)和exit(1) 的用法和区别
2017/06/23 Python
使用NumPy和pandas对CSV文件进行写操作的实例
2018/06/14 Python
pycharm访问mysql数据库的方法步骤
2019/06/18 Python
python异常处理和日志处理方式
2019/12/24 Python
python3注册全局热键的实现
2020/03/22 Python
PyTorch实现重写/改写Dataset并载入Dataloader
2020/07/14 Python
Lyle & Scott苏格兰金鹰官网:英国皇室御用品牌
2018/05/09 全球购物
淘宝好评语大全
2014/05/05 职场文书
运动会跳远广播稿5篇
2014/09/17 职场文书
群众路线个人对照检查材料
2014/09/23 职场文书
2015年教师新年寄语
2014/12/08 职场文书
个人年终总结范文
2015/03/09 职场文书
在 Golang 中实现 Cache::remember 方法详解
2021/03/30 Python
MySQL GRANT用户授权的实现
2021/06/18 MySQL