@opensig/opendesign
Version:
<p align="center"><img src="../docs/public/opendesign-logo-light.png"/></p> <h1 align="center">opendesign</h1> <p align="center">一个 Vue 3 组件库</p> <p align="center"><b>皮肤可定制,使用 TypeScript</b></p>
207 lines (206 loc) • 6.45 kB
JavaScript
import { defineComponent, computed, ref, watch, onMounted, withDirectives, createElementBlock, openBlock, normalizeClass, createElementVNode, renderSlot, withModifiers, normalizeStyle, unref } from "vue";
import { vOnResize } from "../directives/on-resize.mjs";
const _sfc_main = /* @__PURE__ */ defineComponent({
__name: "ScrollbarRail",
props: {
direction: { default: "y" },
thumbRate: {},
offsetRate: { default: 0 },
notStepJump: { type: Boolean },
size: { default: "medium" }
},
emits: ["scroll"],
setup(__props, { emit: __emit }) {
const props = __props;
const emits = __emit;
const isY = computed(() => props.direction === "y");
const isDarggingBar = ref(false);
const barRef = ref(null);
const thumbRef = ref(null);
const trackLength = ref(0);
const thumbSize = computed(() => {
if (trackLength.value && props.thumbRate) {
return Math.round(trackLength.value * props.thumbRate);
}
return 0;
});
const thumbSizeStyle = computed(() => {
return `${thumbSize.value}px`;
});
const maxOffset = computed(() => trackLength.value - thumbSize.value);
const sizeProp = computed(() => {
return isY.value ? "height" : "width";
});
const offsetProp = computed(() => {
return isY.value ? "translateY" : "translateX";
});
const offset = ref(0);
watch(
() => [props.offsetRate, trackLength.value],
(val) => {
if (!isDarggingBar.value) {
offset.value = Math.round(val[1] * val[0]);
}
},
{
immediate: true
}
);
const offsetStyle = computed(() => {
return `${offsetProp.value}(${offset.value}px)`;
});
const adjustOffset = (pos) => {
if (pos < 0) {
return 0;
}
if (pos > maxOffset.value) {
return maxOffset.value;
}
return pos;
};
onMounted(() => {
if (!barRef.value) {
return;
}
const { offsetHeight, offsetWidth } = barRef.value;
trackLength.value = props.direction === "x" ? offsetWidth : offsetHeight;
});
let s = 0;
let oldOffset = 0;
const onMouseMove = (e) => {
const pos = isY.value ? e.clientY : e.clientX;
const v = oldOffset + pos - s;
const of = adjustOffset(v);
if (of !== offset.value) {
offset.value = of;
emits("scroll", offset.value / trackLength.value);
}
};
const onMouseUp = () => {
isDarggingBar.value = false;
window.removeEventListener("mousemove", onMouseMove);
window.removeEventListener("mouseup", onMouseUp);
window.removeEventListener("contextmenu", onMouseUp);
};
const onThumbMouseDown = (e) => {
e.preventDefault();
e.stopPropagation();
isDarggingBar.value = true;
s = isY.value ? e.clientY : e.clientX;
oldOffset = offset.value;
window.addEventListener("mousemove", onMouseMove);
window.addEventListener("mouseup", onMouseUp);
window.addEventListener("contextmenu", onMouseUp);
};
const onTrackClick = (e) => {
e.preventDefault();
if (!thumbRef.value || !barRef.value) {
return;
}
const pos = isY.value ? e.clientY : e.clientX;
let v = 0;
if (props.notStepJump) {
const bc = barRef.value.getBoundingClientRect();
v = pos - (isY.value ? bc.top : bc.left) - thumbSize.value / 2;
} else {
const bc = thumbRef.value.getBoundingClientRect();
const isPlus = pos > (isY.value ? bc.top : bc.left);
v = offset.value + thumbSize.value * (isPlus ? 1 : -1);
}
const of = adjustOffset(v);
if (of !== offset.value) {
offset.value = of;
emits("scroll", offset.value / trackLength.value);
}
};
const onResize = () => {
if (!barRef.value) {
return;
}
const { offsetHeight, offsetWidth } = barRef.value;
trackLength.value = props.direction === "x" ? offsetWidth : offsetHeight;
};
return (_ctx, _cache) => {
return withDirectives((openBlock(), createElementBlock(
"div",
{
ref_key: "barRef",
ref: barRef,
class: normalizeClass(["o-scrollbar-rail", [
`o-scrollbar-${props.direction}`,
`o-scrollbar-${props.size}`,
{
"o-scrollbar-dragging": isDarggingBar.value
}
]]),
onClick: onTrackClick
},
[
createElementVNode(
"div",
{
ref_key: "thumbRef",
ref: thumbRef,
class: normalizeClass(["o-scrollbar-thumb", [
`o-scrollbar-${props.direction}-thumb`,
{
[`o-scrollbar-${props.direction}-thumb-dragging`]: isDarggingBar.value
}
]]),
style: normalizeStyle({
[sizeProp.value]: thumbSizeStyle.value,
transform: offsetStyle.value
}),
onClick: _cache[0] || (_cache[0] = withModifiers(() => {
}, ["stop"])),
onMousedown: onThumbMouseDown
},
[
renderSlot(_ctx.$slots, "thumb", {
direction: props.direction,
dragging: isDarggingBar.value
}, () => [
createElementVNode(
"div",
{
class: normalizeClass([
`o-scrollbar-${props.direction}-thumb-bar`,
{
"is-dragging": isDarggingBar.value
}
])
},
null,
2
/* CLASS */
)
])
],
38
/* CLASS, STYLE, NEED_HYDRATION */
),
renderSlot(_ctx.$slots, "track", {
direction: props.direction
}, () => [
createElementVNode(
"div",
{
class: normalizeClass(["o-scrollbar-track", [`o-scrollbar-${props.direction}-track`]])
},
null,
2
/* CLASS */
)
])
],
2
/* CLASS */
)), [
[unref(vOnResize), onResize]
]);
};
}
});
export {
_sfc_main as default
};