xj.operate 判断操作方式

基本介绍

简介 : 这个插件主要用于判断用户的操作方式,究竟是用鼠标操作还是触屏操作,在引入了这个插件之后,当用户使用鼠标进行操作时 <html> 上将会出现 xj-operate-mouse 的类,当用户使用触屏进行操作时 <html> 上将会出现 xj-operate-touch 的类,这两个类名的设置并非是一次性的,它会根据用户的操作模式进行动态监听和变化,这有助于我们根据用户不同的操作方式进行不同的设置。

兼容 : IE10+ / Edge12+ / Firefox / Chrome / Safari / Opera / IOS Webkit / Android Platform

更新 : https://github.com/xjZone/xj.operate/blob/master/upgrade.md

源码 : https://github.com/xjZone/xj.operate/

协议 : Apache License 2.0

版本 :


引入插件

首先是引入相关的文件,推荐使用带 immutableJSDelivr CDN:


如何使用

如果使用了鼠标进行操作,那么 html 标签会被添加 xj-operate-mouse 类名,如果使用了触屏进行操作,那么 html 标签会被添加 xj-operate-touch 类名,如果既不是鼠标也不是触屏,那么 html 标签会被添加 xj-operate-other 类名,但除非是手动调用了 xj.operate.otherSet() 方法,否则 other 状态一般都不会自动出现的,下面是一个简单的例子,什么状态就显示什么关键词:


让 hover 在触屏时无效

:hover 伪类选择器用于定义元素被鼠标悬停时的样式,但它在 touch 触屏操作的环境下表现就不是那么让人满意了,主要是触屏操作并不像鼠标那样有所谓的悬停状态,所以得点击后才能生效,它也没有像鼠标挪开这样的概念,所以得等到元素失焦后才会失效,这就造成了有时样式并不符合预期结果的情况,因此有人会希望触屏操作时不要让这个选择器生效,现在借助 xj.operate 插件可轻松实现了。


通过配置控制长按结果

在上个例子中我们已经展示了如何让 :hover 选择器不在触屏操作时生效,但如果你觉得在触屏操作时完全禁止 :hover 的样式有些不妥,那么也许可以考虑使用插件提供的折中方案,那就是通过全局配置中的 pressHover 参数,来允许触屏模式下让长按操作能响应 :hover 选择器,其工作原理是判断到长按就临时切换为鼠标的状态,之后如果再次触发了 touchstart 事件就恢复为触屏的状态。


通过配置自定义类名

如果你觉得插件提供的默认类名如 xj-operate-mousexj-operate-touch 实在是太长了,那么可通过全局配置进行修改,但实际上 XJ 并不推荐修改默认类名,因为 XJ 系列插件都是只响应这些默认类名而已,如果修改了可能会引发一些样式错误,但我们还是可以通过全局配置的 mouseCallback, touchCallback, otherCallback 这三个回调方法,在状态被改变的时候同时进行类名的设置。


手动调整当前状态

插件对象提供了 xj.operate.mouseSet(), xj.operate.touchSet(), xj.operate.otherSet() 这三个方法,用于手动改变当前的状态,但是这些改变都是暂时的,在调用了这些方法之后,一旦再次触发 mousemove 事件或者 touchstart 事件,就会恢复为原本的自然状态,除非是在调用这三个方法时传入 false 参数,那样就不会自动恢复了,更多细节可以参考之后的 xj.operate 对象。


xj.operate 对象

xj.operate 对象除了 mouseSet(), touchSet(), otherSet() 这三个方法之外,还有其他一些属性,下面都罗列一下,值得注意的是三个改变状态的方法,改变默认都是暂时性的,之后用户再次触发相关事件,将恢复为正常状态,除非是调用它们时传入 false 参数,此时如果不再重新调用一次 mouseSet()touchSet()otherSet(),则不会再自动恢复监听,也就是说状态将固化。


全局配置

全局配置的对象,用于控制节点类名的设置,长按操作和时间间隔,状态被改变时的回调等内容,需要注意的是,全局配置得在引入插件前就设置好,否则插件加载并执行的时候找不到配置,就会认为配置不存在,并且版本号还要对得上,否则插件也不会理会的,例如本页面使用的插件是 0.6.0 的版本,在 xj.operateConfig 对象后面跟着的就是 ['0.6.0'],版本匹配是考虑到多版本并存而设计的。


判断原理

如何判断当前是使用鼠标操作还是触屏操作?有些开发者会以浏览器是否支持 touchstart 事件做为依据,支持就认为是使用了触屏操作,然而这种判断方法并不可靠,因为支持该事件的设备,也可能是使用着鼠标进行操作的,使用鼠标的环境下设备也可能是支持触屏操作的,那么怎么做才更加准确呢?浏览器目前并没有提供任何关于用户操作模式的 API,但是我们可以曲折的实现,以下是判断的原理。

在支持触屏的环境下,常规的触屏点击会按顺序先触发 touchstart 再触发 mousemove,所以我们可以使用这两个事件的时间间隔来进行判断,如果 touchstartmousemove 的触发时间间隔大于 500ms,那就认为这两个事件并非是同个点击操作导致的,所以此时是使用了鼠标,如果这两个事件的触发时间间隔小于 500ms,则认为它们是由于触屏点击而同时触发的,那么此时是使用了触屏。

之所以使用 500 毫秒进行判断,是因为在部分移动端的浏览器如 Safari(IOS) 中,点击相关的事件存在 300 毫秒的延迟,而事件如果延迟 500 毫秒以上就是长按而不是点击了,所以小于 500 毫秒是比较适中的,兼顾到了延迟和长按,当然实际上判断操作还要考虑事件的真实性(event.isTrusted)和滚动或捏合缩放等,但这些都是插件的细节,就不过多讲述了,有兴趣的可自行查看插件源码。


项目备注

01. :hover:active 这两个伪类选择器在 Safari(IOS) 中存在问题,具体来讲就是如果目标节点无法被聚焦或点击时没有特殊效果,那么这个节点就无法正常响应这两个伪类选择器,解决这问题的常用手段有两种,一是给目标节点绑定 touchstart 事件,回调是个空函数也无所谓,二是给目标节点设置 tabIndex 属性,让节点变得可被聚焦,在之前 "让 hover 在触屏时无效" 的案例中,我们就采用了第二种方法来确保 :hover 伪类生效,但这个问题并不会出现在 buttona 这些本来就可聚焦或可点击的元素上。

02. 插件判断设备类型其实是动态的,因为存在触屏设备插上鼠标变成鼠标操控,或 PC 转为触屏模式如 Chrome 使用移动端模拟,所以动态监听下适应性会更好,但状态的改变还得等对应的事件被触发,也就是说改变并不是立刻生效的,起码得移动过鼠标或触屏过才行。

03. 有疑问或者发现 BUG,可到 GitHub 提 Issue,如果觉得插件写得还行,在 GitHub 中为本项目点个 ★Star 吧,感谢啦 ಠ‿ಠ ❤。


推荐阅读

XJ.Chen - 浅谈 :hover 伪类选择器在 touch 环境如何禁止生效的问题


Copyright © 2015- XJ.Chen All Rights Reserved
More XJ Plugins : https://github.com/xjZone/