概述:
在前端项目中,有时会需要通知、提示一些信息给用户,尤其是在后台系统中,操作的正确与否,都需要给与用户一些信息。
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 回复