理论上可以用于任何元素,生效时会在元素上出现一个同大小的灰色蒙层(button元素会该表原生的disabled属性)。
/** * 当元素触发发起请求后,当发起的请求中最后一个请求的结果返回(不关心返回顺序和结果),解锁元素禁用。 * 优化:用一个pending记录所有请求,逐个判定是否返回结果。 * 指令的方式使用轮询去校验接口是否返回结果,也可以在axios拦截器中,改变store中的数据, * 然后在页面的computed中处理,不过页面内代码不如一个指令来的方便。 * 也可以用Bus来代替轮询 */ const forbiddenInterval = 200; /** * 配合ElementUI逐次查找父节点,目前仅考虑 body 和 dialogue 2个场景 * 将目标节点设为root,将mask(非button元素,el-button实际上就是个原生button元素,直接用原生属性disabled即可)挂在root下 * 并且相对root定位 */ function findRootTag(el) { let parent = el.parentNode; let type = null; let root = null; while (parent) { if (parent.tagName === ‘BODY‘) { type = ‘body‘; root = parent; break; } else if (parent.getAttribute(‘role‘) === ‘dialog‘) { type = ‘dialog‘; root = parent; break; } parent = parent.parentNode; } return { type, root }; } export default { inserted(el) { el.timer = null; if (el.tagName === ‘BUTTON‘) { el.forbiddenClick = () => { el.disabled = true; el.classList.add(‘is-disabled‘); el.timer = setInterval(() => { if (window.currentResq.done) { clearInterval(el.timer); el.disabled = false; el.classList.remove(‘is-disabled‘); } }, forbiddenInterval); }; el.addEventListener(‘click‘, el.forbiddenClick); } else { const { type, root} = findRootTag(el); let mask = document.createElement(‘div‘); if (type === ‘dialog‘) { /* dialog上的mask z-index 设置的较大 */ mask.setAttribute(‘style‘, ` position: absolute; diplay: none; background-color: #e4e7ed; cursor: not-allowed; opacity: .4; z-index: 9999; ` ); } else { mask.setAttribute(‘style‘, ` position: absolute; diplay: none; background-color: #e4e7ed; cursor: not-allowed; opacity: .4; z-index: 1000; ` ); } mask.classList.add(‘mask‘); root.appendChild(mask); el.instance = mask; el.root = root; el.type = type; } }, update(el, binding) { if (el.tagName !== ‘BUTTON‘ && binding.value !== binding.oldValue) { const root = el.root; const type = el.type; const scrollTop = root.scrollTop || document.documentElement.scrollTop; const scrollLeft = root.scrollLeft || document.documentElement.scrollLeft; const mask = el.instance; const elRect = el.getBoundingClientRect(); mask.style.width = `${elRect.width}px`; mask.style.height = `${elRect.height}px`; if (type === ‘body‘) { mask.style.top = `${elRect.top + scrollTop}px`; mask.style.left = `${elRect.left + scrollLeft}px`; } else if (type === ‘dialog‘) { const rootRect = root.getBoundingClientRect(); mask.style.top = `${elRect.top - rootRect.top}px`; mask.style.left = `${elRect.left - rootRect.left}px`; } mask.style.display = ‘block‘; el.timer = setInterval(() => { if (window.currentResq.done) { clearInterval(el.timer); mask.style.display = ‘none‘; } }, forbiddenInterval); } }, unbind(el) { if (el.instance) { el.root.removeChild(el.instance); } if (el.forbiddenClick) { document.removeEventListener(‘click‘, el.forbiddenClick); } }, };
还有很多可以改进的地方,比如应该是有办法去兼容dialog这种会禁用body滚动并且本身也会有动条的元素,等下一个项目去实践一下脑子里的想法。
原文地址:https://www.cnblogs.com/youyouluo/p/11971431.html
时间: 2024-10-13 13:22:43