这里的实现也很简单,唯一需要看一下的就是通过 getBoundingClientRect 来获取了滑块相对于视口的位置,然后根据鼠标所在的位置来判断鼠标是否在滑块上,如果不在则取消移动。
现在它已经能很好的滑动,并完成提示成功的基本功能了。但是,当我们每次滑动到中间就取消,然后再次点击滑动时,就会导致重复的添加滑动事件,而且中途释放后,滑块就停在了当前位置,这显然不对。
解决的办法就是在添加鼠标按下事件的时候,同时也指定一个松开的事件,在这个事件的监听器中判断如果没有成功则取消之前绑定的滑动事件,并进行重置,为了看起来更友好,我们还可以加上一点动画。
class SlideUnlock { init() { /* ... */ document.addEventListener( "mouseup", (this.$$handleMouseUp = this._handleMouseUp.bind(this)), false ) } _handleMouseDown(e) { /* ... */ // 取消在手动滑动过程中的动画效果 this.$$bg.style.transition = "" this.$$block.style.transition = "" /* ... */ } _handleMouseUp(e) { this.$$block.removeEventListener( "mousemove", this.$$handleMouseMove, false ) if (this.$$isSuccess) { return } // 给重置过程添加动画效果 this.$$bg.style.transition = "width 1s ease" this.$$block.style.transition = "left 1s ease" this.$$block.style.left = 0 this.$$bg.style.width = 0 } }
目前为止,滑块已经可以在 PC 端正常的工作了,不过在移动端却并不理想。
为了它能够在移动端也可以很好的工作,我们可以借助 touchstart、touchmove、touchend 等事件来完成。
绑定这些事件的时机和处理方式和之前的三个事件分别相对应,所以我们新增两个方法(和 jQuery 的 on、off 方法很像)来更好的添加和移除事件。
function bindEvents(events, handler, element = $("body")) { events.split(" ").forEach(event => { element.addEventListener(event, handler, false) }) } function unbindEvents(events, handler, element = $("body")) { events.split(" ").forEach(event => { element.removeEventListener(event, handler, false) }) }
根据这两个方法,我们来稍微修改一下滑块中添加事件的代码。
function bindEvents(events, handler, element = $("body")) { events.split(" ").forEach(event => { element.addEventListener(event, handler, false) }) } function unbindEvents(events, handler, element = $("body")) { events.split(" ").forEach(event => { element.removeEventListener(event, handler, false) }) }
另外,需要注意的是在移动端 touch 事件中获取 clientX、clientY 时不能在事件对象上直接读取,而是在 event.changedTouches[0] 对象上取得。
现在,它已经能够同时在 PC 端和移动端上工作了,不过我们还能对它进行一些优化,比如使用函数节流。
函数节流的实现方式有很多,这里列一下我们在本次过程中使用的方式。
utils.throttle = function(method, context = {}, delay = 4, ...outParams) { return function(...innerParams) { clearTimeout(context.$$tId) context.$$tId = setTimeout(function() { method.apply(context, [...outParams, ...innerParams]) }, delay) } }
然后用这个节流函数,来包装我们移动时的处理函数,并根据实际情况做点调整。
除此之外,我们还可以添加一个重置的方法,让它回到最初的状态,涉及到的内容也很简单,就是在成功的状态下重新设置样式和绑定事件。
reset() { if (!this.$$isSuccess) { return } this.$$isSuccess = false this.$$bg.style.cssText = `transition: width ${this.$options.duration}ms ease; width: 0;` this.$$block.style.cssText = `transition: left ${this.$options.duration}ms ease; left: 0;` this.$$text.style.cssText = `color: #5f5f5f; left: ${this.$$block.offsetWidth}px; right: 0;` this.$$text.textContent = this.$options.tip this.$$block.classList.remove("success") this._bindEvents() }
好了,滑块的实现到这里就告一段落了,相信大家看到这里已经完全明白了,甚至有更好的实现。
如何使用
你可以简单的在 HTML 页面中引入该脚本,然后根据自己的需求设置合适的样式;不过更好的方式是通过这样的思路,在项目中做一些改进(比如平滑降级)等处理。
接下来是一个简单的使用模板。
<body> <script src="https://www.jb51.net/slide-unlock/core.js"></script> <script> const slider = new SlideUnlock() slider.init() </script> </body>
你可以在 这里 看见完整的使用方式和效果。