使用js如何手搓一个缩放条
先看效果图

前言
可以通过拖动按钮显示不同的进度,如何手搓一个缩放条,这是我们需要用的鼠标事件和鼠标定位。
鼠标事件
click | 单击鼠标左键时发生,如果右键也按下则不会发生。当用户的焦点在按钮上并按了 Enter 键时,同样会触发这个事件 |
---|---|
dblclick | 双击鼠标左键时发生,如果右键也按下则不会发生 |
mousedown | 单击任意一个鼠标按钮时发生 |
mouseout | 鼠标指针位于某个元素上且将要移出元素的边界时发生 |
mouseover | 鼠标指针移出某个元素到另一个元素上时发生 |
mouseup | 松开任意一个鼠标按钮时发生 |
mousemove | 鼠标在某个元素上时持续发生 |
mouseenter | 在鼠标光标位于元素外部时触发,然后移动到元素内部。 |
mouseleave | 在鼠标光标悬停在元素上时触发,然后移动到元素的外部。 |
鼠标定位
clientX | 以浏览器窗口左上顶角为原点,定位 x 轴坐标 | 所有浏览器,不兼容 Safari |
---|---|---|
clientY | 以浏览器窗口左上顶角为原点,定位 y 轴坐标 | 所有浏览器,不兼容 Safari |
offsetX | 以当前事件的目标对象左上顶角为原点,定位 x 轴坐标 | 所有浏览器,不兼容 Mozilla |
offsetY | 以当前事件的目标对象左上顶角为原点,定位 y 轴坐标 | 所有浏览器,不兼容 Mozilla |
pageX | 以 document 对象(即文档窗口)左上顶角为原点,定位 x 轴坐标 | 所有浏览器,不兼容 IE |
pageY | 以 document 对象(即文档窗口)左上顶角为原点,定位 y 轴坐标 | 所有浏览器,不兼容 IE |
screenX | 计算机屏幕左上顶角为原点,定位 x 轴坐标 | 所有浏览器 |
screenY | 计算机屏幕左上顶角为原点,定位 y 轴坐标 | 所有浏览器 |
layerX | 最近的绝对定位的父元素(如果没有,则为 document 对象)左上顶角为元素,定位 x 轴坐标 | Mozilla 和 Safari |
layerY | 最近的绝对定位的父元素(如果没有,则为 document 对象)左上顶角为元素,定位 y 轴坐标 | Mozilla 和 Safari |
本文主要用到的事件-----mousemove 事件类型是一个实时响应的事件,当鼠标指针的位置发生变化时(至少移动一个像素),就会触发 mousemove 事件。该事件响应的灵敏度主要参考鼠标指针移动速度的快慢以及浏览器跟踪更新的速度。
代码实现
1.创建所要实现的标签
xml
<div>
<div class="progress-container">
<!-- 缩放条 -->
<div class="progress-bar">
<!-- 缩放条上面的label -->
<div class="label">
{{ `${Math.round(scalePercent)}%` }}
</div>
<!-- 拖方块图片 -->
<img src="../../assets/DisplayArea/slider.png" class="slider"/>
<!-- 滑动的过后的背景条 -->
<div class="progress" :style="{ width: `${scalePercent}%` }"></div>
</div>
</div>
</div>
2.给缩放条添加样式
css
.page{
width: 100vw;
height: 100vh;
background-color: #33CCCC ;
}
.progress-container {
width: 936px;
height: 48px;
position: absolute;
top: 50%;
left: calc(50% - 462px);
background-color: rgba(0, 0, 0, 0);
}
.progress-bar {
width: 888px;
height: 8px;
position: absolute;
bottom: 20px;
left: 18px;
background-color: #a49a9a;
// background-image: linear-gradient(to right,#AF40FF, #5B42F3 50%,#00DDEB);
border-radius: 6px;
}
.label {
width: 92px;
height: 72px;
text-align: center;
padding-top: 16px;
box-sizing: border-box;
background-image: url('../../assets/DisplayArea/bubble.png');
background-size: 100%;
font-size: 16px;
font-weight: bold;
color: #00428b;
position: absolute;
top: -72px;
}
.slider {
width: 36px;
height: 24px;
position: absolute;
top: -8px;
z-index: 2;
cursor: grab;
box-shadow: 0 6px 12px rgba(0, 128, 232, 0.16);
}
.progress {
height: 100%;
// background-color: #00428b;
background: linear-gradient(45deg, #ffbc00, #ff0058);
border-radius: 6px;
}
3.实现缩放条的拖动同时数值的变化。这就要用到鼠标的事件了,给容器添加事件
xml
<div class="page">
<div
class="progress-container"
@mouseleave="onHandlerUnSelected"
@mousemove="onSettingScale"
@mouseup="onHandlerUnSelected"
>
<!-- 缩放条 -->
<div class="progress-bar">
<!-- 缩放条上面的label -->
<div class="label">
{{ `${Math.round(scalePercent)}%` }}
</div>
<!-- 拖方块图片 -->
<img
src="../../assets/DisplayArea/slider.png"
class="slider"
@mousedown="onHandlerSelected"
@mouseup="onHandlerUnSelected"
/>
<!-- 滑动的过后的背景条 -->
<div class="progress"></div>
</div>
</div>
</div>
4.书写鼠标事件,通过鼠标定位计算出相差的距离,来更新缩放条的数值。
csharp
<script setup lang="ts">
import { ref } from 'vue'
// 进度数值
let scalePercent = ref(50)
// 是否是在选中状态下拖动
let sliderSelected = ref(false)
let start: number = 1
// 鼠标选中缩放条上滑块时触发
function onHandlerSelected(event: MouseEvent): void {
// 阻止事件冒泡并且阻止该元素上同事件类型的监听器被触发
// 解决事件的兼容性问题
event = event || window.event
event.stopImmediatePropagation()
// 阻止事件冒泡
event.stopPropagation()
// 取消事件的默认动作
event.preventDefault()
// 显示鼠标样式
sliderSelected.value = true
start = event.clientX
}
// 鼠标松开缩放条滑块时触发
function onHandlerUnSelected(): void {
sliderSelected.value = false
start = 1
}
// 鼠标在缩放条上移动时触发
function onSettingScale(event: MouseEvent): void {
if (!sliderSelected.value) return
// 解决事件的兼容性问题
event = event || window.event
updateProgress(event.clientX)
}
//更新进度条和数值
function updateProgress(x: number): void {
const dis = x - start
//window.innerWidth 窗口的内部宽度
// full 计算出缩放条的相对像素
const full = window.innerWidth * (888 / 1920)
// 移动的像素除以缩放条总共的像素 在乘以100 计算出百分比
const per = (dis / full) * 100
// 默认50%的百分比 加上计算出来的百分比
scalePercent.value += per
if (scalePercent.value < 0) {
scalePercent.value = 1
}
if (scalePercent.value > 100) {
scalePercent.value = 100
}
start = x
}
</script>
5.鼠标事件已经写好,需要给缩放条添加缩放的样式效果。
xml
<div class="page">
<div
class="progress-container"
@mouseleave="onHandlerUnSelected"
@mousemove="onSettingScale"
@mouseup="onHandlerUnSelected"
:style="{ cursor: sliderSelected ? 'grabbing' : '' }"
>
<!-- 缩放条 -->
<div class="progress-bar">
<!-- 添加的style -->
<div class="label" :style="{ left: `calc(${scalePercent}% - 46px)` }">
{{ `${Math.round(scalePercent)}%` }}
</div>
<!-- 拖方块图片 添加的style-->
<img
src="../../assets/DisplayArea/slider.png"
class="slider"
:style="{
left: `calc(${scalePercent}% - 18px)`,
cursor: sliderSelected ? 'grabbing' : ''
}"
@mousedown="onHandlerSelected"
@mouseup="onHandlerUnSelected"
/>
<!-- 滑动的过后的背景条 添加的style-->
<div class="progress" :style="{ width: `${scalePercent}%` }"></div>
</div>
</div>
</div>
完整代码和素材
xml
<script setup lang="ts">
import { ref } from 'vue'
// 进度数值
let scalePercent = ref(50)
// 是否是在选中状态下拖动
let sliderSelected = ref(false)
let start: number = 1
// 鼠标离开缩放条时触发
// function onCursorOutside(): void {
// // 离开缩放条时让鼠标样式重置
// sliderSelected.value = false
// start = 1
// }
// 鼠标选中缩放条上滑块时触发
function onHandlerSelected(event: MouseEvent): void {
// 阻止事件冒泡并且阻止该元素上同事件类型的监听器被触发
// 解决事件的兼容性问题
event = event || window.event
event.stopImmediatePropagation()
// 阻止事件冒泡
event.stopPropagation()
// 取消事件的默认动作
event.preventDefault()
// 显示鼠标样式
sliderSelected.value = true
start = event.clientX
}
// 鼠标松开缩放条滑块时触发
function onHandlerUnSelected(): void {
sliderSelected.value = false
start = 1
}
// 鼠标在缩放条上移动时触发
function onSettingScale(event: MouseEvent): void {
if (!sliderSelected.value) return
// 解决事件的兼容性问题
event = event || window.event
updateProgress(event.clientX)
}
function updateProgress(x: number): void {
const dis = x - start
//window.innerWidth 窗口的内部宽度
// full 计算出缩放条的相对像素
const full = window.innerWidth * (888 / 1920)
// 移动的像素除以缩放条总共的像素 在乘以100 计算出百分比
const per = (dis / full) * 100
// 默认50%的百分比 加上计算出来的百分比
scalePercent.value += per
if (scalePercent.value < 0) {
scalePercent.value = 1
}
if (scalePercent.value > 100) {
scalePercent.value = 100
}
start = x
}
</script>
<template>
<div class="page">
<div
class="progress-container"
@mouseleave="onHandlerUnSelected"
@mousemove="onSettingScale"
@mouseup="onHandlerUnSelected"
:style="{ cursor: sliderSelected ? 'grabbing' : '' }"
>
<!-- 缩放条 -->
<div class="progress-bar">
<!-- 缩放条上面的label -->
<div class="label" :style="{ left: `calc(${scalePercent}% - 46px)` }">
{{ `${Math.round(scalePercent)}%` }}
</div>
<!-- 拖方块图片 -->
<img
src="../../assets/DisplayArea/slider.png"
class="slider"
:style="{
left: `calc(${scalePercent}% - 18px)`,
cursor: sliderSelected ? 'grabbing' : ''
}"
@mousedown="onHandlerSelected"
@mouseup="onHandlerUnSelected"
/>
<!-- 滑动的过后的背景条 -->
<div class="progress" :style="{ width: `${scalePercent}%` }"></div>
</div>
</div>
</div>
</template>
<style lang="less" scoped>
.page{
width: 100vw;
height: 100vh;
background-color: #33CCCC ;
}
.progress-container {
width: 936px;
height: 48px;
position: absolute;
top: 50%;
left: calc(50% - 462px);
background-color: rgba(0, 0, 0, 0);
}
.progress-bar {
width: 888px;
height: 8px;
position: absolute;
bottom: 20px;
left: 18px;
background-color: #a49a9a;
// background-image: linear-gradient(to right,#AF40FF, #5B42F3 50%,#00DDEB);
border-radius: 6px;
}
.label {
width: 92px;
height: 72px;
text-align: center;
padding-top: 16px;
box-sizing: border-box;
background-image: url('../../assets//DisplayArea/bubble.png');
background-size: 100%;
font-size: 16px;
font-weight: bold;
color: #00428b;
position: absolute;
top: -72px;
}
.slider {
width: 36px;
height: 24px;
position: absolute;
top: -8px;
z-index: 2;
cursor: grab;
box-shadow: 0 6px 12px rgba(0, 128, 232, 0.16);
}
.progress {
height: 100%;
// background-color: #00428b;
background: linear-gradient(45deg, #ffbc00, #ff0058);
border-radius: 6px;
}
</style>
素材


