滑动输入条、进度条

news2024/11/26 13:58:31

参考:

  • Antdv Slider 滑动输入条
  • Element Plus Progress 进度条

开发时遇到一个需求,一个进度条控制多个视频播放器。正常使用一些组件库自带的组件就好了——antdvslider

但是使用change事件的话,使用拖拽进度点改变进度条value 就会频繁触发,所以考虑使用afterChange

  • afterChange:与 mouseup 触发时机一致,把当前值作为参数传入。

该API纯在如下bug:

该事件触发后,鼠标点击其他区域,会再次触发该事件。gitHub也有这个issue,但是^3^4版本都没有进行修复。于是自己封装了一个简易的进度条,相比组件库中的灵活性更高。代码放在最下面。

效果图

在这里插入图片描述

进度条与视频

  • 对于进度条的时间显示,不能使用计时器控制,而是应该获取视频的当前时间回显到进度条中,不然时间是无法对齐的,总会存在误差。

  • js的浮点数计算不准确,视频时间的精度是小数点后很多位,不能使用计时器累加

组件代码

<template>
  <div id="progress-component" class="progress-component">
    <!-- 进度条 -->
    <div class="progress-bar-box" @click="handleClick" @mouseup="handleMouseUp">
      <div
        class="progress-bar"
        :style="{
          width: (currentValue / totalValue) * 100 + '%',
          backgroundColor: barColor,
        }"
      ></div>
    </div>

    <!-- 拖拽点 -->
    <div
      id="progress-handle"
      class="progress-handle"
      :style="{
        left: (currentValue / totalValue) * 100 - 0.35 + '%',
      }"
      @mousedown="handleDragStart"
    ></div>
  </div>
</template>

<script setup>
const props = defineProps({
  value: {
    type: Number,
    default: 0,
    required: true,
  },
  totalValue: {
    type: Number,
    default: 100,
    required: true,
  },

  barColor: {
    type: String,
    default: "#91caff",
  },
  barBoxColor: {
    type: String,
    default: "rgba(0, 0, 0, 0.04)",
  },
  handleShadowColor: {
    type: String,
    default: "#91caff",
  },
});
const emit = defineEmits(["update:value", "afterChange", "change"]);
const currentValue = ref(parseFloat(props.value.toFixed(1)));
watch(
  () => props.value,
  (now) => {
    currentValue.value = now;
  }
);

const isDragging = ref(false);
const progressBarWidth = ref(0);
const progressBarRect = ref(null);

// 鼠标点击更新进度值
const handleClick = (event) => {
  progressBarRect.value = event.currentTarget.getBoundingClientRect();
  updateProgress(event.clientX);
  emit("change", parseInt(currentValue.value));
};
const handleMouseUp = (event) => {
  progressBarRect.value = event.currentTarget.getBoundingClientRect();
  updateProgress(event.clientX);
  emit("afterChange", parseInt(currentValue.value));
};
// 开始拖动
const handleDragStart = (event) => {
  event.stopPropagation();
  isDragging.value = true;
  progressBarRect.value =
    event.currentTarget.parentElement.getBoundingClientRect();
  document.addEventListener("mousemove", handleDragMove);
  document.addEventListener("mouseup", handleDragEnd);
  // 禁用文本选择
  document.body.style.userSelect = "none";
};

// 拖动时更新进度值
const handleDragMove = (event) => {
  if (isDragging.value) {
    updateProgress(event.clientX);
  }
};

// 结束拖动
const handleDragEnd = () => {
  isDragging.value = false;
  document.removeEventListener("mousemove", handleDragMove);
  document.removeEventListener("mouseup", handleDragEnd);
  // 恢复文本选择
  document.body.style.userSelect = "";
  // 在拖动结束时触发 afterChange 事件
  emit("afterChange", parseInt(currentValue.value));
};

// 更新进度值的函数
const updateProgress = (clientX) => {
  const rect = progressBarRect.value;
  const percentage = Math.min(
    Math.max((clientX - rect.left) / rect.width, 0),
    1
  );

  // 根据 totalValue 计算实际进度值并四舍五入
  let newProgress = percentage * props.totalValue;
  emit("update:value", newProgress);
  currentValue.value = newProgress;
};

// 监听窗口大小变化,重新计算 progress-bar 的宽度
const handleResize = () => {
  const progressBar = document.querySelector(".progress-bar-box");
  progressBarWidth.value = progressBar.offsetWidth;
};

onMounted(() => {
  // 获取 progress-bar 的宽度

  const progressBar = document.querySelector(".progress-bar-box");
  progressBarWidth.value = progressBar.offsetWidth;
  window.addEventListener("resize", handleResize);
});

onBeforeUnmount(() => {
  window.removeEventListener("resize", handleResize);
});
</script>

<style scoped lang="less">
.progress-component {
  width: 100%;
  height: 12px;
  position: relative;
  margin: 4px 0;
  padding: 4px 0;

  .progress-bar-box {
    height: 4px;
    width: 100%;
    position: absolute;
    bottom: 0;
    cursor: pointer;
    // background-color: rgba(0, 0, 0, 0.04);
    background-color: v-bind("barBoxColor");
    border-radius: 4px;
    transition: background-color 0.2s;
    z-index: 50;

    .point {
      width: 6px;
      height: 6px;
      background: #333336;
      border: 1px solid #939393;
      border-radius: 50%;
      position: absolute;
    }
    .point-1 {
      left: 0;
    }
    .point-2 {
      right: 0;
    }
  }
  .progress-bar {
    position: absolute;
    height: 4px;
    background-color: #91caff;
    border-radius: 2px;
    transition: background-color 0.2s;
    z-index: 60;
  }
  .progress-handle {
    position: absolute;
    width: 8px;
    height: 8px;
    outline: none;
    border-radius: 50%;
    background-color: #ffffff;
    position: absolute;
    top: 6px;
    z-index: 100;
    cursor: pointer;

    transition: box-shadow 0.2s;
    box-shadow: 0 0 0 2px v-bind("handleShadowColor");

    &:hover {
      box-shadow: 0 0 0 4px v-bind("handleShadowColor");
    }
  }
}
</style>

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

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

相关文章

C++版设计模式简介 与 初识 工厂模式

目录 前言 一、设计模式简介1. 什么是设计模式2. 设计模式分类3. 设计模式的优点4. 设计模式的实践 二、单例模式1. 单例模式的关键点2. 单例模式的实现方式饿汉式单例&#xff08;Eager Initialization&#xff09;懒汉式单例&#xff08;Lazy Initialization&#xff09;双重…

使用Ollama本地离线体验SimpleRAG(手把手教程)

Ollama介绍 Ollama是一个开源项目&#xff0c;专注于开发和部署大语言模型&#xff0c;特别是像LLaMA这样的模型&#xff0c;用于生成高质量的文本和进行复杂的自然语言处理任务。Ollama的目标是让大语言模型的运行和使用变得更加容易和普及&#xff0c;而无需复杂的基础设施或…

解决执行npm run dev报错node: --openssl-legacy-provider is not allowed in NODE_OPTIONS

问题&#xff1a; 最近下载了一个开源系统&#xff0c;执行npm install很顺利&#xff0c;以为大功告成&#xff0c;结果运行npm run dev时报错node: --openssl-legacy-provider is not allowed in NODE_OPTIONS 解决方法&#xff1a; 应用程序配置&#xff08;package.json&a…

在控件graphicsView中实现绘图功能(三)

这里写自定义目录标题 前言&#xff1a;效果展示&#xff1a;1.图片展示2.视频展示 基础夯实&#xff1a;一.文本框焦点&#xff1a;二.QGraphicsItems&#xff1a;1.QGraphicsRectItem2.QGraphicsLineItem3.QGraphicsEllipseItem4.QGraphicsTextItem5.QGraphicsPathItem 三.鼠…

KI-DDI:知识图谱 + 大模型 + 图注意力,医学诊断

KI-DDI&#xff1a;知识图谱 大模型 图注意力&#xff0c;医学诊断 具体到点精细分析对话处理 SapBERT医学知识处理 - 图注意力网络(GAT)信息融合 - 对话嵌入 - 知识图谱嵌入知识图谱的权重 KI-DDI 图分析性关联图 知识图谱 大模型 VS KI-DDI更强的个性化 论文&#xff1a;T…

[数据集][目标检测]街灯路灯检测数据集VOC+YOLO格式1893张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;1893 标注数量(xml文件个数)&#xff1a;1893 标注数量(txt文件个数)&#xff1a;1893 标注…

adaptive AUTOSAR UCM模块中SoftwareCluster与Software Package是什么样的关系,他们分别包含哪些元素?

在自适应AUTOSAR(Adaptive AUTOSAR)的更新和配置管理(UCM)模块中,SoftwareCluster和Software Package是软件更新过程中的两个关键概念,它们之间有着密切的关系: SoftwareCluster:通常指的是一组功能相关的软件组件,它们共同实现了车辆中的一个或多个特定功能。在UCM中…

钓鱼的常见几种方式

钓鱼的多种方式 office钓鱼攻击 宏与宏病毒 # 宏 宏是office自带的一种高级脚本特性&#xff0c;通过VBA代码&#xff0c;可以在office中去完成某项特定的任务&#xff0c;而不必再重复相同的动作&#xff0c;目的是让用户文档中一些任务自动化# 宏病毒 宏病毒是一种寄存在文…

Qt实现圆型控件的三种方法之设置样式表

前言 最近在研究绘制各种形状的控件&#xff0c;这里专门挑出圆形的控件进行记录&#xff0c;其它形状的也大差不差&#xff0c;会了圆形的之后其它的也类似。 正文 这里我挑出Label来进行举例。 通过设置样式表 (QSS) 这种方法简单且适用于不需要自定义绘制的场景。就是要…

uniapp实现应用内检测版本更新(Android直接下载/ios跳转app store)

背景&#xff1a;最近需要给app加一个可以检测到新版本并更新的功能&#xff0c; 之前没有考虑过这个问题&#xff0c;第一次尝试&#xff0c;特此记录一下。 我在这里使用到了uniapp上的更新插件&#xff0c;并在此插件基础上进行更改以适应我的项目。 插件链接&#xff1a;ht…

【专题】2023-2024中国游戏企业研发竞争力报告合集PDF分享(附原数据表)

原文链接&#xff1a; https://tecdat.cn/?p37447 在当今的数字时代&#xff0c;游戏产业已然成为经济与文化领域中一股不可忽视的重要力量。2023 年&#xff0c;中国自研游戏市场更是呈现出一片繁荣且复杂的景象&#xff0c;实际销售收入达到了令人瞩目的 2563.8 亿元&#x…

计算机毕业设计选题推荐-民宿可视化分析-Python爬虫-随机森林算法

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…

Catf1ag CTF Web(九)

前言 Catf1agCTF 是一个面向所有CTF&#xff08;Capture The Flag&#xff09;爱好者的综合训练平台&#xff0c;尤其适合新手学习和提升技能 。该平台由catf1ag团队打造&#xff0c;拥有超过200个原创题目&#xff0c;题目设计注重知识点的掌握&#xff0c;旨在帮助新手掌握C…

易趋产品升级 | EasyTrack11_V2.0功能更新合集

近日&#xff0c;易趋PPM&#xff08;EasyTrack PPM&#xff09;为了帮助企业全面提升数字化项目管理能力&#xff0c;完成了新一轮的产品升级&#xff0c;从【个人空间】、【项目组合管理】、【合同与外包管理】。除了以上三大功能模块之外&#xff0c;其他升级项暂略。 1.个人…

Ajax技术详解

Ajax简介 Ajax 即 "Asynchronous Javascript And XML"&#xff08;异步 JavaScript 和 XML&#xff09;&#xff0c;是指一种创建交互式、快速动态应用的网页开发技术&#xff0c;无需重新加载整个网页的情况下&#xff0c;能够更新页面局部数据的技术。 为什么要使…

c++习题25-判断字符串是否回文

目录 一&#xff0c;题目 二&#xff0c;思路 三&#xff0c;代码 一&#xff0c;题目 描述 输入一个字符串&#xff0c;输出该字符串是否回文。回文是指顺读和倒读都一样的字符串。 输入描述 输入为一行字符串&#xff08;字符串中没有空白字符&#xff0c;字符串长度不…

Linux文件属性和打包压缩详解

1、文件属性体系 1.1 文件系统概述 [rootyunwei /]# ls -lhi 总用量 72K3505 lrwxrwxrwx. 1 root root 7 3月 7 2019 bin -> usr/bin 262152 dr-xr-xr-x. 5 root root 4.0K 12月 19 16:00 boot 399635 drwxr-xr-x 2 root root 4.0K 11月 5 2019 data1026 drw…

【数据结构】二叉树基础知识

0. 前言 在前面几期博客&#xff0c;我们已经学习过了各种线性的数据结构&#xff0c;顺序表、链表、栈、队列&#xff0c; 本期博客我们一起来学习一种非线性的结构——树 1. 树的概念及结构 1.1 树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>…

学习嵌入式第二十九天

ipc进程间通信方式 PC&#xff0c;即进程间通信&#xff08;Inter-Process Communication&#xff09;&#xff0c;是操作系统中不同进程之间交换数据的一种机制。以下是一些常见的IPC方式&#xff1a; 管道&#xff1a;用于父子进程或兄弟进程之间的通信。消息队列&#xff…