Vue3 实现进度条组件

打印 上一主题 下一主题

主题 1640|帖子 1640|积分 4920

样式如下,代码如下

  1. <script setup>
  2. import { computed, defineEmits, defineProps, onMounted, ref, watch } from 'vue'
  3. // 定义 props
  4. const props = defineProps({
  5.   // 初始百分比
  6.   initialPercentage: {
  7.     type: Number,
  8.     default: 0,
  9.   },
  10. })
  11. // 定义 emits
  12. const emits = defineEmits(['drag-percentage-change'])
  13. // 定义圆圈数量
  14. const circleCount = 5
  15. // 进度条容器引用
  16. const progressBarContainer = ref(null)
  17. // 可拖动圆圈的位置(百分比)
  18. const draggableCircleLeftPercentage = ref(props.initialPercentage)
  19. // 可拖动圆圈的位置样式
  20. const draggableCircleLeft = computed(() => `${draggableCircleLeftPercentage.value}%`)
  21. // 进度条直线宽度
  22. const progressLineWidth = computed(() => '100%')
  23. // 已完成部分直线宽度
  24. const completedLineWidth = computed(() => `${draggableCircleLeftPercentage.value}%`)
  25. // 圆圈位置计算
  26. const circles = ref([])
  27. onMounted(() => {
  28.   if (progressBarContainer.value) {
  29.     const containerWidth = progressBarContainer.value.offsetWidth
  30.     for (let i = 0; i < circleCount; i++) {
  31.       const leftPercentage = (i / (circleCount - 1)) * 100
  32.       circles.value.push({
  33.         left: `${leftPercentage}%`,
  34.       })
  35.     }
  36.   }
  37. })
  38. // 开始拖动
  39. const isDragging = ref(false)
  40. const startDragging = (e) => {
  41.   if (!progressBarContainer.value)
  42.     return
  43.   isDragging.value = true
  44.   const containerRect = progressBarContainer.value.getBoundingClientRect()
  45.   const startX = e.clientX
  46.   const handleMouseMove = (e) => {
  47.     if (isDragging.value) {
  48.       const offsetX = e.clientX - containerRect.left
  49.       const containerWidth = containerRect.width
  50.       let newLeft = (offsetX / containerWidth) * 100
  51.       // 取整并确保在 0 到 100 之间
  52.       newLeft = Math.min(100, Math.max(0, Math.round(newLeft)))
  53.       draggableCircleLeftPercentage.value = newLeft
  54.       // 抛出事件,返回当前百分比
  55.       emits('drag-percentage-change', newLeft)
  56.     }
  57.   }
  58.   const handleMouseUp = () => {
  59.     if (isDragging.value) {
  60.       isDragging.value = false
  61.       document.removeEventListener('mousemove', handleMouseMove)
  62.       document.removeEventListener('mouseup', handleMouseUp)
  63.     }
  64.   }
  65.   document.addEventListener('mousemove', handleMouseMove)
  66.   document.addEventListener('mouseup', handleMouseUp)
  67. }
  68. // 点击进度条
  69. const handleBarClick = (e) => {
  70.   if (!progressBarContainer.value)
  71.     return
  72.   const containerRect = progressBarContainer.value.getBoundingClientRect()
  73.   const offsetX = e.clientX - containerRect.left
  74.   const containerWidth = containerRect.width
  75.   let clickPercentage = (offsetX / containerWidth) * 100
  76.   // 取整并确保在 0 到 100 之间
  77.   clickPercentage = Math.min(100, Math.max(0, Math.round(clickPercentage)))
  78.   draggableCircleLeftPercentage.value = clickPercentage
  79.   // 抛出事件,返回当前百分比
  80.   emits('drag-percentage-change', clickPercentage)
  81. }
  82. // 点击圆圈
  83. const handleCircleClick = (index) => {
  84.   const percentage = (index / (circleCount - 1)) * 100
  85.   draggableCircleLeftPercentage.value = percentage
  86.   emits('drag-percentage-change', percentage)
  87. }
  88. // 监听 initialPercentage 的变化
  89. watch(() => props.initialPercentage, (newValue) => {
  90.   // 取整并确保在 0 到 100 之间
  91.   const validValue = Math.min(100, Math.max(0, Math.round(newValue)))
  92.   draggableCircleLeftPercentage.value = validValue
  93. })
  94. </script>
  95. <template>
  96.   <div ref="progressBarContainer" class="progress-bar-container" @mousedown="handleBarClick">
  97.     <div class="progress-line" :style="{ width: progressLineWidth }" />
  98.     <div class="completed-line" :style="{ width: completedLineWidth }" />
  99.     <div
  100.       v-for="(circle, index) in circles"
  101.       :key="index"
  102.       class="progress-circle"
  103.       :class="{ active: index * (100 / (circleCount - 1)) <= draggableCircleLeftPercentage }"
  104.       :style="{ left: `calc(${circle.left} - 5px)` }"
  105.       @click="handleCircleClick(index)"
  106.     />
  107.     <div
  108.       class="draggable-circle"
  109.       :style="{ left: `calc(${draggableCircleLeft} - 7px)` }"
  110.       @mousedown="startDragging"
  111.     />
  112.   </div>
  113. </template>
  114. <style scoped>
  115. .progress-bar-container {
  116.   position: relative;
  117.   width: 100%;
  118.   height: 20px;
  119. }
  120. .progress-line {
  121.   position: absolute;
  122.   top: 50%;
  123.   transform: translateY(-50%);
  124.   left: 0;
  125.   width: 100%;
  126.   height: 2px;
  127.   background-color: gray;
  128.   z-index: 1;
  129. }
  130. .completed-line {
  131.   position: absolute;
  132.   top: 50%;
  133.   transform: translateY(-50%);
  134.   left: 0;
  135.   height: 2px;
  136.   background-color: white;
  137.   z-index: 2;
  138. }
  139. .progress-circle {
  140.   position: absolute;
  141.   top: 50%;
  142.   transform: translateY(-50%);
  143.   width: 10px;
  144.   height: 10px;
  145.   border-radius: 50%;
  146.   background-color: #808080;
  147.   z-index: 3;
  148.   cursor: pointer;
  149. }
  150. .progress-circle.active {
  151.   background-color: white;
  152. }
  153. .draggable-circle {
  154.   position: absolute;
  155.   top: 50%;
  156.   transform: translateY(-50%);
  157.   width: 14px;
  158.   height: 14px;
  159.   border-radius: 50%;
  160.   background-color: white;
  161.   z-index: 4;
  162.   cursor: pointer;
  163. }
  164. </style>
复制代码
  1. <template>
  2.   <div>
  3.     <CircleProgressBar
  4.       :initialPercentage="initialValue"
  5.       @drag-percentage-change="handlePercentageChange"
  6.     />
  7.   </div>
  8. </template>
  9. <script setup>
  10. import { ref } from 'vue';
  11. import CircleProgressBar from './CircleProgressBar.vue';
  12. const initialValue = ref(20); // 初始百分比为 20%
  13. const handlePercentageChange = (percentage) => {
  14.   console.log('当前百分比:', percentage);
  15.   // 你可以在这里处理接收到的百分比
  16. };
  17. </script>
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

耶耶耶耶耶

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表