vue-devui
Version:
DevUI components based on Vite and Vue3
209 lines (208 loc) • 6.43 kB
JavaScript
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 };