UNPKG

@aplus-frontend/antdv

Version:

Vue basic component library maintained based on ant-design-vue

183 lines 6.83 kB
import { createVNode as _createVNode } from "vue"; import _extends from "@babel/runtime/helpers/esm/extends"; import { nextTick, onActivated, watchEffect, defineComponent, onBeforeUnmount, onMounted, ref, shallowRef, watch } from 'vue'; import addEventListenerWrap from '../vc-util/Dom/addEventListener'; import { getOffset } from '../vc-util/Dom/css'; import classNames from '../_util/classNames'; import getScrollBarSize from '../_util/getScrollBarSize'; import { useInjectTable } from './context/TableContext'; import { useLayoutState } from './hooks/useFrame'; export default defineComponent({ name: 'StickyScrollBar', inheritAttrs: false, props: ['offsetScroll', 'container', 'scrollBodyRef', 'scrollBodySizeInfo'], emits: ['scroll'], setup(props, _ref) { let { emit, expose } = _ref; const tableContext = useInjectTable(); const bodyScrollWidth = shallowRef(0); const bodyWidth = shallowRef(0); const scrollBarWidth = shallowRef(0); watchEffect(() => { bodyScrollWidth.value = props.scrollBodySizeInfo.scrollWidth || 0; bodyWidth.value = props.scrollBodySizeInfo.clientWidth || 0; scrollBarWidth.value = bodyScrollWidth.value && bodyWidth.value * (bodyWidth.value / bodyScrollWidth.value); }, { flush: 'post' }); const scrollBarRef = shallowRef(); const [scrollState, setScrollState] = useLayoutState({ scrollLeft: 0, isHiddenScrollBar: true }); const refState = ref({ delta: 0, x: 0 }); const isActive = shallowRef(false); const onMouseUp = () => { isActive.value = false; }; const onMouseDown = event => { refState.value = { delta: event.pageX - scrollState.value.scrollLeft, x: 0 }; isActive.value = true; event.preventDefault(); }; const onMouseMove = event => { // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/buttons const { buttons } = event || (window === null || window === void 0 ? void 0 : window.event); if (!isActive.value || buttons === 0) { // If out body mouse up, we can set isActive false when mouse move if (isActive.value) { isActive.value = false; } return; } let left = refState.value.x + event.pageX - refState.value.x - refState.value.delta; if (left <= 0) { left = 0; } if (left + scrollBarWidth.value >= bodyWidth.value) { left = bodyWidth.value - scrollBarWidth.value; } emit('scroll', { scrollLeft: left / bodyWidth.value * (bodyScrollWidth.value + 2) }); refState.value.x = event.pageX; }; const onContainerScroll = () => { if (!props.scrollBodyRef.value) { return; } const tableOffsetTop = getOffset(props.scrollBodyRef.value).top; const tableBottomOffset = tableOffsetTop + props.scrollBodyRef.value.offsetHeight; const currentClientOffset = props.container === window ? document.documentElement.scrollTop + window.innerHeight : getOffset(props.container).top + props.container.clientHeight; if (tableBottomOffset - getScrollBarSize() <= currentClientOffset || tableOffsetTop >= currentClientOffset - props.offsetScroll) { setScrollState(state => _extends(_extends({}, state), { isHiddenScrollBar: true })); } else { setScrollState(state => _extends(_extends({}, state), { isHiddenScrollBar: false })); } }; const setScrollLeft = left => { setScrollState(state => { return _extends(_extends({}, state), { scrollLeft: left / bodyScrollWidth.value * bodyWidth.value || 0 }); }); }; expose({ setScrollLeft }); let onMouseUpListener = null; let onMouseMoveListener = null; let onResizeListener = null; let onScrollListener = null; onMounted(() => { onMouseUpListener = addEventListenerWrap(document.body, 'mouseup', onMouseUp, false); onMouseMoveListener = addEventListenerWrap(document.body, 'mousemove', onMouseMove, false); onResizeListener = addEventListenerWrap(window, 'resize', onContainerScroll, false); }); onActivated(() => { nextTick(() => { onContainerScroll(); }); }); onMounted(() => { setTimeout(() => { watch([scrollBarWidth, isActive], () => { onContainerScroll(); }, { immediate: true, flush: 'post' }); }); }); watch(() => props.container, () => { onScrollListener === null || onScrollListener === void 0 ? void 0 : onScrollListener.remove(); onScrollListener = addEventListenerWrap(props.container, 'scroll', onContainerScroll, false); }, { immediate: true, flush: 'post' }); onBeforeUnmount(() => { onMouseUpListener === null || onMouseUpListener === void 0 ? void 0 : onMouseUpListener.remove(); onMouseMoveListener === null || onMouseMoveListener === void 0 ? void 0 : onMouseMoveListener.remove(); onScrollListener === null || onScrollListener === void 0 ? void 0 : onScrollListener.remove(); onResizeListener === null || onResizeListener === void 0 ? void 0 : onResizeListener.remove(); }); watch(() => _extends({}, scrollState.value), (newState, preState) => { if (newState.isHiddenScrollBar !== (preState === null || preState === void 0 ? void 0 : preState.isHiddenScrollBar) && !newState.isHiddenScrollBar) { setScrollState(state => { const bodyNode = props.scrollBodyRef.value; if (!bodyNode) { return state; } return _extends(_extends({}, state), { scrollLeft: bodyNode.scrollLeft / bodyNode.scrollWidth * bodyNode.clientWidth }); }); } }, { immediate: true }); const scrollbarSize = getScrollBarSize(); return () => { if (bodyScrollWidth.value <= bodyWidth.value || !scrollBarWidth.value || scrollState.value.isHiddenScrollBar) { return null; } const { prefixCls } = tableContext; return _createVNode("div", { "style": { height: `${scrollbarSize}px`, width: `${bodyWidth.value}px`, bottom: `${props.offsetScroll}px` }, "class": `${prefixCls}-sticky-scroll` }, [_createVNode("div", { "onMousedown": onMouseDown, "ref": scrollBarRef, "class": classNames(`${prefixCls}-sticky-scroll-bar`, { [`${prefixCls}-sticky-scroll-bar-active`]: isActive.value }), "style": { width: `${scrollBarWidth.value}px`, transform: `translate3d(${scrollState.value.scrollLeft}px, 0, 0)` } }, null)]); }; } });