Vue3 实现进度条组件

news2025/4/17 9:08:41

样式如下,代码如下
在这里插入图片描述

<script setup>
import { computed, defineEmits, defineProps, onMounted, ref, watch } from 'vue'

// 定义 props
const props = defineProps({
  // 初始百分比
  initialPercentage: {
    type: Number,
    default: 0,
  },
})

// 定义 emits
const emits = defineEmits(['drag-percentage-change'])

// 定义圆圈数量
const circleCount = 5
// 进度条容器引用
const progressBarContainer = ref(null)
// 可拖动圆圈的位置(百分比)
const draggableCircleLeftPercentage = ref(props.initialPercentage)
// 可拖动圆圈的位置样式
const draggableCircleLeft = computed(() => `${draggableCircleLeftPercentage.value}%`)
// 进度条直线宽度
const progressLineWidth = computed(() => '100%')
// 已完成部分直线宽度
const completedLineWidth = computed(() => `${draggableCircleLeftPercentage.value}%`)

// 圆圈位置计算
const circles = ref([])
onMounted(() => {
  if (progressBarContainer.value) {
    const containerWidth = progressBarContainer.value.offsetWidth
    for (let i = 0; i < circleCount; i++) {
      const leftPercentage = (i / (circleCount - 1)) * 100
      circles.value.push({
        left: `${leftPercentage}%`,
      })
    }
  }
})

// 开始拖动
const isDragging = ref(false)
const startDragging = (e) => {
  if (!progressBarContainer.value)
    return
  isDragging.value = true
  const containerRect = progressBarContainer.value.getBoundingClientRect()
  const startX = e.clientX

  const handleMouseMove = (e) => {
    if (isDragging.value) {
      const offsetX = e.clientX - containerRect.left
      const containerWidth = containerRect.width
      let newLeft = (offsetX / containerWidth) * 100
      // 取整并确保在 0 到 100 之间
      newLeft = Math.min(100, Math.max(0, Math.round(newLeft)))
      draggableCircleLeftPercentage.value = newLeft
      // 抛出事件,返回当前百分比
      emits('drag-percentage-change', newLeft)
    }
  }

  const handleMouseUp = () => {
    if (isDragging.value) {
      isDragging.value = false
      document.removeEventListener('mousemove', handleMouseMove)
      document.removeEventListener('mouseup', handleMouseUp)
    }
  }

  document.addEventListener('mousemove', handleMouseMove)
  document.addEventListener('mouseup', handleMouseUp)
}

// 点击进度条
const handleBarClick = (e) => {
  if (!progressBarContainer.value)
    return
  const containerRect = progressBarContainer.value.getBoundingClientRect()
  const offsetX = e.clientX - containerRect.left
  const containerWidth = containerRect.width
  let clickPercentage = (offsetX / containerWidth) * 100
  // 取整并确保在 0 到 100 之间
  clickPercentage = Math.min(100, Math.max(0, Math.round(clickPercentage)))
  draggableCircleLeftPercentage.value = clickPercentage
  // 抛出事件,返回当前百分比
  emits('drag-percentage-change', clickPercentage)
}

// 点击圆圈
const handleCircleClick = (index) => {
  const percentage = (index / (circleCount - 1)) * 100
  draggableCircleLeftPercentage.value = percentage
  emits('drag-percentage-change', percentage)
}

// 监听 initialPercentage 的变化
watch(() => props.initialPercentage, (newValue) => {
  // 取整并确保在 0 到 100 之间
  const validValue = Math.min(100, Math.max(0, Math.round(newValue)))
  draggableCircleLeftPercentage.value = validValue
})
</script>

<template>
  <div ref="progressBarContainer" class="progress-bar-container" @mousedown="handleBarClick">
    <div class="progress-line" :style="{ width: progressLineWidth }" />
    <div class="completed-line" :style="{ width: completedLineWidth }" />
    <div
      v-for="(circle, index) in circles"
      :key="index"
      class="progress-circle"
      :class="{ active: index * (100 / (circleCount - 1)) <= draggableCircleLeftPercentage }"
      :style="{ left: `calc(${circle.left} - 5px)` }"
      @click="handleCircleClick(index)"
    />
    <div
      class="draggable-circle"
      :style="{ left: `calc(${draggableCircleLeft} - 7px)` }"
      @mousedown="startDragging"
    />
  </div>
</template>

<style scoped>
.progress-bar-container {
  position: relative;
  width: 100%;
  height: 20px;
}

.progress-line {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  left: 0;
  width: 100%;
  height: 2px;
  background-color: gray;
  z-index: 1;
}

.completed-line {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  left: 0;
  height: 2px;
  background-color: white;
  z-index: 2;
}

.progress-circle {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background-color: #808080;
  z-index: 3;
  cursor: pointer;
}

.progress-circle.active {
  background-color: white;
}

.draggable-circle {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background-color: white;
  z-index: 4;
  cursor: pointer;
}
</style>

<template>
  <div>
    <CircleProgressBar
      :initialPercentage="initialValue"
      @drag-percentage-change="handlePercentageChange"
    />
  </div>
</template>

<script setup>
import { ref } from 'vue';
import CircleProgressBar from './CircleProgressBar.vue';

const initialValue = ref(20); // 初始百分比为 20%

const handlePercentageChange = (percentage) => {
  console.log('当前百分比:', percentage);
  // 你可以在这里处理接收到的百分比
};
</script>

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

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

相关文章

35.[前端开发-JavaScript基础]Day12-for循环中变量-华为商城-商品列表-轮播图

for循环中监听函数中打印变量 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"wi…

【蓝桥杯】十五届省赛B组c++

目录 前言 握手问题 分析 排列组合写法 枚举 小球反弹 分析 代码 好数 分析 代码 R 格式 分析 代码 宝石组合 分析 代码 数字接龙 分析 代码 拔河 分析 代码 总结 前言 主播这两天做了一套蓝桥杯的省赛题目&#xff08;切实感受到了自己有多菜&#x…

[Linux系统编程]多线程

多线程 1. 线程1.1 线程的概念1.2 进程与线程对比1.3 轻量级进程 2. Linux线程控制2.1 POSIX 线程&#xff08;pthread&#xff09;2.2 线程ID、pthread_t、和进程地址空间的关系2.2.1 pthread_self2.2.2 pthread_create2.2.3 pthread_join2.2.4 线程终止的三种方式2.2.5 pthre…

IntelliJ IDEA下开发FPGA——FPGA开发体验提升__下

前言 由于Quartus写代码比较费劲&#xff0c;虽然新版已经有了代码补全&#xff0c;但体验上还有所欠缺。于是使用VS Code开发&#xff0c;效果如下所示&#xff0c;代码样式和基本的代码补全已经可以满足开发&#xff0c;其余工作则交由Quartus完成 但VS Code的自带的git功能&…

odo18实施——销售-仓库-采购-制造-制造外包-整个流程自动化单据功能的演示教程

安装模块 安装销售 、库存、采购、制造模块 2.开启外包功能 在进入制造应用点击 配置—>设置 勾选外包&#xff0c;点击保存 添加信息 一、添加客户信息 点击到销售应用 点击订单—>客户 点击新建 创建客户1&#xff0c;及其他客户相关信息&#xff0c;点…

微信小程序生成某个具体页面的二维码

微信小程序&#xff0c;如果要生成某个具体页面&#xff0c;而非首页的二维码&#xff0c;体验和正式的生成方法如下&#xff1a; 1、体验版二维码&#xff1a; 管理---版本管理---修改页面路径&#xff0c;输入具体页面的路径以及参数&#xff0c;生成的是二维码 2、正式小程…

鸿蒙开发_ARKTS快速入门_语法说明_组件声明_组件手册查看---纯血鸿蒙HarmonyOS5.0工作笔记010

然后我们来看如何使用组件 可以看到组件的组成 可以看到我们使用的组件 然后看一下组件的语法.组件中可以使用子组件. 然后组件中可以有参数,来修改组件的样式等 可以看到{},这种方式可以设置组件参数,当然在下面. 的方式也可以的 然后再来

接口异常数组基础题

题目描述 设想你正在构建一个智能家居控制系统。这个系统可以连接多种不同类型的智能设备&#xff0c;如智能灯泡、智能空调和智能门锁。每种设备都有其独特的功能&#xff0c;不过它们也有一些通用的操作&#xff0c;像开启、关闭和获取设备状态等。系统需要提供一个方法来控…

rustdesk折腾手记

背景 我的工作环境&#xff1a;主力电脑是macPro, 另外一台ThinkPad W530作为开发机&#xff0c;装的是LinuxMint&#xff0c;还有一台ThinkPad P15作为服务器。平常显示器接到macPro&#xff0c;在macOS上通过微软的远程桌面连接到另外两台Linux。基本访问比较流畅&#xff0…

使用el-tab 实现两个tab切换

1、主页面 index.vue 2、tab1&#xff1a;school.vue 3、tab2&#xff1a;parent.vue 具体代码如下&#xff1a; <template><div class"app-container"><!-- 使用el-tabs 实现两个组件的切换 --><el-tabs v-model"activeName" typ…

使用Pholcus编写Go爬虫示例

想用Pholcus库来写一个Go的爬虫程序。首先&#xff0c;我得确认Pholcus的当前状态&#xff0c;因为之前听说过它可能已经不再维护了。不过用户可能还是需要基于这个库的示例&#xff0c;所以得先提供一个基本的框架。 首先&#xff0c;我应该回忆一下Pholcus的基本用法。Pholc…

单片机实现触摸按钮执行自定义任务组件

触摸按钮执行自定义任务组件 项目简介 本项目基于RT8H8K001开发板 RT6809CNN01开发板 TFT显示屏(1024x600) GT911触摸屏实现了一个多功能触摸按钮组件。系统具备按钮控制后执行任务的功能&#xff0c;可用于各类触摸屏人机交互场景。 硬件平台 MCU: STC8H8K64U&#xff0…

Ai云防护技术解析——服务器数据安全的智能防御体系

本文深度解析AI云防护技术如何通过智能流量分析、动态行为建模、自适应防御策略构建服务器安全体系。结合2023年群联科技实战案例,揭示机器学习算法在识别新型DDoS攻击、加密流量检测、零日漏洞防御中的技术突破,并附Gartner最新防护效果验证数据。 AI驱动的流量特征建模技术…

JSONP跨域访问漏洞

一、漏洞一:利用回调GetCookie <?php$conn new mysqli(127.0.0.1,root,root,learn) or die("数据库连接不成功"); $conn->set_charset(utf8); $sql "select articleid,author,viewcount,creattime from learn3 where articleid < 5"; $result…

图形裁剪算法

1.学习目标 理解区域编码(Region Code&#xff0c;RC) 设计Cohen-Sutherland直线裁剪算法 编程实现Cohen-Sutherland直线裁剪算法 2.具体代码 1.具体算法 /*** Cohen-Sutherland直线裁剪算法 - 优化版* author AI Assistant* license MIT*/// 区域编码常量 - 使用对象枚举…

R 语言科研绘图第 36 期 --- 饼状图-基础

在发表科研论文的过程中&#xff0c;科研绘图是必不可少的&#xff0c;一张好看的图形会是文章很大的加分项。 为了便于使用&#xff0c;本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中&#xff0c;获取方式&#xff1a; R 语言科研绘图模板 --- sciRplothttps://mp.…

vue 3 从零开始到掌握

vue3从零开始一篇文章带你学习 升级vue CLI 使用命令 ## 查看vue/cli版本&#xff0c;确保vue/cli版本在4.5.0以上 vue --version ## 安装或者升级你的vue/cli npm install -g vue/cli ## 创建 vue create vue_test ## 启动 cd vue_test npm run servenvm管理node版本&#…

【R语言绘图】圈图绘制代码

绘制代码 rm(list ls())# 加载必要包 library(data.table) library(circlize) library(ComplexHeatmap) library(rtracklayer) library(GenomicRanges) library(BSgenome) library(GenomicFeatures) library(dplyr)### 数据准备阶段 ### # 1. 读取染色体长度信息 df <- re…

Python爬虫第6节-requests库的基本用法

目录 前言 一、准备工作 二、实例引入 三、GET请求 3.1 基本示例 3.2 抓取网页 3.3 抓取二进制数据 3.4 添加headers 四、POST请求 五、响应 前言 前面我们学习了urllib的基础使用方法。不过&#xff0c;urllib在实际应用中存在一些不便之处。以网页验证和Cookies处理…

什么是可靠性工程师?

一、什么是可靠性工程师&#xff1f; 可靠性工程师就是负责确保产品在使用过程中不出故障、不给客户添麻烦。 你可以理解为是那种“挑毛病的人”&#xff0c;但不是事后挑&#xff0c;是提前想清楚产品在哪些情况下可能会出问题&#xff0c;然后解决掉。 比如&#xff1a; …