Open phenomLi opened 6 years ago
最近再做一个类似滑块控件的东西,按道理来说滑块控件应该是挺好做的,没什么难度。但是具体做的时候却遇到了一点点小波折,就是类似下面这种滑块的实现: 主要难点就在于这种滑块的滑动点不是连续的,而是离散的。连续的还比较好做,只要获取鼠标的clientX然后转换成控件圆点的left就行。 那么,离散的要怎么实现? 先不急,我们先仔细观察一下这个控件,看看有什么规律可循。其实正常人都能看出来,控件小圆点在哪个离散点取决于鼠标的相对离散点的最近距离。 假如控件有A,B,C三个离散断点,离散点之间的距离我们取个中点,以这些中点为分界点,鼠标在中点左侧,则小圆点在左侧离鼠标最近那个离散点,若鼠标在中点右侧,则小圆点在右侧离鼠标最近那个离散点。画个图好理解一点: 假如ABC之间距离都为100,那么鼠标在< 50的位置时小圆点在A上,>= 50 && < 150 小圆点在B上,>= 150小圆点在C上,以此类推。
clientX
left
< 50
>= 50 && < 150
>= 150
现在知道了原理,但是怎么用代码实现呢? 当时想了挺久的,一开始打算用简单粗暴if else判断鼠标位置:
if else
/** * x为鼠标横坐标 */ if(x < 50) { //.... } else if(x >= 50 && x < 150) { //... } else { //... }
但假如离散点很多怎么办?所以if else不太现实。后来想到用取模%:
%
/** * x为鼠标横坐标 * interval为离散点间间隔 */ n = x%interval //??????? n = x%(interval/2) //???????
但是认真推算一下根本不是那个道理,好像越想越歪,走不通。 难道就没有办法了吗,看起来并不是很复杂的功能啊。其实再结合上面的图仔细联想一下,假如我想要小圆点在B上,我只要鼠标大于1/2AB并且小于1/2BC,也就是说,假如以B为基准,只要大于一点点1/2AB就取到基准,小于一点点1/2BC就舍去不要,这不就是小学学的四舍五入嘛! 大体思路是有了,但是怎么四舍五入是个问题。其实思路很简单,离散点间的距离是已知的,以控件最左边为原点,我们用鼠标的横坐标/控件距离,再四舍五入,就可以算出现在圆点应该在哪个离散点上。伪代码如下:
/** * x为鼠标横坐标 * interval为离散点间间隔 * * Math.round是javascript提供的四舍五入的方法 */ n = Math.round(x/interval);
那么知道了应该要到哪个点上,那么只要将n乘上离散点间间隔,就能算出小圆点的left应该设置多少了:
n
left = interval*Math.round(x/interval);
就是这么简单直接,没有一点点多余的东西,一行代码搞定。 下面是我做的一个成品效果:
核心代码:
/** * clickFlag是一个标志,用作判断用户是否按下鼠标,按下鼠标才能拖拽圆点 * 在mousedown的时候将标志设置为true,表示用户已经按下鼠标 */ mouseDown() { this.setState({ clickFlag: true }); } /** * mousemove的时候先判断用户是否在按下鼠标的情况下进行拖拽 * transformXY是用作将鼠标相对于页面的横纵坐标转换成相对于控件的横纵坐标 * @param {Event} ev 事件对象 */ mouseMove(ev) { if(this.state.clickFlag) { let {x, y} = this.transformXY(ev.clientX, ev.clientY); /** * 首先做一个判断,防止鼠标越界(超出控件) */ if(x < 400 - 7 && x > 0) { this.setState({ /** * 关键代码 * 100就是离散点间的间隔 */ left: Math.round(x/100)*100 }); } } } /** * mouseup鼠标抬起,将标志位设置为false */ mouseUp() { this.setState({ clickFlag: false }); }
最近再做一个类似滑块控件的东西,按道理来说滑块控件应该是挺好做的,没什么难度。但是具体做的时候却遇到了一点点小波折,就是类似下面这种滑块的实现:
假如ABC之间距离都为100,那么鼠标在
主要难点就在于这种滑块的滑动点不是连续的,而是离散的。连续的还比较好做,只要获取鼠标的
clientX
然后转换成控件圆点的left
就行。那么,离散的要怎么实现?
先不急,我们先仔细观察一下这个控件,看看有什么规律可循。其实正常人都能看出来,控件小圆点在哪个离散点取决于鼠标的相对离散点的最近距离。
假如控件有A,B,C三个离散断点,离散点之间的距离我们取个中点,以这些中点为分界点,鼠标在中点左侧,则小圆点在左侧离鼠标最近那个离散点,若鼠标在中点右侧,则小圆点在右侧离鼠标最近那个离散点。画个图好理解一点:
< 50
的位置时小圆点在A上,>= 50 && < 150
小圆点在B上,>= 150
小圆点在C上,以此类推。实现
现在知道了原理,但是怎么用代码实现呢?
当时想了挺久的,一开始打算用简单粗暴
if else
判断鼠标位置:但假如离散点很多怎么办?所以
if else
不太现实。后来想到用取模%
:但是认真推算一下根本不是那个道理,好像越想越歪,走不通。
难道就没有办法了吗,看起来并不是很复杂的功能啊。其实再结合上面的图仔细联想一下,假如我想要小圆点在B上,我只要鼠标大于1/2AB并且小于1/2BC,也就是说,假如以B为基准,只要大于一点点1/2AB就取到基准,小于一点点1/2BC就舍去不要,这不就是小学学的四舍五入嘛!
大体思路是有了,但是怎么四舍五入是个问题。其实思路很简单,离散点间的距离是已知的,以控件最左边为原点,我们用鼠标的横坐标/控件距离,再四舍五入,就可以算出现在圆点应该在哪个离散点上。伪代码如下:
那么知道了应该要到哪个点上,那么只要将
n
乘上离散点间间隔,就能算出小圆点的left
应该设置多少了:就是这么简单直接,没有一点点多余的东西,一行代码搞定。
下面是我做的一个成品效果:
核心代码: