vue3范围选择组件封装

news2025/1/20 7:14:36

个人项目地址: 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>
      <!-- 选中范围高亮条 -->
      <p
        class="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, //移动的left
      rangeWidth: 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获取的组件本身相等就设置id
            if (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)是实际移动的left
      const 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;
      // 距离减去按钮宽度未实际移动left
      data.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.coloradmin.cn/o/925633.html

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

相关文章

测试框架pytest教程(10)自定义命令行-pytest_addoption

pytest_addoption pytest_addoption是pytest插件系统中的一个钩子函数&#xff0c;用于向pytest添加自定义命令行选项。 在pytest中&#xff0c;可以使用命令行选项来控制测试的行为和配置。pytest_addoption钩子函数允许您在运行pytest时添加自定义的命令行选项&#xff0c;…

四信智能充电桩解决方案

新能源汽车是信息技术与制造体系的全面融合&#xff0c;是产业发展的大势所趋&#xff0c;也是新动能的重要支点&#xff0c;而推进充电基础设施建设则是实现我国从汽车大国迈向汽车强国必由之路战略举措的有力保障。 据国际能源署测算&#xff0c;2030年全球私人充电桩保有量预…

数组和指针的练习解析(4)

题目&#xff1a; int main() { int aa[2][5] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; int *ptr1 (int *)(&aa 1); int *ptr2 (int *)(*(aa 1)); printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1)); return 0; } 思路分析&#xff1a; int *ptr1 (int *)(&…

Java的锁大全

Java的锁 各种锁的类型 乐观锁 VS 悲观锁 乐观锁与悲观锁是一种广义上的概念&#xff0c;体现了看待线程同步的不同角度。在Java和数据库中都有此概念对应的实际应用。 先说概念。对于同一个数据的并发操作&#xff0c;悲观锁认为自己在使用数据的时候一定有别的线程来修改数…

AMBA总线协议(0)——目录与传送门

一、AMBA总线协议 Arm高级微控制器总线架构&#xff08;Advanced Microcontroller Bus Architecture&#xff0c;AMBA&#xff09;是一种开放式标准片上互联规范&#xff0c;用于连接和管理片上系统&#xff08;System on Chip,Soc&#xff09;中的功能块。 AMBA是一种广泛用于…

跨域知识点+springboot解决跨域

目录 一 跨域简介 二 跨域的三种情况 三 springboot解决跨域案例 一 跨域简介 什么是跨域&#xff1f; 由于浏览器的一些安全性限制&#xff0c;不允许前端页面访问一些协议不同、域名不同、端口号不同的http接口&#xff0c;例如我本地创建一个html&#xff0c;里面写一个a…

什么是代码审计?怎么做?

代码审计是对源代码进行人工或自动化审查&#xff0c;以查找潜在的安全漏洞和隐患。在信息安全测试中&#xff0c;代码审计是非常重要的一环。它主要包括以下几个方面&#xff1a; 1.变量验证&#xff1a;检查代码是否对变量进行验证&#xff0c;防止变量被恶意用户篡改。 2.…

python systemrdl 使用实例

今天来看一个具体实例&#xff0c;上一篇传送门&#xff1a;python SystemRDL 包介绍_Bug_Killer_Master的博客-CSDN博客 通常来说&#xff0c;我们验证过程用到的情况大多都是需要提取reg field的路径以及reset 值等信息&#xff0c;所以比较常见的一种方法就是先把rdl compil…

深入理解python虚拟机:调试器实现原理与源码分析

调试器是一个编程语言非常重要的部分&#xff0c;调试器是一种用于诊断和修复代码错误&#xff08;或称为 bug&#xff09;的工具&#xff0c;它允许开发者在程序执行时逐步查看和分析代码的状态和行为&#xff0c;它可以帮助开发者诊断和修复代码错误&#xff0c;理解程序的行…

vue(element ui安装)

目录 一&#xff0c;element ui安装二&#xff0c;main.js三&#xff0c;使用element ui最后 一&#xff0c;element ui安装 先在盘服中找到你创建的node的位置 如有不懂根据可以看看上一章安装node 然后在终端找到 进入这个位置之后就可以安装了 输入npm i element-ui -S这个…

什么是长短时记忆网络(LSTM)

什么是长短时记忆网络(LSTM) RNN有一定的记忆能力&#xff0c;但不幸的是它只能保留短期记忆&#xff0c;在各类任务上表现并不好&#xff0c;那该怎么办? 人们将目光投向了自己&#xff0c;人类的记忆是有取舍的&#xff0c;我们不会记住每时每刻发生的所有事&#xff0c;会…

基于Java+SpringBoot+vue前后端分离高校办公室行政事务管理系统设计实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

奎文区残疾人联合会党组领导侯效刚、刘金玲莅临考察交流

2023年8月15日上午&#xff0c;为进一步提升残疾人精准化服务水平&#xff0c;推动“如康家园”残疾人之家建设有序展开&#xff0c;奎文区残疾人联合会党组书记兼理事长侯效刚&#xff0c;党组成员兼副理事长刘金玲&#xff0c;潍州路街道办事处副主任董江芹主任一行5人莅临潍…

RK3568评估板外接屏幕修改竖屏为横屏显示

问题 使用RK3568评估板外接HDMI屏幕时竖屏显示内容&#xff0c;需要修改为横屏显示。 解决办法 修改weston.ini配置文件&#xff0c;配置output输出参数 查看显示屏名称 使用ls /sys/class/drm/ 命令查看显示屏名称&#xff0c;如下图所示&#xff0c;示例屏为HDMI屏&#xff0…

1448. 统计二叉树中好节点的数目

题目描述&#xff1a; 给你一棵根为 root 的二叉树&#xff0c;请你返回二叉树中好节点的数目。 「好节点」X 定义为&#xff1a;从根到该节点 X 所经过的节点中&#xff0c;没有任何节点的值大于 X 的值。 示例&#xff1a; 解题思路&#xff1a; 通过左右子树分别判断是否大于…

胜券汇:运营商有望引领国内AI信创加速

8月20日&#xff0c;中国电信发布《中国电信AI算力服务器&#xff08;2023-2024年&#xff09;会集收购项目会集资历预审公告》。胜券汇研报点评称&#xff0c;中国电信集采4175台AI算力服务器&#xff0c;数量大幅增加&#xff0c;佐证AI服务器高景气量。估计国产占比约47%&am…

【三维重建】【深度学习】NeRF代码Pytorch实现--数据加载(上)

【三维重建】【深度学习】NeRF代码Pytorch实现–数据加载(上) 论文提出了一种5D的神经辐射场来作为复杂场景的隐式表示&#xff0c;称为NeRF&#xff0c;其输⼊稀疏的多⻆度带pose的图像训练得到⼀个神经辐射场模型。简单来说就是通过输入同一场景不同视角下的二维图片和相机位…

抢鲜体验!vLive虚拟直播5大实用新功能上线!

vLive虚拟直播系统2.6.2版本全新上线&#xff01;新版本一共更新了5项实用功能&#xff0c;能让你的直播操作更加方便。现在就跟随小编一起来看看吧&#xff01; 1.本地下载场景支持一键迁移 用户下载后的场景可以直接迁移至另一个磁盘&#xff0c;无需重复下载。 2.信号源添加…

《深度学习计算机视觉 》书籍分享(包邮送书三本)

深度学习计算机视觉介绍 随着计算机技术的发展和进步&#xff0c;计算机视觉领域得到了广泛的关注和研究。而深度学习作为一种强大的机器学习方法&#xff0c;已经成为计算机视觉领域的重要工具之一。本文将介绍深度学习在计算机视觉中的应用和取得的成果。 深度学习是一种模…

MeterSphere常用操作/脚本记录

设置变量 vars.put(“key”,“value”); //存为场景变量 设置环境变量 vars.put(${__metersphere_env_id}“key”,“value”); //存为环境变量 随机生成手机号 String phone “178123${__RandomString(5,0123456789)}”; //178123开头&#xff0c;后面5位随机 获取当前请求…