从零开始实现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 相关文章推荐
一些有关检查数据的JS代码
Sep 07 Javascript
javascript+dom树型菜单类,希望朋友们一起进步
May 03 Javascript
鼠标滑在标题上显示图片的JS代码
Nov 19 Javascript
jquery ajax 局部无刷新更新数据的实现案例
Feb 08 Javascript
jQuery简单验证上传文件大小及类型的方法
Jun 02 Javascript
初识简单却不失优雅的Vue.js
Sep 12 Javascript
JS如何实现在页面上快速定位(锚点跳转问题)
Aug 14 Javascript
vue小图标favicon不显示的解决方案
Sep 19 Javascript
详解Nuxt.js部署及踩过的坑
Aug 07 Javascript
vue 弹框产生的滚动穿透问题的解决
Sep 21 Javascript
vue中使用cookies和crypto-js实现记住密码和加密的方法
Oct 18 Javascript
vue实现多个echarts根据屏幕大小变化而变化实例
Jul 19 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
合作指挥官:孟斯克
2020/03/16 星际争霸
生成静态页面的PHP类
2006/11/25 PHP
深入php函数file_get_contents超时处理的方法详解
2013/06/03 PHP
Laravel 中使用 Vue.js 实现基于 Ajax 的表单提交错误验证操作
2017/06/30 PHP
鼠标移动到图片名上,显示图片的简单实例
2013/07/14 Javascript
JS实现仿新浪微博发布内容为空时提示功能代码
2015/08/19 Javascript
谈谈jQuery之Deferred源码剖析
2016/12/19 Javascript
Bootstrap组合上、下拉框简单实现代码
2017/03/06 Javascript
NodeJS学习笔记之Module的简介
2017/03/24 NodeJs
详解有关easyUI的拖动操作中droppable,draggable用法例子
2017/06/03 Javascript
vue引用js文件的多种方式(推荐)
2018/05/17 Javascript
详解webpack loader和plugin编写
2018/10/12 Javascript
在Vue中创建可重用的 Transition的方法
2020/06/02 Javascript
vue使用better-scroll实现滑动以及左右联动
2020/06/30 Javascript
在Python中处理字符串之ljust()方法的使用简介
2015/05/19 Python
约瑟夫问题的Python和C++求解方法
2015/08/20 Python
详解Python requests 超时和重试的方法
2018/12/18 Python
python 限制函数执行时间,自己实现timeout的实例
2019/01/12 Python
Python函数中参数是传递值还是引用详解
2019/07/02 Python
在Python中使用MongoEngine操作数据库教程实例
2019/12/03 Python
python 解决print数组/矩阵无法完整输出的问题
2020/02/19 Python
python主要用于哪些方向
2020/07/05 Python
使用CSS3制作响应式导航菜单的方法
2015/07/12 HTML / CSS
雅诗兰黛旗下走天然植物路线的彩妆品牌:Prescriptives
2016/08/14 全球购物
英国度假别墅预订:Sykes Cottages
2017/06/12 全球购物
世界上最大的在线学习和教学市场:Udemy
2017/11/08 全球购物
皮姆斯勒语言学习:Pimsleur Language Programs
2018/06/30 全球购物
Amara德国:家居饰品、设计师品牌和豪华礼品
2019/05/20 全球购物
探亲邀请信范文
2014/01/30 职场文书
高三学生评语大全
2014/04/25 职场文书
简易离婚协议书(范本)
2014/10/25 职场文书
早会开场白台词大全
2015/06/01 职场文书
铁人纪念馆观后感
2015/06/16 职场文书
高中班长竞选稿
2015/11/20 职场文书
《亲亲我的妈妈》观后感(3篇)
2019/09/26 职场文书
MySQL 1130异常,无法远程登录解决方案详解
2021/08/23 MySQL