前言
相信很多人做需求过程中,都遇到过把文字复制到剪贴板的功能。很不幸我也遇到了,本以为是一个简简单单的需求,开发测试过程中却遇到了不少坑,这里一一展开。
execCommand
方法
第一次,我使用了选中文字 execCommand
这个方法来实现,代码如下:
创建了一个textArea
DOM 元素,插入到 body
中,再选中 textArea
的内容,执行 document.execCommand('copy')
,最后在移除 textArea
。
写完一跑,没问题,完美,就提测了。谁承想,提测之后,测试提出来一个 bug。
在手机 Safari 浏览器中,点击复制按钮,整个页面会跳动一下。
这是什么神奇 bug?
经排查(two thousand years later),创建的textArea
不在页面可视区域之内,然后执行textArea.select()
,就会触发浏览器的控件跳转行为,页面会滚动到 textArea
所在位置。然后执行完又快速移除了,就会形成闪动的这么一个现状。
知道问题了,那就很好解决了,给元素增加绝对定位。
于是我修改代码如下:
增加了一个 fixed 定位,left 是-999px,top 是 10 px,保存代码运行测试,ok 完美。
这时候我有查了下execCommand
的 MDN,https://developer.mozilla.org/zh-CN/docs/Web/API/Document/execCommand
该特性已经被弃用,之所以还能用,是因为有些浏览器还没删除实现。可能不知道哪天就删了,也可能永远不删。
这不太行啊
navigator.clipboard
于是,我用上了 navigator.clipboard
,可能兼容性还不太好,所以代码这么写:
测试一下,完美,于是完整代码变成了这样:
优先使用 navigator.clipboard
,如果不存在再降级使用 execCommand
。
又兴高采烈的提测了。
bug 它又来了。
“你来啦,土星,不是,是 bug”
在安卓 APP 的 WebView 中,点击复制按钮没有反应。
我特发?
继续排查(又 two thousand years later)。
点击复制的时候,报错Write permission denied
。
查看 MDN:https://developer.mozilla.org/zh-CN/docs/Web/API/Navigator/clipboard
只有在用户事先授予网站或应用对剪切板的访问许可之后,才能使用异步剪切板读写方法。许可操作必须通过取得权限 Permissions API 的 “clipboard-read” 和/或 “clipboard-write” 项获得。
Navigator 这种新 API 都是需要事先授予权限的,而权限是通过 Permissions API
获取的。
看这里,原来 Permissions API
在安卓的 WebView 中是没实现的。
CGQAQ 同学帮我找了一下 android_webview 的源码
果不其然,这里并没实现,直接返回了PermissionStatus::DENIED
状态。
那么我们再在代码里加一个Permissions API
的判断。
完整代码如下:
调用 APP 方法
还有一种解决方案,就是由安卓端实现一个供 JS 调用的复制到剪贴板方法,JS 判断是否在 APP 内,进行调用。
此方案需要多端协调,考虑情况暂未采用,其他人遇到此问题的可以酌情使用。
最后
又提测了,希望不会出现新的 bug。
后记 2023-1-12
果不其然遇到了新问题,在华为手机自带浏览器上,navigator.clipboard
和 navigator.permissions
都存在,但是抛了个异常:DOMExecption: PAESE_ERROR
。
navigator.clipboard 的兼容性有大问题!
最后我删掉了 navigator.clipboard
,老老实实用 execCommand。
参考文献:
liruifengv2333
,进群交流,抱团取暖。
- 新生代程序员群
- Astro 学习交流群
SayHub
,带来更多原创内容。