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

原创 黎云锐 教程 前端 4737阅读 2018-12-17 22:02:38 举报

概述:

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

1. 实例

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

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

代码地址:Github UI-Library

2. 原理

代码结构

将Toast插件分为两个部分:

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

Toast方法

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

/* 构造单个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;
}

/* 初始化每个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对象在页面中的垂直属性 */
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]
}
}
}

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

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);
}

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

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

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

评论 ( 0 )
最新评论
暂无评论

赶紧努力消灭 0 回复