@fesjs/fes-design
Version:
fes-design for PC
161 lines (156 loc) • 6.15 kB
JavaScript
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 };