UNPKG

@fesjs/fes-design

Version:
161 lines (156 loc) 6.15 kB
import { defineComponent, computed, ref, onMounted, nextTick, onBeforeUnmount, openBlock, createBlock, Transition, withCtx, withDirectives, createElementVNode, normalizeClass, withModifiers, normalizeStyle, vShow } from 'vue'; import { useEventListener } from '@vueuse/core'; import getPrefixCls from '../_util/getPrefixCls'; import { BAR_MAP } from './const'; const prefixCls = getPrefixCls('scrollbar-track'); function renderThumbStyle(_ref) { let { move, size, bar } = _ref; const style = {}; const translate = `translate${bar.axis}(${move}%)`; style[bar.size] = size; style.transform = translate; return style; } const barProps = { vertical: Boolean, size: String, move: Number, ratio: Number, always: Boolean, scrollbarRef: Array, containerRef: Object, thumbStyle: [String, Array, Object] }; var script = defineComponent({ name: 'FBar', props: barProps, setup(props) { const containerRef = computed(() => props.containerRef); const barStore = ref({}); const barRef = ref(); const thumbRef = ref(); const barMap = computed(() => BAR_MAP[props.vertical ? 'vertical' : 'horizontal']); const thumbStyle = computed(() => [renderThumbStyle({ size: props.size, move: props.move, bar: barMap.value }), props.thumbStyle]); const offsetRatio = computed(() => barRef.value[barMap.value.offset] ** 2 / containerRef.value[barMap.value.scrollSize] / props.ratio / thumbRef.value[barMap.value.offset]); const visible = ref(false); const cursorLeave = ref(); const cursorDown = ref(); let onselectstartStore = null; const mouseMoveDocumentHandler = e => { if (cursorDown.value === false) { return; } const prevPage = barStore.value[barMap.value.axis]; if (!prevPage) { return; } const offset = (barRef.value.getBoundingClientRect()[barMap.value.direction] - e[barMap.value.client]) * -1; const thumbClickPosition = thumbRef.value[barMap.value.offset] - prevPage; const thumbPositionPercentage = (offset - thumbClickPosition) * 100 * offsetRatio.value / barRef.value[barMap.value.offset]; containerRef.value[barMap.value.scroll] = thumbPositionPercentage * containerRef.value[barMap.value.scrollSize] / 100; }; let docMouseMoveClose; const mouseUpDocumentHandler = () => { var _docMouseMoveClose; cursorDown.value = false; barStore.value[barMap.value.axis] = 0; (_docMouseMoveClose = docMouseMoveClose) === null || _docMouseMoveClose === void 0 || _docMouseMoveClose(); document.onselectstart = onselectstartStore; if (cursorLeave.value) { visible.value = false; } }; const startDrag = e => { e.stopImmediatePropagation(); cursorDown.value = true; docMouseMoveClose = useEventListener(document, 'mousemove', mouseMoveDocumentHandler); useEventListener(document, 'mouseup', mouseUpDocumentHandler); onselectstartStore = document.onselectstart; document.onselectstart = () => false; }; const mouseMoveScrollbarHandler = () => { cursorLeave.value = false; visible.value = !!props.size; }; const mouseLeaveScrollbarHandler = () => { cursorLeave.value = true; visible.value = cursorDown.value; }; onMounted(() => { nextTick(() => { props.scrollbarRef.forEach(item => { useEventListener(item, 'mouseenter', mouseMoveScrollbarHandler); useEventListener(item, 'mousemove', mouseMoveScrollbarHandler); useEventListener(item, 'mouseleave', mouseLeaveScrollbarHandler); }); }); }); const clickTrackHandler = e => { const offset = Math.abs(e.target.getBoundingClientRect()[barMap.value.direction] - e[barMap.value.client]); const thumbHalf = thumbRef.value[barMap.value.offset] / 2; const thumbPositionPercentage = (offset - thumbHalf) * 100 * offsetRatio.value / barRef.value[barMap.value.offset]; containerRef.value[barMap.value.scroll] = thumbPositionPercentage * containerRef.value[barMap.value.scrollSize] / 100; }; const clickThumbHandler = e => { // prevent click event of middle and right button e.stopPropagation(); if (e.ctrlKey || [1, 2].includes(e.button)) { return; } window.getSelection().removeAllRanges(); startDrag(e); barStore.value[barMap.value.axis] = e.currentTarget[barMap.value.offset] - (e[barMap.value.client] - e.currentTarget.getBoundingClientRect()[barMap.value.direction]); }; onBeforeUnmount(() => { // 确保在组件卸载时清理所有状态 if (cursorDown.value) { mouseUpDocumentHandler(); } onselectstartStore = null; }); return { prefixCls, barRef, thumbRef, visible, cursorDown, barMap, thumbStyle, clickTrackHandler, clickThumbHandler }; } }); function render(_ctx, _cache, $props, $setup, $data, $options) { return openBlock(), createBlock(Transition, { name: `${_ctx.prefixCls}-fade`, persisted: "" }, { default: withCtx(() => [withDirectives(createElementVNode("div", { ref: "barRef", class: normalizeClass([_ctx.prefixCls, `is-${_ctx.barMap.key}`, _ctx.cursorDown && `is-hovering`]), onMousedown: _cache[1] || (_cache[1] = withModifiers(function () { return _ctx.clickTrackHandler && _ctx.clickTrackHandler(...arguments); }, ["stop", "prevent"])) }, [createElementVNode("div", { ref: "thumbRef", class: normalizeClass([`${_ctx.prefixCls}-thumb`]), style: normalizeStyle(_ctx.thumbStyle), onMousedown: _cache[0] || (_cache[0] = withModifiers(function () { return _ctx.clickThumbHandler && _ctx.clickThumbHandler(...arguments); }, ["stop", "prevent"])) }, null, 38 /* CLASS, STYLE, NEED_HYDRATION */)], 34 /* CLASS, NEED_HYDRATION */), [[vShow, _ctx.always || _ctx.visible]])]), _: 1 /* STABLE */ }, 8 /* PROPS */, ["name"]); } script.render = render; script.__file = "components/scrollbar/bar.vue"; export { script as default };