| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- import { defineComponent, computed, ref, reactive, unref, watch, onBeforeUnmount, h, withModifiers } from 'vue';
- import { HORIZONTAL, ScrollbarDirKey, SCROLLBAR_MIN_SIZE } from '../defaults.mjs';
- import { virtualizedScrollbarProps } from '../props.mjs';
- import { renderThumbStyle } from '../utils.mjs';
- import { BAR_MAP } from '../../../scrollbar/src/util.mjs';
- import { useNamespace } from '../../../../hooks/use-namespace/index.mjs';
- import { cAF, rAF } from '../../../../utils/raf.mjs';
- const ScrollBar = defineComponent({
- name: "ElVirtualScrollBar",
- props: virtualizedScrollbarProps,
- emits: ["scroll", "start-move", "stop-move"],
- setup(props, { emit }) {
- const GAP = computed(() => props.startGap + props.endGap);
- const nsVirtualScrollbar = useNamespace("virtual-scrollbar");
- const nsScrollbar = useNamespace("scrollbar");
- const trackRef = ref();
- const thumbRef = ref();
- let frameHandle = null;
- let onselectstartStore = null;
- const state = reactive({
- isDragging: false,
- traveled: 0
- });
- const bar = computed(() => BAR_MAP[props.layout]);
- const trackSize = computed(() => props.clientSize - unref(GAP));
- const trackStyle = computed(() => ({
- position: "absolute",
- width: `${HORIZONTAL === props.layout ? trackSize.value : props.scrollbarSize}px`,
- height: `${HORIZONTAL === props.layout ? props.scrollbarSize : trackSize.value}px`,
- [ScrollbarDirKey[props.layout]]: "2px",
- right: "2px",
- bottom: "2px",
- borderRadius: "4px"
- }));
- const thumbSize = computed(() => {
- const ratio = props.ratio;
- if (ratio >= 100) {
- return Number.POSITIVE_INFINITY;
- }
- if (ratio >= 50) {
- return ratio * trackSize.value / 100;
- }
- const SCROLLBAR_MAX_SIZE = trackSize.value / 3;
- return Math.floor(Math.min(Math.max(ratio * trackSize.value / 100, SCROLLBAR_MIN_SIZE), SCROLLBAR_MAX_SIZE));
- });
- const thumbStyle = computed(() => {
- if (!Number.isFinite(thumbSize.value)) {
- return {
- display: "none"
- };
- }
- const thumb = `${thumbSize.value}px`;
- const style = renderThumbStyle({
- bar: bar.value,
- size: thumb,
- move: state.traveled
- }, props.layout);
- return style;
- });
- const totalSteps = computed(() => Math.ceil(props.clientSize - thumbSize.value - unref(GAP)));
- const attachEvents = () => {
- window.addEventListener("mousemove", onMouseMove);
- window.addEventListener("mouseup", onMouseUp);
- const thumbEl = unref(thumbRef);
- if (!thumbEl)
- return;
- onselectstartStore = document.onselectstart;
- document.onselectstart = () => false;
- thumbEl.addEventListener("touchmove", onMouseMove, { passive: true });
- thumbEl.addEventListener("touchend", onMouseUp);
- };
- const detachEvents = () => {
- window.removeEventListener("mousemove", onMouseMove);
- window.removeEventListener("mouseup", onMouseUp);
- document.onselectstart = onselectstartStore;
- onselectstartStore = null;
- const thumbEl = unref(thumbRef);
- if (!thumbEl)
- return;
- thumbEl.removeEventListener("touchmove", onMouseMove);
- thumbEl.removeEventListener("touchend", onMouseUp);
- };
- const onThumbMouseDown = (e) => {
- e.stopImmediatePropagation();
- if (e.ctrlKey || [1, 2].includes(e.button)) {
- return;
- }
- state.isDragging = true;
- state[bar.value.axis] = e.currentTarget[bar.value.offset] - (e[bar.value.client] - e.currentTarget.getBoundingClientRect()[bar.value.direction]);
- emit("start-move");
- attachEvents();
- };
- const onMouseUp = () => {
- state.isDragging = false;
- state[bar.value.axis] = 0;
- emit("stop-move");
- detachEvents();
- };
- const onMouseMove = (e) => {
- const { isDragging } = state;
- if (!isDragging)
- return;
- if (!thumbRef.value || !trackRef.value)
- return;
- const prevPage = state[bar.value.axis];
- if (!prevPage)
- return;
- cAF(frameHandle);
- const offset = (trackRef.value.getBoundingClientRect()[bar.value.direction] - e[bar.value.client]) * -1;
- const thumbClickPosition = thumbRef.value[bar.value.offset] - prevPage;
- const distance = offset - thumbClickPosition;
- frameHandle = rAF(() => {
- state.traveled = Math.max(0, Math.min(distance, totalSteps.value));
- emit("scroll", distance, totalSteps.value);
- });
- };
- const clickTrackHandler = (e) => {
- const offset = Math.abs(e.target.getBoundingClientRect()[bar.value.direction] - e[bar.value.client]);
- const thumbHalf = thumbRef.value[bar.value.offset] / 2;
- const distance = offset - thumbHalf;
- state.traveled = Math.max(0, Math.min(distance, totalSteps.value));
- emit("scroll", distance, totalSteps.value);
- };
- watch(() => props.scrollFrom, (v) => {
- if (state.isDragging)
- return;
- state.traveled = Math.ceil(v * totalSteps.value);
- });
- onBeforeUnmount(() => {
- detachEvents();
- });
- return () => {
- return h("div", {
- role: "presentation",
- ref: trackRef,
- class: [
- nsVirtualScrollbar.b(),
- props.class,
- (props.alwaysOn || state.isDragging) && "always-on"
- ],
- style: trackStyle.value,
- onMousedown: withModifiers(clickTrackHandler, ["stop", "prevent"]),
- onTouchstartPrevent: onThumbMouseDown
- }, h("div", {
- ref: thumbRef,
- class: nsScrollbar.e("thumb"),
- style: thumbStyle.value,
- onMousedown: onThumbMouseDown
- }, []));
- };
- }
- });
- export { ScrollBar as default };
- //# sourceMappingURL=scrollbar.mjs.map
|