最近在IOS客户端UIWebView里遇到禁用选中态的奇怪bug。
本文适用于,仅需要页面部分区域不可选中(比如我们的是一个小图标,span里面包着img),大部分文字都是可以被选中的(因为我们还有反馈错别字功能呀)。
首先说一下我们的场景:
有一个可以无限点击的按键,每次点击都会飞出来一个❤,对于看到这个按键又喜欢乱点的用户,当然会选择一通乱点啊。
于是bug就来了,快速点击会触发浏览器的双击选中事件。点击按键但是按键附近的文字总是动不动就被选中,对于一个有洁癖的程序员来说,这是不可接受的。
于是就引发了一系列的禁止选中态的问题。
先上结论,太长不想看粘走就行
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-touch-callout: none;
如果以上代码没有解决你的禁止选中态的问题,你有两个选择:
- 更换到WKWebView,他里面双击不会选中。
- 使用js来禁掉一且你想禁但是没有禁掉的地方,例如下面
var $body = $('body');
var timeId;
elems.button.on('tap',function() {
clearTimeout(timeId);
$body.css({
'-webkit-user-select': 'none',
'-moz-user-select': 'none',
'-ms-user-select': 'none',
'user-select': 'none',
'-webkit-touch-callout': 'none'
});
// 一些业务代码
// ....
timeId = setTimeout(function() {
$body.css({
'-webkit-user-select': 'text',
'-moz-user-select': 'text',
'-ms-user-select': 'text',
'user-select': 'text',
'-webkit-touch-callout': 'default'
})
}, 300);
});
下面说一下改造过程
对于普通浏览器
对于IOS端,Safari、Chrome经测试加入以下代码即可禁止双击和长按选中
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-touch-callout: none;
-webkit-touch-callout
链接 非标准属性
-webkit-touch-callout: none;
禁用了默认的标注显示( callout shown ), 标注是指当触摸并按住一个元素的时候出现的提示。当在iOS上一直按住一个目标元素时,Safari会展示一个关于这个链接的callout信息。webkit-touch-callout
属性允许禁用掉这一行为。
user-select
链接 实验中的属性
控制着实际的选区(Selection)操作。This doesn't have any effect on content loaded as chrome, except in textboxes.
对于UIWebView
上面这些在浏览器里面没啥毛病。
但是放在IOS APP的webview里面(UIWebView),如果长按选中过其他未被禁止的元素,再长按或者双击禁止的元素时,会默认的去选中距离最近的未被禁止的元素....这是一个很奇特的问题.....
(不知道是不是我们的客户端做了别的什么配置导致,我猜测应该不是吧。反正如果你的UIWebView加上以上代码就完全好了,那就不用往下看了)
从代码来看,HTML解构如下:
<style>
ul li {
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
</style>
<p>我是可以选中的节点</p>
<ul>
<li>
<div>我是被禁掉选中态的div1</div>
<p>我是被禁掉选中态的p1</p>
...
</li>
<li>
<div>我是被禁掉选中态的div2</div>
<p>我是被禁掉选中态的p2</p>
...
</li>
...
</ul>
一进页面,啥也不选,直接长按或者双击li,很好,什么也选不中;
但是,在已选中过顶部的P节点的情况下,双击或长按li,会自动的选中到顶部P里面的内容..........
原因... 应该是浏览器内核的原因,在不设置任何属性的情况下,点击段落空白处,会去选中举例最近的文字。
那这个问题咋解决呢?....
(1) 对于长按乱选中问题
li的外面套一层a,像下面这样
<style>
ul li {
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
a {
text-decoration: none;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
outline: none;
}
</style>
<p>我是可以选中的节点</p>
<ul>
<li>
<a href="javascript:;">
<div>我是被禁掉选中态的div1</div>
<p>我是被禁掉选中态的p1</p>
...
</a>
</li>
<li>
<a href="javascript:;">
<div>我是被禁掉选中态的div2</div>
<p>我是被禁掉选中态的p2</p>
...
</a>
</li>
...
</ul>
可以看到
对a标签,加上href="javascript:;"
,长按的时候乱选中的问题就神奇的解决了。
(2) 对于双击乱选中问题
但是对于双击事件,UIWebView中总是会去找离点击位置最近的可选中的节点。
查看stackoverflow 上的回答,所做的都是我做过的。
事已至此,不得不使用js来帮助了。
去除选中态有两种方法:
- window.getSelection().removeAllRanges();
- document.execCommand('Unselect');
在PC端和移动端Safari Chrome都运行良好,但是在UIWebView中直接无效!
是的!!没错!!!虽然这个方法理论上来说会先出选中,然后再禁掉,会造成不好的视觉效果,我已经做好了心理准备接受这个瑕疵,可是他还是,无效。
这样的话就不得不启用终极方案了:点击的时候禁掉页面所有元素的选中态。
var $body = $('body');
var timeId;
elems.button.on('tap',function() {
clearTimeout(timeId);
$body.css({
'-webkit-user-select': 'none',
'-moz-user-select': 'none',
'-ms-user-select': 'none',
'user-select': 'none',
'-webkit-touch-callout': 'none'
});
// 一些业务代码
// ....
timeId = setTimeout(function() {
$body.css({
'-webkit-user-select': 'text',
'-moz-user-select': 'text',
'-ms-user-select': 'text',
'user-select': 'text',
'-webkit-touch-callout': 'default'
})
}, 300);
});
代码运行稳定,Over!
如果有更好的解决方案,欢迎指出~