El-slider 增加鼠标滚动滑块事件

为了实现鼠标悬停在滑块区域时通过滚轮(Mouse Wheel)改变数值,我们需要做以下两件事:

监听滚轮事件 (wheel):在包裹滑块的容器上监听该事件。

计算新数值:根据滚动的方向(向上或向下)以及设定的 step(步长)来增加或减少数值,同时确保不超出 minmax 的范围,并处理好精度 (precision)。

下面是修改后的完整代码。我使用了 Vue 的事件修饰符 @wheel.prevent,这样当你在滑块上滚动时,页面不会跟着滚动,体验会更好。

javascript 复制代码
<template>
    <div class="slider-container">
        <div class="slider-header">
            <span class="slider-label">{{ label }}</span>
            <el-input-number
                v-if="showInput"
                v-model="inputValue"
                :min="min"
                :max="max"
                :step="step"
                :precision="precision"
                :size="size"
                controls-position="right"
                class="value-input"
                @change="handleInputChange"
            />
            <span v-else class="slider-value"> {{ formattedValue }}{{ unit }} </span>
        </div>

        <div class="slider-with-labels" @wheel.prevent="handleWheel">
            <span class="min-label" v-if="showLimitLabels">{{ min }}{{ unit }}</span>
            <el-slider
                :model-value="modelValue"
                :min="min"
                :max="max"
                :step="step"
                :show-tooltip="showTooltip"
                :format-tooltip="formatTooltip"
                :size="size"
                :disabled="disabled"
                @update:model-value="handleInput"
                @change="handleChange"
                class="slider"
            />
            <span class="max-label" v-if="showLimitLabels">{{ max }}{{ unit }}</span>
        </div>
    </div>
</template>

<script setup>
import { computed } from "vue";

const props = defineProps({
    modelValue: {
        type: Number,
        required: true,
    },
    label: {
        type: String,
        default: "",
    },
    min: {
        type: Number,
        default: 0,
    },
    max: {
        type: Number,
        default: 100,
    },
    step: {
        type: Number,
        default: 1,
        validator: (value) => value > 0,
    },
    precision: {  // elInputNumber数值精度
        type: Number,
        default: 0,
        validator: (value) => value >= 0,
    },
    unit: {
        type: String,
        default: "mm",
    },
    size: {
        type: String,
        default: "small",
        validator: (value) => ["small", "medium", "large"].includes(value),
    },
    showTooltip: {
        type: Boolean,
        default: false,
    },
    showInput: {
        type: Boolean,
        default: false,
    },
    disabled: {
        type: Boolean,
        default: false,
    },
    showLimitLabels: {
        type: Boolean,
        default: true,
    },
});

const emit = defineEmits(["update:modelValue", "change"]);

const inputValue = computed({
    get: () => props.modelValue,
    set: (value) => emit("update:modelValue", value),
});

const formattedValue = computed(() => {
    return props.precision > 0 ? props.modelValue.toFixed(props.precision) : props.modelValue;
});

const formatTooltip = (value) => {
    return props.precision > 0 ? value.toFixed(props.precision) + props.unit : value + props.unit;
};

const handleInput = (value) => {
    emit("update:modelValue", value);
};

const handleChange = (value) => {
    emit("change", value);
};

const handleInputChange = (value) => {
    emit("update:modelValue", value);
    emit("change", value);
};
// 👇👇👇 handleWheel  
const handleWheel = (event) => {
    // 如果禁用了组件,则不处理
    if (props.disabled) return;

    // deltaY < 0 表示向上滚动(数值增加),> 0 表示向下滚动(数值减少)
    const isIncrease = event.deltaY < 0;

    // 根据 step 计算变化量
    const changeAmount = isIncrease ? props.step : -props.step;

    // 计算新值
    let newValue = props.modelValue + changeAmount;

    // 边界检查:确保不超出 min 和 max
    if (newValue > props.max) newValue = props.max;
    if (newValue < props.min) newValue = props.min;


    //计算 step 本身的小数位数
    const stepString = props.step.toString()
    const dotIndex = stepString.indexOf('.')
    let stepPrecision = 0
    if (dotIndex !== -1) {
        stepPrecision = stepString.length - dotIndex - 1
    }

    //取 props.precision 和 stepPrecision 中的较大值
    const finalPrecision = Math.max(props.precision, stepPrecision)

    newValue = parseFloat(newValue.toFixed(finalPrecision))

    // 如果数值确实发生了变化,则触发更新
    if (newValue !== props.modelValue) {
        emit("update:modelValue", newValue);
        // 同时也触发 change 事件,保持与 el-slider 行为一致
        emit("change", newValue);
    }
};
</script>

.slider-with-labels div 上添加了 @wheel.prevent="handleWheel"

之所以加在.slider-with-labels而不是直接加在<el-slider>上,是因为 el-slider 的实际 DOM 结构比较复杂,且有时鼠标悬停在轨道边缘(Label 附近)时用户也期望能滚动。加在父容器上能增大"热区",体验更流畅。

相关推荐
AI即插即用1 天前
即插即用系列(代码实践)专栏介绍
开发语言·人工智能·深度学习·计算机视觉
码农水水1 天前
蚂蚁Java面试被问:混沌工程在分布式系统中的应用
java·linux·开发语言·面试·职场和发展·php
喵了meme1 天前
c语言经验分享
c语言·开发语言
Knight_AL1 天前
用 JOL 验证 synchronized 的锁升级过程(偏向锁 → 轻量级锁 → 重量级锁)
开发语言·jvm·c#
啊阿狸不会拉杆1 天前
《数字图像处理》第 4 章 - 频域滤波
开发语言·python·数字信号处理·数字图像处理·频率域滤波
悟能不能悟1 天前
前端上载文件时,上载多个文件,但是一个一个调用接口,怎么实现
前端
江沉晚呤时1 天前
从零实现 C# 插件系统:轻松扩展应用功能
java·开发语言·microsoft·c#
Knight_AL1 天前
Java 多态详解:概念、实现机制与实践应用
java·开发语言
Omigeq1 天前
1.2.1 - 图搜索算法(以A*为例) - Python运动规划库教程(Python Motion Planning)
开发语言·python·机器人·图搜索算法
资深流水灯工程师1 天前
基于Python的Qt开发之Pyside6 串口接收数据被分割的解决方案
开发语言·python·qt