美文网首页让前端飞前端技术分享
从零开始实现Vue简单的Toast插件

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

作者: 老王420 | 来源:发表于2018-12-17 22:06 被阅读11次

    概述:

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

    1. 实例

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

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

    在页面的右侧会出现一个Toast弹框,多次点击时,会依照顺序进行显示,并且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 = {}) => {...}`
    `}`
    `}`
    

    总结
    通过封装一个Toast插件,提取不同业务之间公共的部分,减少业务的工作量。
    好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值
    本次给大家推荐一个交流圈,里面概括移动应用网站开发,css,html,webpack,vue node angular以及面试资源等。
    对web开发技术感兴趣的同学,欢迎加入:582735936,不管你是小白还是大牛我都欢迎,还有大牛整理的一套高效率学习路线和教程与您免费分享,同时每天更新视频资料。
    最后,祝大家早日学有所成,拿到满意offer,快速升职加薪,走上人生巅峰。

    相关文章

      网友评论

        本文标题:从零开始实现Vue简单的Toast插件

        本文链接:https://www.haomeiwen.com/subject/qsdhkqtx.html