JS手写slider组件(缩放拖拽)
程序员文章站
2022-04-21 21:38:26
...
效果:点击观看
布局:
<div id='box' className='drag-bar-box'>
<div id='drag' className='drag-bar'>
<div id='scaleleft' className='drag-block-left'></div>
<div id='scaleright' className='drag-block-right'></div>
</div>
</div>
样式:
.drag-bar-box {
position: relative;
width: calc(100% - 44px);
height: 16px;
margin-left: 44px;
border: 1px solid #D9D9D9;
border-radius: 3px;
}
.drag-bar-box > .drag-bar {
position: relative;
width: 100%;
height: 100%;
cursor: move;
background: #F5F7FA;
}
.drag-bar-box > .drag-bar .drag-block-left,
.drag-bar-box > .drag-bar .drag-block-right {
position: absolute;
bottom: -1px;
width: 6px;
height: 16px;
background: #fff;
border: 1px solid #C1C9D5;
overflow: hidden;
cursor: w-resize;
}
.drag-bar-box > .drag-bar .drag-block-left {
left: -1px;
}
.drag-bar-box > .drag-bar .drag-block-right {
right: -1px;
}
js:
useEffect(() => {
drag()
function drag () {
const box = document.getElementById('box')
const drag = document.getElementById('drag')
const scaleRight = document.getElementById('scaleright')
const scaleleft = document.getElementById('scaleleft')
dragTool(drag)
scaleRightTool(drag, scaleRight, box)
scaleLeftTool(drag, scaleleft, box)
function computedTime () {
// 滑块范围的总宽度
const boxWidth = box.offsetWidth - 2 // 1230
// 灰色区域的宽度
const dragWidth = drag.style.width // 75.8721%
// 灰色区域距离左边的距离
const dragLeft = drag.offsetLeft // 203
let lineTotalTime = lineEndTime - lineStartTime
// 滑块所在的位置代表的结束、开始时间 parseInt改为Math.ceil(避免计算相差1s导致时序图小绿点丢失问题)
let dragStartTime = Math.ceil(
lineStartTime + lineTotalTime * (dragLeft / boxWidth)
)
let dragEndTime = Math.ceil(
dragStartTime + lineTotalTime * (dragWidth.split('%')[0] / 100)
)
props.updataTime({
startTime: dragStartTime,
endTime: dragEndTime
})
}
// 拖拽方法
function dragTool (node) {
drag.onmousedown = function (ev) {
// 浏览器兼容处理
let e = ev || window.event
// 鼠标按下记录相对位置
// 水平方向都距离 = 当前鼠标左边的距离 - 被拖拽元素距离左边的距离
let offsetX = e.clientX - node.offsetLeft
// 垂直方向都距离 = 当前鼠标都上边的距离 - 被拖拽元素距离距离的距离
let offsetY = e.clientY - node.offsetTop
// 鼠标移动和被拖拽的元素是相对的 这里是鼠标拖拽的物体在整个页面上移动 所以
// move加在document上
document.onmousemove = function (ev) {
// 当前鼠标的事件对象
let e = ev || window.event
// 定义 currentLeft = 当前鼠标位置 - 距离左边的距离
let currentLeft = e.clientX - offsetX
// 定义 currentTop = 当前鼠标上边位置 - 距离上边的距离
let currentTop = e.clientY - offsetY
// 限制左出界 最左是 0
if (currentLeft <= 0) {
currentLeft = 0
}
// 当前窗口的宽 浏览器兼容
const boxWidth = box.offsetWidth - 2
// 限制右边出界 如果大于当前窗口的宽 那么就让它等于当前窗口的宽减去当前元素的offsetWidth 也就是留在原地
if (currentLeft >= boxWidth - drag.offsetWidth) {
currentLeft = boxWidth - drag.offsetWidth
}
// 设置上出界 最上边是 0
if (currentTop <= 0) {
currentTop = 0
}
// 当前窗口的高 浏览器兼容
// 限制下边出界 如果大于当前窗口的高 减去 本身的高 那么就让它等于 当前窗口的高减去本身的高
if (currentTop >= 0) {
currentTop = 0
}
// 当前被拖拽元素的 left 值 等于上面计算出的 currentLeft
node.style.left = (currentLeft / boxWidth) * 100 + '%'
setOldLeft(currentLeftCopy)
setCurrentLeftCopy((currentLeft / boxWidth) * 100)
// dragShadow.style.left = (currentLeft / boxWidth) * 100 + '%'
}
}
// 监听点击时,设置新旧left为同一个值,防止调用接口
document.onclick = function () {
setOldLeft(currentLeftCopy)
setCurrentLeftCopy(currentLeftCopy)
}
// 鼠标弹起取消拖拽 这里添加到 node 元素对象也可以的
document.onmouseup = function () {
document.onmousemove = null
if (oldLeft !== currentLeftCopy) {
computedTime()
}
}
document.onmouseleave = function () {
document.onmousemove = null
if (oldLeft !== currentLeftCopy) {
computedTime()
}
}
}
// 右边缩放
function scaleRightTool (drag, scaleRight, box) {
scaleRight.onmousedown = function (e) {
// 阻止冒泡 避免缩放触发移动事件
e.stopPropagation()
// 取消事件的默认动作
e.preventDefault()
// 定义position
let position = {
w: drag.offsetWidth, // 被缩放元素的offsetWidth
h: drag.offsetHeight, // 被缩放元素的offsetHeight
x: e.clientX, // 当前窗口鼠标指针的水平坐标
y: e.clientY // 当前窗口鼠标指针的垂直坐标
}
document.onmousemove = function (ev) {
ev.preventDefault()
// 设置最大缩放为30*30 Math.max取最大值
let boxRealWidth = box.offsetWidth - 2
const minvalue =
type === 'det'
? boxRealWidth *
(hourToMs[detWindowText] / (lineEndTime - lineStartTime))
: 10
let w = Math.max(minvalue, ev.clientX - position.x + position.w)
w =
w >= boxRealWidth - drag.offsetLeft
? boxRealWidth - drag.offsetLeft
: w
drag.style.width = (w / boxRealWidth) * 100 + '%'
}
// 鼠标离开和抬起取消缩放
document.onmouseup = function () {
document.onmousemove = null
document.onmouseup = null
computedTime()
}
document.onmouseleave = function () {
document.onmousemove = null
document.onmouseup = null
}
}
}
// // 缩放-左边div
function scaleLeftTool (drag, scaleleft, box) {
scaleleft.onmousedown = function (e) {
// 阻止冒泡 避免缩放触发移动事件
e.stopPropagation()
// 取消事件的默认动作
e.preventDefault()
// 定义position
let position = {
w: drag.offsetWidth, // 被缩放元素的offsetWidth
h: drag.offsetHeight, // 被缩放元素的offsetHeight
x: e.clientX, // 当前窗口鼠标指针的水平坐标
y: e.clientY, // 当前窗口鼠标指针的垂直坐标
r: drag.style.left.split('%')[0]
}
document.onmousemove = function (ev) {
ev.preventDefault()
// 设置最大缩放为70 Math.max取最大值
let boxRealWidth = box.offsetWidth - 2
const minvalue =
type === 'det'
? boxRealWidth *
(hourToMs[detWindowText] / (lineEndTime - lineStartTime))
: 10
let w = Math.max(minvalue, position.x - ev.clientX + position.w)
// 挪动的距离
// ev.clientX:鼠标距离屏幕左边缘的距离拖动时一直在变的
// drag.offsetLeft 被缩放元素距离它的父级元素左边的距离 只能获取不能设置
let copyw = position.x - ev.clientX
// 设置left Math.max取最大值
let l = Math.max(
minvalue,
(position.r / 100) * boxRealWidth - copyw
)
w = w >= boxRealWidth ? boxRealWidth : w
drag.style.width = (w / boxRealWidth) * 100 + '%'
l =
drag.offsetLeft + drag.offsetWidth >= boxRealWidth
? boxRealWidth - w
: l
drag.style.left = (l / boxRealWidth) * 100 + '%'
setOldLeft(currentLeftCopy)
setCurrentLeftCopy((l / boxRealWidth) * 100)
}
// 鼠标离开和抬起取消缩放
document.onmouseup = function () {
document.onmousemove = null
document.onmouseup = null
computedTime()
}
document.onmouseleave = function () {
document.onmousemove = null
document.onmouseup = null
}
}
}
}
})
上一篇: antv G6事件方法小结
下一篇: antv从数据库中获取数据