拖动播放条
拖动播放条
hook.ts
import { clamp, round } from "lodash-es";
import { getScaleMultiplesNumber } from "@/components/Adapter/utils";
export interface callBackResponse {
type: 'moving' | 'moveEnd',
percent: number
}
export function useProgress<T extends ReturnType<typeof defineEmits>>(emits: T) {
const container = ref<HTMLDivElement | null>();
const thumb = ref<HTMLDivElement | null>();
const defaultInitLeft = ref(6);
const curLeftValue = ref(defaultInitLeft.value)
// 点击后添加事件
const mousedown = () => {
window.addEventListener("mousemove", handleChange);
window.addEventListener("mouseup", mouseup);
};
// 移动滑块
const handleChange = (e: MouseEvent) => {
const containerDom: NonNullable<typeof container.value> = container.value!;
const thumbDom: NonNullable<typeof thumb.value> = thumb.value!;
if (!thumbDom) return;
const defaultLeft = defaultInitLeft.value;
const containerWidth = containerDom.offsetWidth;
const thumbWidth = thumbDom.offsetWidth;
const RANG_LEFT_VALUE = [defaultLeft, containerWidth - defaultLeft - thumbWidth];
function moveAt(pageX: number) {
let leftValue = pageX - containerDom.getBoundingClientRect().left;
// * 适配不同分辨率情况下解决拖动时的偏移
// * 缩放情况下鼠标的获取坐标会发生偏移现象(导致鼠标实际移动的距离 = dom元素移动的距离 / 缩放倍数),
// * 所以这里需要对其的x坐标进行转化到偏移前。
const { restore } = getScaleMultiplesNumber();
leftValue = leftValue * restore.x;
leftValue = clamp(leftValue, RANG_LEFT_VALUE[0], RANG_LEFT_VALUE[1]);
curLeftValue.value = leftValue
containerDom.style.setProperty("--cur-init-left", `${curLeftValue.value}px`);
emits('move', {
type: 'moving',
percent: getPercent()
})
}
moveAt(e.pageX);
};
// 鼠标放开后移除事件
const mouseup = () => {
window.removeEventListener("mousemove", handleChange);
window.removeEventListener("mouseup", mouseup);
emits('move', {
type: 'moveEnd',
percent: getPercent()
})
};
const resetValue = () => {
const containerDom: NonNullable<typeof container.value> = container.value!;
curLeftValue.value = defaultInitLeft.value;
containerDom.style.setProperty("--cur-init-left", `${curLeftValue.value}px`);
}
const getPercent = () => {
const containerDom: NonNullable<typeof container.value> = container.value!;
const thumbDom: NonNullable<typeof thumb.value> = thumb.value!;
const defaultLeft = defaultInitLeft.value;
const containerWidth = containerDom.offsetWidth;
const thumbWidth = thumbDom.offsetWidth;
const RANG_LEFT_VALUE = [defaultLeft, containerWidth - defaultLeft - thumbWidth];
const result = (curLeftValue.value - RANG_LEFT_VALUE[0]) / (RANG_LEFT_VALUE[1] - RANG_LEFT_VALUE[0])
const percent = round(result * 100, 0)
return percent
}
onMounted(() => {
resetValue()
});
return {
mousedown, container, thumb, resetValue,
getPercent
}
}
vue
<template>
<div relative ref="container">
<div class="progress"></div>
<div
ref="thumb"
class="progress-control--trangle progress-control--position"
@mousedown="mousedown"
></div>
</div>
</template>
<script setup lang="ts">
import { useProgress } from "./hook";
import type { callBackResponse } from "./hook";
const emits = defineEmits<{
(eventName: "move", callback: callBackResponse): void;
}>();
const { mousedown, container, thumb, resetValue, getPercent } = useProgress<typeof emits>(
emits
);
defineExpose({
resetValue,
getPercent,
});
</script>
<style lang="scss" scoped>
$--cur-init-left: var(--cur-init-left);
.progress {
width: 100%;
height: 0;
border: 1px solid rgba(63, 155, 190, 1);
&-control {
&--trangle {
width: 0;
height: 0;
border: 6px solid transparent;
border-left-color: rgba(16, 195, 220, 1);
transform: translateY(-50%);
cursor: pointer;
}
&--position {
position: absolute;
top: 0;
bottom: 0;
left: $--cur-init-left;
}
}
}
</style>
【推荐】FlashTable:表单开发界的极速跑车,让你的开发效率一路狂飙
【推荐】Flutter适配HarmonyOS 5知识地图,实战解析+高频避坑指南
【推荐】博客园的心动:当一群程序员决定开源共建一个真诚相亲平台
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 于是转身独立开发者
· C#.Net筑基-泛型T & 协变逆变
· dotnet 代码调试方法
· DbContext是如何识别出实体集合的
· 一次 .NET 性能优化之旅:将 GC 压力降低 99%
· 我救了一个网站,性能提升了1500 多倍!
· .NET程序员的多语言笔记本:Polyglot Notebook
· 免费开源 .NET OpenCV 迷你运行时全平台发布
· 经验贴!万字总结网卡丢包及ping延迟等网络问题排查思路
· 用好索引的10条军规