UNPKG

vue-devui

Version:

DevUI components based on Vite and Vue3

209 lines (208 loc) 6.43 kB
import { ref, watch, onMounted, defineComponent, computed, createVNode } from "vue"; import "clipboard"; const sliderProps = { disabled: { type: Boolean, default: false }, max: { type: Number, default: 100 }, min: { type: Number, default: 0 }, modelValue: { type: Number, default: 0 }, step: { type: Number, default: 1 }, tipsRenderer: { type: [Function, null], default: () => (value) => `${value}` } }; const isFunction = (value) => Object.prototype.toString.call(value) === "[object Function]"; function createBem(namespace, element, modifier) { let cls = namespace; if (element) { cls += `__${element}`; } if (modifier) { cls += `--${modifier}`; } return cls; } function useNamespace(block, needDot = false) { const namespace = needDot ? `.devui-${block}` : `devui-${block}`; const b = () => createBem(namespace); const e = (element) => element ? createBem(namespace, element) : ""; const m = (modifier) => modifier ? createBem(namespace, "", modifier) : ""; const em = (element, modifier) => element && modifier ? createBem(namespace, element, modifier) : ""; return { b, e, m, em }; } function useSliderEvent(props, ctx) { let isClick = true; let startPosition = 0; let startX = 0; const sliderRunway = ref(); const currentValue = ref(Number(props.modelValue)); const currentPosition = ref(0); const percentDisplay = ref(""); const popoverShow = ref(false); const newPosition = ref(0); function getSliderWidth() { var _a; return Boolean(sliderRunway.value) ? ((_a = sliderRunway.value) == null ? void 0 : _a.clientWidth) || 0 : 0; } function initCurrentPosition() { const sliderWidth = getSliderWidth(); currentPosition.value = sliderWidth * (currentValue.value - props.min) / (props.max - props.min); } function setPosition(position) { const clientWidth = getSliderWidth(); const sliderWidth = Math.round(clientWidth); if (position < 0) { position = 0; } const LengthPerStep = sliderWidth / ((props.max - props.min) / props.step); const steps = Math.round(position / LengthPerStep); const value = steps * LengthPerStep; if (Math.round(value) >= sliderWidth) { currentPosition.value = sliderWidth; currentValue.value = props.max; percentDisplay.value = "100%"; ctx.emit("update:modelValue", props.max); return; } percentDisplay.value = Math.round(value * 100 / sliderWidth) + "%"; currentValue.value = Math.round(value * (props.max - props.min) / sliderWidth) + props.min; currentPosition.value = position; ctx.emit("update:modelValue", currentValue.value); } function dragStart(event) { isClick = false; startX = event.clientX; startPosition = currentPosition.value; newPosition.value = startPosition; } function onDragging(event) { popoverShow.value = true; const currentX = event.clientX; const pxOffset = currentX - startX; newPosition.value = startPosition + pxOffset; setPosition(newPosition.value); } function onDragEnd() { popoverShow.value = false; setTimeout(() => { isClick = true; }, 100); window.removeEventListener("mousemove", onDragging); window.removeEventListener("mouseup", onDragEnd); } function handleButtonMousedown(event) { popoverShow.value = true; if (!props.disabled) { event.preventDefault(); dragStart(event); window.addEventListener("mousemove", onDragging); window.addEventListener("mouseup", onDragEnd); } } function handleRunwayMousedown(event) { if (!props.disabled && isClick) { const _e = event.target; startX = _e.getBoundingClientRect().left; const currentX = event.clientX; setPosition(currentX - startX); handleButtonMousedown(event); } } watch( [() => props.modelValue, () => props.max, () => props.min], () => { currentValue.value = Number(props.modelValue); if (currentValue.value > props.max) { percentDisplay.value = "100%"; } else if (currentValue.value < props.min) { percentDisplay.value = "0%"; } else { percentDisplay.value = (currentValue.value - props.min) * 100 / (props.max - props.min) + "%"; } initCurrentPosition(); }, { immediate: true } ); onMounted(initCurrentPosition); return { sliderRunway, popoverShow, percentDisplay, currentValue, handleRunwayMousedown, handleButtonMousedown }; } var slider = ""; var Slider = defineComponent({ name: "DSlider", props: sliderProps, emits: ["update:modelValue"], setup(props, ctx) { const ns = useNamespace("slider"); const { sliderRunway, popoverShow, percentDisplay, currentValue, handleRunwayMousedown, handleButtonMousedown } = useSliderEvent(props, ctx); const disableClass = computed(() => { return props.disabled ? " disabled" : ""; }); const tipsContent = computed(() => isFunction(props.tipsRenderer) ? props.tipsRenderer(currentValue.value) : ""); return () => createVNode("div", { "class": ns.b() }, [createVNode("div", { "ref": sliderRunway, "class": [ns.e("runway"), disableClass.value], "onMousedown": handleRunwayMousedown, "onMouseout": () => popoverShow.value = false }, [createVNode("div", { "class": [ns.e("bar"), disableClass.value], "style": { width: percentDisplay.value } }, null), createVNode("div", { "class": [ns.e("button"), disableClass.value], "style": { left: percentDisplay.value }, "onMousedown": handleButtonMousedown, "onMouseenter": () => popoverShow.value = true, "onMouseout": () => popoverShow.value = false }, null), props.tipsRenderer === null ? null : popoverShow.value ? createVNode("div", { "class": ns.e("popover"), "style": { left: percentDisplay.value } }, [createVNode("div", { "class": ns.e("popover-arrow") }, null), createVNode("div", { "class": ns.e("popover-content") }, [tipsContent.value])]) : null])]); } }); var index = { title: "Slider \u6ED1\u5757", category: "\u6570\u636E\u5F55\u5165", status: "100%", install(app) { app.component(Slider.name, Slider); } }; export { Slider, index as default, sliderProps };