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.滑动和点击会改变范围值

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/50974.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

react 11之 router6路由 (两种路由模式、两种路由跳转、两种传参与接收参数、嵌套路由,layout组件、路由懒加载)

目录 react路由1&#xff1a;安装和两种模式react路由2&#xff1a;两种路由跳转 &#xff08; 命令式与编程式&#xff09;2-1 路由跳转-命令式2-2 路由跳转-编程式 - 函数组件2-2-1 app.jsx2-2-2 page / Home.jsx2-2-3 page / About.jsx2-2-4 效果 react路由3&#xff1a;函数…

mysql 8.0 窗口函数 之 分布函数 与 sql server (2017以后支持) 分布函数 一样

mysql 分布函数 percent_rank&#xff08;&#xff09; &#xff1a;等级值 百分比cume_dist() &#xff1a;累积分布值 percent_rank&#xff08;&#xff09; 计算方式 (rank-1)/(rows-1)&#xff0c; 其中 rank 的值为使用RANK()函数产生的序号&#xff0c;rows 的值为当前…

进行Stable Diffusion的ai训练怎么选择显卡?

Stable Diffusion主要用于从文本生成图像&#xff0c;是人工智能技术在内容创作行业中不断发展的应用。要在本地计算机上运行Stable Diffusion&#xff0c;您需要一个强大的 GPU 来满足其繁重的要求。强大的 GPU 可以让您更快地生成图像&#xff0c;而具有大量 VRAM 的更强大的…

奥威BI数据可视化工具:个性化定制,打造独特大屏

每个人都有自己独特的审美&#xff0c;因此即使是做可视化大屏&#xff0c;也有很多人希望做出不一样的报表&#xff0c;用以缓解审美疲劳的同时提高报表浏览效率。因此这也催生出了数据可视化工具的个性化可视化大屏制作需求。 奥威BI数据可视化工具&#xff1a;个性化定制&a…

在Linux系统上安装和配置Redis数据库,无需公网IP即可实现远程连接的详细解析

文章目录 1. Linux(centos8)安装redis数据库2. 配置redis数据库3. 内网穿透3.1 安装cpolar内网穿透3.2 创建隧道映射本地端口 4. 配置固定TCP端口地址4.1 保留一个固定tcp地址4.2 配置固定TCP地址4.3 使用固定的tcp地址连接 Redis作为一款高速缓存的key value键值对的数据库,在…

消息队列——RabbitMQ(一)

MQ的相关概念 什么事mq MQ(message queue)&#xff0c;从字面意思上看&#xff0c;本质是个队列&#xff0c;FIFO 先入先出&#xff0c;只不过队列中存放的内容是 message 而已&#xff0c;还是一种跨进程的通信机制&#xff0c;用于上下游传递消息。在互联网架构中&#xff…

【Python爬虫案例】爬取大麦网任意城市的近期演出!

老规矩&#xff0c;先上结果&#xff1a; 含10个字段&#xff1a; 页码&#xff0c;演出标题&#xff0c;链接地址&#xff0c;演出时间&#xff0c;演出城市&#xff0c;演出地点&#xff0c;售价&#xff0c;演出类别&#xff0c;演出子类别&#xff0c;售票状态。 代码演示…

一款打工人必备的电脑端自律软件!!冲鸭打工人!!

你&#xff01;有没有渴望进步&#xff01;&#xff01; 你&#xff01;有没有渴望变强&#xff01;&#xff01;&#xff01; 成为大佬&#xff01;&#xff01;&#xff01;超越巨佬&#xff01;&#xff01;&#xff01; 这就是一款为这样的你量身定做的程序&#xff1a;输入…

vue3 tailwindcss的使用

首先安装依赖&#xff1a; npm install -D tailwindcsslatest postcsslatest autoprefixerlatestnpm i -D unocss 然后vite.config.ts中 引入 import Unocss from unocss/viteexport default defineConfig({plugins: [Unocss(),],})终端执行&#xff1a; npx tailwindcss in…

【HTML】HTML面试知识梳理

目录 DOCTYPE&#xff08;文章类型&#xff09;head标签浏览器乱码的原因及解决常用的meta标签与SEOscript标签中defer和async的区别src&href区别HTML5有哪些更新语义化标签媒体标签表单进度条、度量器DOM查询Web存储Canvas和SVG拖放 &#xff08;HTML5 drag API&#xff0…

跨平台图表:ChartDirector for .NET 7.1 Crack

什么是新的 ChartDirector for .NET 7.0 支持跨平台使用&#xff0c;但仅限于 .NET 6。这是因为在 .NET 7 中&#xff0c;Microsoft 停止了用于非 Windows 使用的 .NET 图形库 System.Drawing.Common。由于 ChartDirector for .NET 7.0 依赖于该库&#xff0c;因此它不再支持 .…

村口的人家排放污水,污水浸染了整个村子,怎么办

从前有一个很不错的村子里&#xff0c;村子里有很多户人家&#xff0c;随着生活水平越来越好&#xff0c;房子也修起来了&#xff0c;柏油马路也宽敞了&#xff0c;大家进出村子&#xff0c;都要走那条马路&#xff0c;要不就出不去。 目录 1. 修厕所 2. 村口的日家 3. 告诉…

如何利用SFTP如何实现更安全的远程文件传输 ——【内网穿透】

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《高效编程技巧》《cpolar》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 1. 安装openSSH1.1 安装SSH1.2 启动ssh 2. 安装cpolar2.1 配置termux服务 3. 远程SFTP连接配置3.1 查看生成的随机公…

CSS 实现页面底部加载中与加载完毕效果

效果图 实现代码 <view class"bottom-load-tip"><view class"line-tip"></view><view class"loading-animation" v-if"!lastPage"></view><view>{{ lastPage ? "没有更多了" : "…

【深度学习 | 感知器 MLP(BP神经网络)】掌握感知的艺术: 感知器和MLP-BP如何革新神经网络

&#x1f935;‍♂️ 个人主页: AI_magician &#x1f4e1;主页地址&#xff1a; 作者简介&#xff1a;CSDN内容合伙人&#xff0c;全栈领域优质创作者。 &#x1f468;‍&#x1f4bb;景愿&#xff1a;旨在于能和更多的热爱计算机的伙伴一起成长&#xff01;&#xff01;&…

学会Mybatis框架:一文掌握MyBatis与GitHub插件分页的完美结合【三.分页】

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于Mybatis的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一.Mybatis分页 1. Mybatis自带分页 2…

如何使用CSS实现一个拖拽排序效果?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 实现拖拽排序效果的CSS和JavaScript示例⭐ HTML 结构⭐ CSS 样式 (styles.css)⭐ JavaScript 代码 (script.js)⭐ 实现说明⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦…

在自定义数据集上使用 Detectron2 和 PyTorch 进行人脸检测

本文讲讲述如何使用Python在自定义人脸检测数据集上微调预训练的目标检测模型。学习如何为Detectron2和PyTorch准备自定义人脸检测数据集&#xff0c;微调预训练模型以在图像中找到人脸边界。 人脸检测是在图像中找到&#xff08;边界的&#xff09;人脸的任务。这在以下情况下…

基于前端技术原生HTML、JS、CSS 电子病历编辑器源码

电子病历系统采取结构化与自由式录入的新模式&#xff0c;自由书写&#xff0c;轻松录入。实现病人医疗记录&#xff08;包含有首页、病程记录、检查检验结果、医嘱、手术记录、护理记录等等。&#xff09;的保存、管理、传输和重现&#xff0c;取代手写纸张病历。不仅实现了纸…

centos7.9和redhat6.9 离线升级OpenSSH和openssl (2023年的版本)

升级注意事项&#xff01; 1、多开几个连接窗口&#xff08;xshell&#xff09;&#xff0c;避免升级openssh失败无法再次连接终端&#xff0c;否则要跑机房了。 2、可开启telnet服务、vnc服务、打快照。多几个“保命”的路数。一、centos7.9的信息 [rootnode2 ~]# openssl v…