@ithinkdt/naive
Version:
iThinkDT Naive UI
163 lines (135 loc) • 4.2 kB
JSX
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,
})
}
}