mint-ui range 分析
前段时间学习了 mint-ui, 一看,感觉这个 ui 真的是 前端的福音,但是继续学习感觉怪怪的,有一部分出现了问题,
网站上大部分有解答,但是 range 我发现我真心是 找不到答案,就是 拖不动那个滑块,百度也没有资源
当时 是弄了个 input type=range ,正好参数一致,对好位置后放在 那个 range 上面隐形,能正常使用
<input type="range" class="range" v-model.number="rangeValue" max="90" min="10" step="10">
注意这里要使用 .number ,要不然返回的是 字符型的 数据
后来想想不能这样糊弄自己,只好自己去看代码(目前只是小白,写这个单纯交流,勿喷)
html
<template>
<div class="content" ref="content">
<!-- <div class="thumb" ref="thumb"></div> -->
<div class="progress" ref="thumb" :style="{width: progress + '%'}"></div>
<div class="thumb" ref="thumb" :style="{left: progress + '%'}"></div>
</div>
</template>
<script>
data()
data
()
{
return
{
progress
:
0
, // 当前的 进度(相对于 整个 range 的 百分比)
max
:
100
,
min
:
0
,
step
:
1
,
dragState
:
{},
// 拖动的 状态
newProgress
:
null
,
// 新的 在 range 里的 占比
isDragging
:
false
,
// 是否正在拖动
supportTouch
:
true
// 是否支持 touch 事件(源码里是判断来着,但我还是写死好了)
}
},
mounted()
// 这里主要就是 给 元素绑定 各种 拖动的事件
// 我发现 在源码中 主要是没有在这里写 各种绑定事件导致的不能拖动
mounted
()
{
let
element
=
this
.
$refs
.
content
// 获取 range 组件的 根节点
element
.
addEventListener(
this
.
supportTouch
?
'
touchstart
'
:
'
mousedown
'
,
(
event
)
=>
{
if (
this
.
isDragging)
return
event
.
preventDefault()
// 就是 防止 在拖动的时候 顺便把 东西给 左键 选中
document
.
onselectstart
=
function
()
{
return
false
}
// 就是 防止 在拖动滑块的时候 顺便把 东西给 拖放了
document
.
ondragstart
=
function
()
{
return
false
}
if (
!
this
.
supportTouch)
{ // 这里 this.supportTouch 我顺便被 默认 true 了
document
.
addEventListener(
'
mousemove
'
,
this
.
moveFn)
document
.
addEventListener(
'
mouseup
'
,
this
.
endFn)
}
this
.
isDragging
=
true
if (
this
.
start)
{
this
.
start(
this
.
supportTouch
?
event
.
changedTouches[
0]
||
event
.
touches[
0]
:
event)
}
})
if (
this
.
supportTouch)
{
element
.
addEventListener(
'
touchmove
'
,
this
.
moveFn)
;
element
.
addEventListener(
'
touchend
'
,
this
.
endFn)
;
element
.
addEventListener(
'
touchcancel
'
,
this
.
endFn)
;
}
},
methods
:
{
// 获取 滑块的 信息
getThumbPosition
()
{
// 那个小滑块
let
thumb
=
this
.
$refs
.
thumb
// 整个 range 的 容器 (不包括 文字)
let
content
=
this
.
$refs
.
content
let
contentBox
=
content
.
getBoundingClientRect()
let
thumbBox
=
thumb
.
getBoundingClientRect()
return
{
left
:
thumbBox
.
left
-
contentBox
.
left
,
top
:
thumbBox
.
top
-
contentBox
.
top
,
thumbBoxLeft
:
thumbBox
.
left
}
},
/**********************************************************************
说实话,我这是第一次看到这个函数 getBoundingClientRect(),当时找半天,找不到这个函数的 定义在哪里
查了 资料才知道原来是一个 原生 的函数,特意在控制台输出了一下
返回值:
一个一个属性过,说一下
left 和 top 就是理解的那个 left top
但是 bottom = top + height
right = left + width
这个真的是,孤陋寡闻,如闻天音
**********************************************************************/
// 刚点击的 滑块 和 点击点 的位置信息
start
(
event
)
{
console
.
log(
'
start
')
if (
this
.
disabled)
return
let
position
=
this
.
getThumbPosition()
// 看点击的 位置 和 原先 滑块的 位置有 多少距离
let
thumbClickDetalX
=
event
.
clientX
-
position
.
thumbBoxLeft
// 点击之后 滑块 的 位置 属性
this
.
dragState
=
{
thumbStartLeft
:
position
.
left
,
thumbStartTop
:
position
.
top
,
thumbClickDetalX
:
thumbClickDetalX
}
},
drag
(
event
)
{
if (
this
.
disabled)
return
let
dragState
=
this
.
dragState
let
content
=
this
.
$refs
.
content
let
contentBox
=
content
.
getBoundingClientRect()
// 点击之后 拖动的 距离(搞得这么麻烦我也是醉了)
let
deltax
=
event
.
pageX
-
contentBox
.
left
-
dragState
.
thumbStartLeft
-
dragState
.
thumbClickDetalX
let
stepCount
=
Math
.
ceil((
this
.
max
-
this
.
min)
/
this
.
step)
// 这里有点奇妙,我卡在这里有一会了。
// 原始的距离 + 拖动的 距离 理论上就是 当前 距离的数值,
// 但是若设置了 步长, 这里 假设 stepCount = 1, 那 % 之后 一直为 0
// 那 当前的 距离就是 原始的 距离 + 拖动 的 距离
// 若 步长 不为 1 假设 为 10
// 若 拖动的 距离 小于 10 那 % 出来的 数字 即为 拖动的 那一段距离,正好被减掉,滑块为 不拖动,
// 若拖动距离 为 10 那 % 之后的 数字为 0, 那就 会 跳了 一格
let
newPosition
= (
dragState
.
thumbStartLeft
+
deltax)
-
(
dragState
.
thumbStartLeft
+
deltax)
% (
contentBox
.
width
/
stepCount)
console
.
log(
newPosition)
let
newProgress
=
newPosition
/
contentBox
.
width
console
.
log(
newProgress)
if (
newProgress
<
0)
{
newProgress
=
0
}
else
if (
newProgress
>
1)
{
newProgress
=
1
}
// console.log(newProgress)
this
.
progress
=
newProgress
*
100
this
.
$emit(
'
input
'
,
Math
.
round(
this
.
min
+
newProgress
* (
this
.
max
-
this
.
min)))
},
end
()
{
if (
this
.
disabled)
return
this
.
$emit(
'
change
'
,
this
.
value)
this
.
dragState
=
{}
},
moveFn
(
event
)
{
// console.log(event.touches)
if (
this
.
drag)
{
this
.
drag(
this
.
supportTouch
?
event
.
touches[
0]
:
event)
}
},
endFn
(
event
)
{
if (
!
this
.
supportTouch)
{
document
.
removeEventListener(
'
mousemove
'
,
this
.
moveFn)
document
.
removeEventListener(
'
mouseup
'
,
this
.
endFn)
}
document
.
onselectstart
=
null
document
.
ondragstart
=
null
this
.
isDragging
=
false
if (
this
.
end)
{
this
.
end(
this
.
supportTouch
?
event
.
touches[
0]
:
event)
}
}
}
style 只写了很简单的一点
<
style
lang=
"
stylus
"
>
.content
width
100
%
height
10
px
background-color
pink
div
position
absolute
&
.thumb
width
20
px
height
20
px
background-color
white
border-radius
50
%
&
.progress
background-color
blue
height
10
px
</
style
>