当前位置: 首页 > news >正文

vue3范围选择组件封装

个人项目地址: SubTopH前端开发个人站

(自己开发的前端功能和UI组件,一些有趣的小功能,感兴趣的伙伴可以访问,欢迎提出更好的想法,私信沟通,网站属于静态页面)

SubTopH前端开发个人站https://subtop.gitee.io/subtoph.github.io/#/home

以上 👆 是个人前端项目,欢迎提出您的建议😊

以下是正文内容...............

实现效果

直接上代码

组件文件

<template><div class="swh-range-page" :id="onlyId" ref="rangeRef"><div class="swh-range-selection" :id="onlyId + '_selection'"><!-- 滑动槽 --><div class="swh-trough" @click="handleTroughClick"></div><!-- 选中范围高亮条 --><pclass="swh-drag-trough":id="onlyId + '_drag-trough'"@click="handleTroughClick"></p><!-- 拖拽按钮 --><p class="swh-drag-btn" :id="onlyId + '_drag-btn'"></p><p class="drag-value" :id="onlyId + '_drag-value'">{{ rangValue }}</p></div></div>
</template><script>
import { reactive, toRefs, onBeforeMount, onMounted, ref, nextTick } from 'vue';
import { findCloseNum, handleStepNumber } from '@/utils/common.js';
export default {name: '',props: {minValue: {type: Number,default: 0,explain: '范围最小值',otherVal: '---'},maxValue: {type: Number,default: 100,explain: '范围最大值',},// 初始值initValue: {type: Number,default: 0,explain: '设置初始值',},// 是否设置初始值setInitValue: {type: Boolean,default: true,explain: '是否使用初始值(true时initValue有效)',},getRangChange: {type: Function,explain: '数值发生变化'}},setup(props, ctx) {const data = reactive({dragEle: null, //推拽槽元素rangeEle: null, //推拽按钮元素dragTrough: null, //推拽的条元素clickPos: 0, //点击移动按钮时鼠标距离父级的位置moveLeft: 0, //移动的leftrangeWidth: 0, //范围盒子宽度btnWidth: 0, //拖拽按钮尺寸rangValue: 0, //选中值optionalRange: 0, //实际范围rangArr: [], //范围段数组onlyId: ''});const rangeRef = ref(null); // 获取当前组件中外层元素onBeforeMount(() => {});onMounted(() => {nextTick(() => {// 获取组件数量const ele = document.getElementsByClassName('swh-range-page');if (ele.length) {for (let i = 0; i < ele.length; i++) {// 组件和当前ref获取的组件本身相等就设置idif (rangeRef.value === ele[i]) {data.onlyId = `swhRangeRef_${i}`; //设置显示框id}}}nextTick(() => {init();});});});const init = () => {const { onlyId } = data;data.rangeCom = document.querySelector(`#${onlyId}`);data.dragEle = document.querySelector(`#${onlyId}_drag-btn`);data.dragValueEle = document.querySelector(`#${onlyId}_drag-value`);data.rangeEle = document.querySelector(`#${onlyId}_selection`);data.dragTrough = document.querySelector(`#${onlyId}_drag-trough`);data.btnWidth = data.dragEle.offsetWidth;data.rangeWidth = data.rangeEle.offsetWidth;data.dragEle.style.left = -data.btnWidth / 2 + 'px';// 设置默认值,没有就是最小值const { setInitValue, initValue, minValue, maxValue } = props;if (setInitValue) {// 设置默认值if (initValue >= minValue && initValue <= maxValue) {// 初始值在范围内data.rangValue = initValue;} else {console.error('未设置初始值或者初始值超出范围');data.rangValue = minValue;}} else {// 未设置默认值,默认最小值data.rangValue = props.minValue;}// 最大值减区最小值是 实际范围data.optionalRange = props.maxValue - props.minValue;// 获取分割范围数组data.rangArr = handleStepNumber(data.rangeWidth, data.optionalRange);initMovePosition();bindEvent();};// 初始化值所在的位置const initMovePosition = () => {const index = rangNumArr().indexOf(data.rangValue);if (index !== -1) {const proportion = index / data.optionalRange;const initLeft = data.rangeWidth * proportion;data.moveLeft = initLeft;moveLeft();}};// 范围数值数组const rangNumArr = () => {let rNumArr = [];for (let i = 0; i < data.optionalRange + 1; i++) {rNumArr.push(props.minValue + i);}return rNumArr;};// 事件监听const bindEvent = () => {data.dragEle.addEventListener('mousedown', handleMouseDown, false);};// 按下事件const handleMouseDown = (e) => {// 点击时鼠标距离父级left    减去已经实际移动的距离data.clickPos = e.clientX - data.rangeEle.offsetLeft - data.moveLeft;document.addEventListener('mousemove', handleMouseMove, false);document.addEventListener('mouseup', handleMouseUp, false);};// 移动处理const handleMouseMove = (e) => {// 获取实际移动的位置,移动后left减去点击时clickPos(left)是实际移动的leftconst inMoveleft = e.clientX - data.rangeEle.offsetLeft;// 移动的距离  -  开始点击的位置 = 实际移动距离data.moveLeft = inMoveleft - data.clickPos;moveLeft();};// 直接点击范围条,改变拖拽按钮选中位置const handleTroughClick = (e) => {// 鼠标点击位置减去元素距离body的left,获取点击在跳上的left距离const inMoveleft = e.clientX - data.rangeCom.getBoundingClientRect().left;// 距离减去按钮宽度未实际移动leftdata.moveLeft = inMoveleft - data.btnWidth;moveLeft();};// 移动位置const moveLeft = () => {// 调整实际移动的距离if (data.moveLeft > data.rangeWidth) {// 最大限制data.moveLeft = data.rangeWidth;} else if (data.moveLeft < 0) {// 最小限制data.moveLeft = 0;} else {// 移动至鼠标最接近的范围点上data.moveLeft = findCloseNum(data.rangArr, data.moveLeft);}//按键 移动的距离减去按键一半宽度data.dragEle.style.left = data.moveLeft - data.btnWidth / 2 + 'px';//设置选中范围条宽度data.dragTrough.style.width = data.moveLeft + 'px';// 移动的占比const proportion = data.moveLeft / data.rangeWidth;// 计算移动的值data.rangValue =parseInt(data.optionalRange * proportion) + props.minValue;// 计算提示数值的偏移位置const wc = (data.dragValueEle.offsetWidth - data.btnWidth) / 2;// 设置显示范围值的提示位置,设置按钮的位置即可data.dragValueEle.style.left =data.dragEle.offsetLeft - Math.abs(wc) + 'px';ctx.emit('getRangChange', data.rangValue);};// 移除事件监听const handleMouseUp = () => {document.removeEventListener('mousemove', handleMouseMove, false);document.removeEventListener('mouseup', handleMouseUp, false);};return {rangeRef,handleTroughClick,...toRefs(data)};}
};
</script>
<style scoped lang="less">
.swh-range-page {position: relative;min-width: 160px;width: 100%;display: flex;padding: 0 20px;justify-content: center;border-radius: 10px;.swh-range-selection {position: relative;width: 100%;height: 30px;z-index: 9;.swh-trough {position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);width: 100%;height: 5px;background: rgb(243, 243, 243);border-radius: 3px;cursor: pointer;}.swh-drag-btn {position: absolute;top: 50%;left: 0;width: 20px;height: 20px;background: #fff;border: 2px solid @TSB;transform: translateY(-50%);border-radius: 50%;z-index: 1;cursor: pointer;box-sizing: border-box;&:hover {transform: translateY(-50%) scale(1.1);transition: 0.3s;}}.swh-drag-trough {cursor: pointer;position: absolute;top: 50%;left: 0;transform: translateY(-50%);background: @TSB;height: 5px;border-radius: 3px;}.drag-value {position: absolute;top: -20px;left: 0px;border-radius: 5px;width: 30px;height: 20px;background: rgba(0, 0, 0, 0.8);font-size: 12px;line-height: 20px;color: #fff;text-align: center;}}
}
</style>

 组件使用到的findCloseNum方法

// 判断当前数字  最靠近数组中那个数字
export function findCloseNum(arr, num) {var index = 0; // 保存最接近数值在数组中的索引var old_value = Number.MAX_VALUE; // 保存差值绝对值,默认为最大数值for (var i = 0; i < arr.length; i++) {var new_value = Math.abs(arr[i] - num); // 新差值if (new_value <= old_value) { // 如果新差值绝对值小于等于旧差值绝对值,保存新差值绝对值和索引if (new_value === old_value && arr[i] < arr[index]) { // 如果数组中两个数值跟目标数值差值一样,取大continue;}index = i;old_value = new_value;}}return arr[index] // 返回最接近的数值
}

 组件使用到的handleStepNumber方法

export function handleStepNumber(w, r) {const itemPx = w / r;let rangArr = [];for (let i = 0; i < r+1; i++) {rangArr.push(Math.ceil(itemPx * i));}return rangArr;
};

1.组件可以实现最小值和最大值的设置

2.可初始化值

3.组件长度根据父组件自定义

4.滑动和点击会改变范围值

根据自己的需求可进行更多扩展

相关文章:

vue3范围选择组件封装

个人项目地址&#xff1a; SubTopH前端开发个人站 &#xff08;自己开发的前端功能和UI组件&#xff0c;一些有趣的小功能&#xff0c;感兴趣的伙伴可以访问&#xff0c;欢迎提出更好的想法&#xff0c;私信沟通&#xff0c;网站属于静态页面&#xff09; SubTopH前端开发个人站…...

能被整除的数(容斥原理)

思路&#xff1a; &#xff08;1&#xff09;需求&#xff1a;求对于1~n中至少能被p1~pm至少1个整除的数的个数&#xff0c;由于都是质数&#xff0c;彼此互质&#xff0c;不需要进行质因子分解&#xff0c;根据容斥原理&#xff0c; res n/p1 n/p2 ... n/pm - n /(p1p2) -…...

Modbus转Profinet网关与流量变送器兼容转ModbusTCP协议博图配置

首先&#xff0c;我们需要明确电磁流量计的通信协议是Modbus&#xff0c;而西门子1200PLC的通信协议是Profinet。这两种协议在功能和特性上存在一定的差异&#xff0c;因此需要使用兴达易控Modbus转Profinet网关设备进行转换。兴达易控的XD-MDPN100是Profinet转ModbusTCP的网关…...

HLS实现CORDIC算法计算正余弦并上板验证

硬件&#xff1a;ZYNQ7010 软件&#xff1a;MATLAB 2019b、Vivado 2017.4、HLS 2017.4、System Generator 2017.4 1、CORDIC算法计算正余弦 CORDIC算法详细分析网上有很多资料&#xff0c;它的原理是用一系列旋转去逼近目标角度&#xff0c;这一系列旋转的角度为 θ a r c t…...

高阶数据结构并查集

目录&#xff1a; 并查集的概念代码实现 LeetCode例题 并查集的概念 将n个不同的元素划分成一些不相交的集合。开始时&#xff0c;每个元素自成一个单元元素集合&#xff0c;然后按一定的规律将归于同一组元素的集合合并。在此过程中反复遇到查询某一个元素属于那个集合的运算…...

WSL2连接不了外网怎么办?

某天忽然WLAN变成地球图标&#xff0c;上不了Internet&#xff0c;搞了半天网络适配器&#xff0c;仍然不行。回忆之前做过的操作&#xff0c;曾经运行过ZoogVPN&#xff0c;试着启动并连接&#xff0c;然后退出&#xff0c;WLAN神奇地恢复了连接&#xff0c;可以上Internet了。…...

【C/C++】探索内存对齐的奥秘与优势

目录 一&#xff0c;前言 二&#xff0c;什么是内存对齐&#xff1f; 三&#xff0c;内存对齐的原理 四&#xff0c;内存对齐的优势 五&#xff0c;如何实现内存对齐&#xff1f;&#xff08;看这节就行&#xff09; 1.使用 #pragma pack 来实现内存对齐的示例 七&#…...

leetcode分类刷题:滑动窗口(二、重复元素类型)

1、连续子数组、连续子串问题通常需要滑动窗口来求解&#xff0c;本篇文章对应的“二、重复元素类型”在此基础上对连续子数组、连续子串中重复元素个数、种类进行考察&#xff0c;此时&#xff0c;需要使用和维护哈希表进行左右指针的移动&#xff0c;因此这类题目对应的解法为…...

MySQL—buffer pool

一、buffer pool的介绍 Buffer pool是什么 一个内存区域&#xff0c;为了提⾼数据库的性能&#xff0c;数据库操作数据的时候&#xff0c;把硬盘上的数据加载到buffer pool&#xff0c;不直接和硬盘打交道&#xff0c;操作的是 buffer pool的数据&#xff0c;数据库的增删改查…...

《C和指针》笔记8: 枚举类型

枚举 (enumerated)类型就是指它的值为符号常量而不是字面值的类型&#xff0c;它们以下面这种形式声明&#xff1a; enum Jar_Type { CUP, PINT, QUART, HALF_GALLON, GALLON };这条语句声明了一个类型&#xff0c;称为Jar_Type。这种类型的变量按下列方式声明&#xff1a; e…...

Python爬虫框架之Selenium库入门:用Python实现网页自动化测试详解

概要 是否还在为网页测试而烦恼&#xff1f;是否还在为重复的点击、等待而劳累&#xff1f;试试强大的Selenium&#xff01;让你的网页自动化测试变得轻松有趣&#xff01; 一、Selenium库到底是什么&#xff1f; Selenium 是一个强大的自动化测试工具&#xff0c;它可以让你直…...

docker swarm 部署服务网络问题

docker swarm 服务部署问题 docker swarm 部署服务时可能会出现&#xff0c;启动服务特别慢的情况&#xff0c;甚至一个service 启动后&#xff0c;容器会长时间处于 preparing 状态&#xff0c;直到 状态切换成 running 状态后&#xff0c;才会启动下一个service。然后查询资…...

1.00001git源码clone后进行编译(带调试)

– 新建用户 useradd postgres passwd postgres – 用户加入sude组 先cd到/etc/sudoers目录下 由于sudoers文件为只读权限&#xff0c;所以需要添加写入权限&#xff0c;chmod uw sudoers vim sudoers 找到root ALL (ALL) ALL这一行&#xff0c;在下一行加入username ALL (A…...

使用StorageClass动态创建pv

rook-ceph安装部署到位后&#xff0c;就可以开始来尝试使用StorageClass来动态创建pv了。 有状态的中间件在kubernetes上落地基本上都会用到StorageClass来动态创建pv&#xff08;对于云上应用没有那么多烦恼&#xff0c;云硬盘很好用&#xff0c;但是对于自己学习和练习来说还…...

数据结构(Java实现)-ArrayList与顺序表

什么是List List是一个接口&#xff0c;继承自Collection。 List的使用 List是个接口&#xff0c;并不能直接用来实例化。 如果要使用&#xff0c;必须去实例化List的实现类。在集合框架中&#xff0c;ArrayList和LinkedList都实现了List接口。 线性表 线性表&#xff08;lin…...

性能优化维度

CPU 首先检查 cpu&#xff0c;cpu 使用率要提升而不是降低。其次CPU 空闲并不一定是没事做&#xff0c;也有可能是锁或者外部资源瓶颈。常用top、vmstat命令查看信息。 vmstat 命令: top: 命令 IO iostat 命令&#xff1a; Memory free 命令&#xff1a; 温馨提示&#xff1a…...

PMP P-06 Resource Management

...

【C++】map的奇葩用法:和函数结合

2023年8月26日&#xff0c;周六下午 今天才发现map居然还能这样用... #include <iostream> #include <map> #include <functional>void printOne() {std::cout << "已经打印出1" << std::endl; }void printTwo() {std::cout <<…...

关于JVM的参数类型

JVM参数类型&#xff0c;主要是可以分为三类。分别是&#xff1a; 标准参数 例如&#xff1a; -help-server-client-version-showversion-cp-classpath 等等&#xff0c;这类参数的特点是在jdk各版本里基本不会变的&#xff0c;相对稳定。 X参数 X参数也就是非标准化参数&am…...

HTTP协议中的Content-Type及其常见类型

什么是Content-Type&#xff1f; Content-Type是HTTP协议中的一个头部字段&#xff0c;用于指示请求或响应中所传输的实体的媒体类型。 为什么使用Content-Type&#xff1f; 使用Content-Type可以告知接收方如何解析和处理传输的数据&#xff0c;确保数据能够正确地被解析和…...

利用ngx_stream_return_module构建简易 TCP/UDP 响应网关

一、模块概述 ngx_stream_return_module 提供了一个极简的指令&#xff1a; return <value>;在收到客户端连接后&#xff0c;立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量&#xff08;如 $time_iso8601、$remote_addr 等&#xff09;&a…...

23-Oracle 23 ai 区块链表(Blockchain Table)

小伙伴有没有在金融强合规的领域中遇见&#xff0c;必须要保持数据不可变&#xff0c;管理员都无法修改和留痕的要求。比如医疗的电子病历中&#xff0c;影像检查检验结果不可篡改行的&#xff0c;药品追溯过程中数据只可插入无法删除的特性需求&#xff1b;登录日志、修改日志…...

基础测试工具使用经验

背景 vtune&#xff0c;perf, nsight system等基础测试工具&#xff0c;都是用过的&#xff0c;但是没有记录&#xff0c;都逐渐忘了。所以写这篇博客总结记录一下&#xff0c;只要以后发现新的用法&#xff0c;就记得来编辑补充一下 perf 比较基础的用法&#xff1a; 先改这…...

Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器

第一章 引言&#xff1a;语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域&#xff0c;文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量&#xff0c;支撑着搜索引擎、推荐系统、…...

c#开发AI模型对话

AI模型 前面已经介绍了一般AI模型本地部署&#xff0c;直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型&#xff0c;但是目前国内可能使用不多&#xff0c;至少实践例子很少看见。开发训练模型就不介绍了&am…...

MySQL用户和授权

开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务&#xff1a; test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

Python 包管理器 uv 介绍

Python 包管理器 uv 全面介绍 uv 是由 Astral&#xff08;热门工具 Ruff 的开发者&#xff09;推出的下一代高性能 Python 包管理器和构建工具&#xff0c;用 Rust 编写。它旨在解决传统工具&#xff08;如 pip、virtualenv、pip-tools&#xff09;的性能瓶颈&#xff0c;同时…...

五子棋测试用例

一.项目背景 1.1 项目简介 传统棋类文化的推广 五子棋是一种古老的棋类游戏&#xff0c;有着深厚的文化底蕴。通过将五子棋制作成网页游戏&#xff0c;可以让更多的人了解和接触到这一传统棋类文化。无论是国内还是国外的玩家&#xff0c;都可以通过网页五子棋感受到东方棋类…...

智能职业发展系统:AI驱动的职业规划平台技术解析

智能职业发展系统&#xff1a;AI驱动的职业规划平台技术解析 引言&#xff1a;数字时代的职业革命 在当今瞬息万变的就业市场中&#xff0c;传统的职业规划方法已无法满足个人和企业的需求。据统计&#xff0c;全球每年有超过2亿人面临职业转型困境&#xff0c;而企业也因此遭…...

从零开始了解数据采集(二十八)——制造业数字孪生

近年来&#xff0c;我国的工业领域正经历一场前所未有的数字化变革&#xff0c;从“双碳目标”到工业互联网平台的推广&#xff0c;国家政策和市场需求共同推动了制造业的升级。在这场变革中&#xff0c;数字孪生技术成为备受关注的关键工具&#xff0c;它不仅让企业“看见”设…...