当前位置: 首页 > 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;确保数据能够正确地被解析和…...

Linux 文件类型,目录与路径,文件与目录管理

文件类型 后面的字符表示文件类型标志 普通文件&#xff1a;-&#xff08;纯文本文件&#xff0c;二进制文件&#xff0c;数据格式文件&#xff09; 如文本文件、图片、程序文件等。 目录文件&#xff1a;d&#xff08;directory&#xff09; 用来存放其他文件或子目录。 设备…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)

文章目录 1.什么是Redis&#xff1f;2.为什么要使用redis作为mysql的缓存&#xff1f;3.什么是缓存雪崩、缓存穿透、缓存击穿&#xff1f;3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:

在 HarmonyOS 应用开发中&#xff0c;手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力&#xff0c;既支持点击、长按、拖拽等基础单一手势的精细控制&#xff0c;也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档&#xff0c…...

IGP(Interior Gateway Protocol,内部网关协议)

IGP&#xff08;Interior Gateway Protocol&#xff0c;内部网关协议&#xff09; 是一种用于在一个自治系统&#xff08;AS&#xff09;内部传递路由信息的路由协议&#xff0c;主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

Leetcode 3577. Count the Number of Computer Unlocking Permutations

Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接&#xff1a;3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯&#xff0c;要想要能够将所有的电脑解锁&#x…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…...

聊一聊接口测试的意义有哪些?

目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开&#xff0c;首…...

Docker 本地安装 mysql 数据库

Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker &#xff1b;并安装。 基础操作不再赘述。 打开 macOS 终端&#xff0c;开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...

解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用

在工业制造领域&#xff0c;无损检测&#xff08;NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统&#xff0c;以非接触式光学麦克风技术为核心&#xff0c;打破传统检测瓶颈&#xff0c;为半导体、航空航天、汽车制造等行业提供了高灵敏…...

阿里云Ubuntu 22.04 64位搭建Flask流程(亲测)

cd /home 进入home盘 安装虚拟环境&#xff1a; 1、安装virtualenv pip install virtualenv 2.创建新的虚拟环境&#xff1a; virtualenv myenv 3、激活虚拟环境&#xff08;激活环境可以在当前环境下安装包&#xff09; source myenv/bin/activate 此时&#xff0c;终端…...