UNPKG

@ithinkdt/naive

Version:

iThinkDT Naive UI

163 lines (135 loc) 4.2 kB
import { defineComponent, ref, reactive, shallowReactive, nextTick } from 'vue' import { NSpin } from 'ithinkdt-ui' import { useElementIntersectionRect } from '@ithinkdt/common' import { cB, cE, c, cM, CSS_MOUNT_ANCHOR_META_NAME, CSS_STYLE_PREFIX as p } from '@ithinkdt/core/cssr' const cls = `${p}-directive-spin` const SpinClass = `${cls}-container--spin` const spins = shallowReactive([]) export const SpinProvider = defineComponent({ name: 'DtSpinDirectiveProvider', setup() { createStyle(cls) return () => <div class={`${cls}-provider`}>{spins}</div> }, }) const Spin = Symbol(cls) const init = (el, value) => { if (el[Spin]) return const loading = ref(!!value) const pos = reactive(useElementIntersectionRect(el)) const tip = ref('') const SpinWrapper = defineComponent({ setup() { return () => { if (loading.value) { el.classList.add(SpinClass) tip.value = el.dataset.spinTip } else { el.classList.remove(SpinClass) } return ( <NSpin class={[cls, loading.value ? '' : `${cls}--hidden`]} show={loading.value && !!(pos.width && pos.height)} style={{ left: pos.left + 'px', top: pos.top + 'px', width: pos.width + 'px', height: pos.height + 'px', }} description={tip.value} > <div /> </NSpin> ) } }, }) const spin = <SpinWrapper key={(Date.now() % 1_000_000) + '-' + Math.floor(Math.random() * 1000)} /> spins.push(spin) el[Spin] = { loading, stop: pos.stop, spin, tip, } } const obs = async (el) => { if (el[Spin].observer) return // 创建 MutationObserver 对象 await nextTick() const observer = (el[Spin].observer = new MutationObserver((mutationsList) => { for (const mutation of mutationsList) { if (mutation.type === 'attributes' && mutation.attributeName === 'data-spin-tip') { el[Spin].tip.value = el.dataset.spinTip return } } })) // 开始观察目标元素 observer.observe(el, { attributes: true }) } export const vSpin = { created(el, { value }) { init(el, value) }, beforeMount(el, { value }) { init(el, value) el.classList.add(`${cls}-container`) }, mounted(el, { value }) { init(el, value) obs(el) }, updated(el, { value }) { init(el, value) obs(el) el[Spin].loading.value = !!value }, beforeUnmount(el) { el[Spin].loading.value = false el[Spin].stop() const index = spins.indexOf(el[Spin].spin) spins.splice(index, 1) el[Spin].observer?.disconnect() delete el[Spin] }, } let style function createStyle(cls) { if (!style) { style = c([ cB( 'directive-spin', { position: 'absolute', zIndex: '999999', }, [ cM('hidden', { pointerEvents: 'none', }), cE('content', { pointerEvents: 'none', background: `var(--${p}-base-color)`, }), ], ), cB( 'directive-spin-container', { transition: `opacity 0.3s var(--${p}-cubic-bezier-ease-in-out)`, }, [ cM('spin', { opacity: '0.5', }), ], ), ]) style.mount({ id: cls, anchorMetaName: CSS_MOUNT_ANCHOR_META_NAME, }) } }