feat application ui (#3250)
This commit is contained in:
parent
8def4f3e4a
commit
e9aa3a311c
7
ui/src/directives/clickoutside.ts
Normal file
7
ui/src/directives/clickoutside.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import type { App } from 'vue'
|
||||||
|
import { ClickOutside as vClickOutside } from 'element-plus'
|
||||||
|
export default {
|
||||||
|
install: (app: App) => {
|
||||||
|
app.directive('click-outside', vClickOutside)
|
||||||
|
}
|
||||||
|
}
|
||||||
151
ui/src/directives/infiniteScrollUp.ts
Normal file
151
ui/src/directives/infiniteScrollUp.ts
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
import { nextTick } from 'vue'
|
||||||
|
|
||||||
|
import { throttle } from 'lodash-unified'
|
||||||
|
import { getScrollContainer } from 'element-plus/es/utils/index'
|
||||||
|
import type { App } from 'vue'
|
||||||
|
export const SCOPE = 'InfiniteScrollUP'
|
||||||
|
export const CHECK_INTERVAL = 50
|
||||||
|
export const DEFAULT_DELAY = 200
|
||||||
|
export const DEFAULT_DISTANCE = 0
|
||||||
|
|
||||||
|
const attributes = {
|
||||||
|
delay: {
|
||||||
|
type: Number,
|
||||||
|
default: DEFAULT_DELAY
|
||||||
|
},
|
||||||
|
distance: {
|
||||||
|
type: Number,
|
||||||
|
default: DEFAULT_DISTANCE
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
immediate: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Attrs = typeof attributes
|
||||||
|
type ScrollOptions = { [K in keyof Attrs]: Attrs[K]['default'] }
|
||||||
|
type InfiniteScrollCallback = () => void
|
||||||
|
type InfiniteScrollEl = HTMLElement & {
|
||||||
|
[SCOPE]: {
|
||||||
|
container: HTMLElement | Window
|
||||||
|
containerEl: HTMLElement
|
||||||
|
instance: any
|
||||||
|
delay: number // export for test
|
||||||
|
lastScrollTop: number
|
||||||
|
cb: InfiniteScrollCallback
|
||||||
|
onScroll: () => void
|
||||||
|
observer?: MutationObserver
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getScrollOptions = (el: HTMLElement, instance: any): ScrollOptions => {
|
||||||
|
return Object.entries(attributes).reduce((acm: any, [name, option]) => {
|
||||||
|
const { type, default: defaultValue } = option
|
||||||
|
const attrVal: any = el.getAttribute(`infinite-scroll-up-${name}`)
|
||||||
|
let value = instance[attrVal] ?? attrVal ?? defaultValue
|
||||||
|
value = value === 'false' ? false : value
|
||||||
|
value = type(value)
|
||||||
|
acm[name] = Number.isNaN(value) ? defaultValue : value
|
||||||
|
return acm
|
||||||
|
}, {} as ScrollOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
const destroyObserver = (el: InfiniteScrollEl) => {
|
||||||
|
const { observer } = el[SCOPE]
|
||||||
|
|
||||||
|
if (observer) {
|
||||||
|
observer.disconnect()
|
||||||
|
delete el[SCOPE].observer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleScroll = (el: InfiniteScrollEl, cb: InfiniteScrollCallback) => {
|
||||||
|
const { container, containerEl, instance, observer, lastScrollTop } = el[SCOPE]
|
||||||
|
const { disabled } = getScrollOptions(el, instance)
|
||||||
|
const { scrollTop } = containerEl
|
||||||
|
|
||||||
|
el[SCOPE].lastScrollTop = scrollTop
|
||||||
|
|
||||||
|
// trigger only if full check has done and not disabled and scroll down
|
||||||
|
|
||||||
|
if (observer || disabled || scrollTop > 0) return
|
||||||
|
|
||||||
|
if (scrollTop == 0) {
|
||||||
|
cb.call(instance)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkFull(el: InfiniteScrollEl, cb: InfiniteScrollCallback) {
|
||||||
|
const { containerEl, instance } = el[SCOPE]
|
||||||
|
const { disabled } = getScrollOptions(el, instance)
|
||||||
|
|
||||||
|
if (disabled || containerEl.clientHeight == 0) return
|
||||||
|
|
||||||
|
if (containerEl.scrollTop <= 0) {
|
||||||
|
cb.call(instance)
|
||||||
|
} else {
|
||||||
|
destroyObserver(el)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const InfiniteScroll = {
|
||||||
|
async mounted(el: any, binding: any) {
|
||||||
|
const { instance, value: cb } = binding
|
||||||
|
|
||||||
|
// ensure parentNode mounted
|
||||||
|
await nextTick()
|
||||||
|
|
||||||
|
const { delay, immediate } = getScrollOptions(el, instance)
|
||||||
|
const container = getScrollContainer(el, true)
|
||||||
|
const containerEl = container === window ? document.documentElement : (container as HTMLElement)
|
||||||
|
const onScroll = throttle(handleScroll.bind(null, el, cb), delay)
|
||||||
|
|
||||||
|
if (!container) return
|
||||||
|
|
||||||
|
el[SCOPE] = {
|
||||||
|
instance,
|
||||||
|
container,
|
||||||
|
containerEl,
|
||||||
|
delay,
|
||||||
|
cb,
|
||||||
|
onScroll,
|
||||||
|
lastScrollTop: containerEl.scrollTop
|
||||||
|
}
|
||||||
|
|
||||||
|
if (immediate) {
|
||||||
|
const observer = new MutationObserver(throttle(checkFull.bind(null, el, cb), CHECK_INTERVAL))
|
||||||
|
el[SCOPE].observer = observer
|
||||||
|
observer.observe(el, { childList: true, subtree: true })
|
||||||
|
checkFull(el, cb)
|
||||||
|
}
|
||||||
|
|
||||||
|
container.addEventListener('scroll', onScroll)
|
||||||
|
},
|
||||||
|
unmounted(el: any) {
|
||||||
|
if (!el[SCOPE]) return
|
||||||
|
const { container, onScroll } = el[SCOPE]
|
||||||
|
|
||||||
|
container?.removeEventListener('scroll', onScroll)
|
||||||
|
destroyObserver(el)
|
||||||
|
},
|
||||||
|
async updated(el: any) {
|
||||||
|
if (!el[SCOPE]) {
|
||||||
|
await nextTick()
|
||||||
|
} else {
|
||||||
|
const { containerEl, cb, observer } = el[SCOPE]
|
||||||
|
if (containerEl.clientHeight && observer) {
|
||||||
|
checkFull(el, cb)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default {
|
||||||
|
install: (app: App) => {
|
||||||
|
app.directive('infinite-scroll-up', InfiniteScroll)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -34,7 +34,7 @@ const data = computed({
|
|||||||
},
|
},
|
||||||
get: () => {
|
get: () => {
|
||||||
return props.modelValue
|
return props.modelValue
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
const options = ref<Array<any>>([])
|
const options = ref<Array<any>>([])
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user