最近在看vue组件库 Plain UI 时,发现一个比拟乏味的异步弹框组件写法,操作如下:
<div class="dialog"> <input type="text" name="message"> <button type="button">cancel</button> <button type="button">confirm</button></div>
(async ()=>{ let message = await openDialog(); console.log("弹窗信息",message)})()
在异步函数中关上弹窗 openDialog
办法,当用户点击 confirm
按钮后,弹窗敞开,返回输入框信息。
openDialog
办法能够很不便的通过promise实现,不过在看组件库源码时,发现对方是用defer 实现的,在promise兼容性还不是很好的时代 JQuery 就曾经有 deferred.promise() 办法了,这里顺便也做了复习。
defer
办法:
const defer = () => { const def = {} def.promise = new Promise((resolve, reject) => { def.resolve = resolve def.reject = reject }) return def}
defer
办法其实返回的也是一个promise,并且将 resolve
和 reject
办法拆开,这样咱们就能够抉择在适当的机会调用 resolve
或者 reject
办法了。
const dialogController = () => { let dfd = null const confirmBtn = document.getElementById('confirm') // 点击确定按钮 confirmBtn.addEventListener('click', () => { // 暗藏弹窗 dialogEl.hide() // resolve输入框信息给用户 dfd.resolve(inputEl.value) }) return () => { dfd = defer() dialogEl.show() return dfd.promise }}
取得关上弹窗promise办法:
const openDialog = dialogController()
管制弹窗的关上,在异步函数中如果用户点击了弹窗确定按钮,敞开弹窗,取得输出信息。
const controlBtn = document.getElementById('control')controlBtn.addEventListener('click', async () => { const message = await openDialog() console.log("弹窗输入框信息:",message)})
这种形式能够不便咱们封装罕用的业务组件,之前在看 axios.cancel
源码时外面也是应用这种套路,灵便且实用。
通过 defer
形式实现的弹窗代码:
<html> <head> <title>defer promise</title> <style> .dialog { top: 0; left: 0; right: 0; bottom: 0; display: flex; position: fixed; align-items: center; pointer-events: none; justify-content: center; } .dialog .mask { top: 0; left: 0; width: 100%; height: 100%; position: absolute; opacity: 0; transition: 0.3s; background-color: rgba(0, 0, 0, 0.4); } .dialog-content { padding: 20px; transition: 0.2s; opacity: 0; transform: scale(0.95); background-color: #fff; } .dialog.visible { pointer-events: all; } .dialog.visible .mask { opacity: 1; } .dialog.visible .dialog-content { opacity: 1; transform: scale(1); } </style> </head> <body> <div class="container"> <button id="control">显示弹窗</button> <div class="dialog" id="dialog"> <div class="mask" onclick="this.parentNode.classList.remove('visible')"></div> <div class="dialog-content"> <input type="text" id="content" /> <button id="confirm">确定</button> </div> </div> </div> <script> const defer = () => { const def = {} def.promise = new Promise((resolve, reject) => { def.resolve = resolve def.reject = reject }) return def } ;(() => { const inputEl = document.getElementById('content') const dialogEl = document.getElementById('dialog') dialogEl.show = () => dialogEl.classList.add('visible') dialogEl.hide = () => dialogEl.classList.remove('visible') const dialogController = () => { let dfd = null const confirmBtn = document.getElementById('confirm') confirmBtn.addEventListener('click', () => { dialogEl.hide() dfd.resolve(inputEl.value) }) return () => { dfd = defer() dialogEl.show() return dfd.promise } } const openDialog = dialogController() const controlBtn = document.getElementById('control') controlBtn.addEventListener('click', async () => { const message = await openDialog() console.log('弹窗输入框信息:', message) }) })() </script> </body></html>