混合开发中粘贴功能的实现
最近做了一个粘贴功能,简单记录一下从调研到最后的方案
因为我这的页面是 hybrid ,不是单纯的 web 页面,所以在 api 的使用上也有着限制。业务场景是,需要用户在别处复制一段内容(一键复制,不需要手动选中),然后来我的页面上进行粘贴,解析后调用接口通过参数传递。首先基于业务场景的考虑,要有一些限制,比如可粘贴的最大字符数是多少,需要做 json 格式校验,需要做内容字段解析,解析出的内容需做简单的 length 判断。然后看粘贴的方案怎么实现,理想的方案是,FE 展示一个按钮,点击按钮的时候调用端的能力去获取粘贴内容,但是当前端并无提供的 action,端改动的话需要跟版,预计会是一个很长的周期,看能不能有 FE 的临时方案,可以无需跟版直接上线,后续等端支持了粘贴能力再做主动获取粘贴。
FE 粘贴方案选型
execCommand
mdn 上已经将其标记为弃用,自然不在考虑之中
clipboard.js
这个也是以前做后台项目常用的,但是这个库只是支持复制,并不支持粘贴能力
ClipboardAPI
这个按说是最合适,浏览器提供的 api 足够强大和安全,但是它在调用的时候会弹出询问框,需要用户点击同意之后才能使用。然后写了 demo 页面在端中测试,当使用端的正式包且使用 https 的页面地址的时候 navigator.clipboard
这个对象才是可用,其次,可能是端的 web 容器对弹出框有拦截操作,在端内使用时,这个询问框根本弹不出来,所以调用会直接报错,error 是 undefined ,所以这个 api 在端内实际用不了
这个 api 具体的使用就不介绍了,网上一大堆
paste 事件
当用户通过浏览器的用户界面发起一个“粘贴”动作时,将触发 paste
事件。试了下这个还是比较符合预期的,但是需要文案提示用户,通过 Ctrl+V 键进行粘贴操作,也算是符合常用的粘贴操作吧,可以接受。
但是这个后面联调的时候发现了一个怪问题,就是我们常见的操作是,点击页面聚焦,然后就可以进行粘贴操作了,但是在端内的时候,需要点击两次才能监听到粘贴事件,只点击一次的时候无法获取到焦点,在浏览器中是没有这个问题的,但是毕竟浏览器的页面本身自带一个聚焦,所以这个对比也不是特别可靠。然后经过了艰苦的排查,并尝试进行 hack,看能否让用户只点击一次就行,结果都是不行,然后想是否容器有问题,因为另一页面的输入框也是需要点击两次才能聚焦,找了端上的老师排查之后,果然,端的底层做了一点事情,将第一次点击焦点直接丢弃了,所以每次需要点两下才能获取焦点。噢漏,这属实难顶。
结语
所以最后的主要方案还是要使用端的能力去主动获取粘贴内容,这样稳定可靠,交互简单。FE 的方案作为发版前的临时方案使用,会给用户提示,需要双击后再 cv 粘贴,然后给粘贴框加了一个 focus 样式,用伪类写一个闪动的光标就行了,然后粘贴框是 div,正常是无法获取焦点的,在标签上添加了一个 tabindex="-1"
的属性,使其可以响应聚焦,这样用 css 就可以准确达到聚焦的效果。用 js 的话反而麻烦,因为页面在端内只是一部分,端内还可能会点击页面之外的地方,一些边界条件需要判断,就比较麻烦。
而且监听粘贴事件的话,没法主动控制粘入的内容的大小,用户粘一个 1G 的内容也是可以的,但是会引起页面的卡顿,这个暂时没什么好的解决办法,只能是等主动粘贴能用之后去掉这个被动粘贴比较靠谱。