微信 H5 页面兼容性——复制到剪贴板

发布时间 2023-07-31 17:33:13作者: 艾前端

在开发微信 H5 页面时,时常会遇到难以解决的兼容性问题,现收集问题和解决方案,以备后用。

在 PC 浏览器和手机移动端浏览器中,Web API 提供了两种方式:

1.1. Document.execCommand() 方法

Document.execCommand() 是操作剪贴板的传统方法,各种浏览器都支持。

它支持复制、剪切和粘贴这三个操作。

  • document.execCommand('copy')(复制)
  • document.execCommand('cut')(剪切)
  • document.execCommand('paste')(粘贴)

缺点:

  1. 它只能将选中的内容复制到剪贴板,无法向剪贴板任意写入内容。
  2. 它是同步操作,如果复制/粘贴大量数据,页面会出现卡顿。
  3. 有些浏览器还会跳出提示框,要求用户许可,这时在用户做出选择前,页面会失去响应。

1.2. 异步 Clipboard API

优点:

  1. 它的所有操作都是异步的,返回 Promise 对象,不会造成页面卡顿。
  2. 可以将任意内容(比如图片)放入剪贴板。
  • Clipboard.readText() 方法用于复制剪贴板里面的文本数据。
  • Clipboard.read() 方法用于复制剪贴板里面的数据,可以是文本数据,也可以是二进制数据(比如图片)。
  • Clipboard.writeText() 方法用于将文本内容写入剪贴板。
  • Clipboard.write() 方法用于将任意数据写入剪贴板,可以是文本数据,也可以是二进制数据。

在微信浏览器中,安卓设备和苹果设备操作复制功能,会出现下面的兼容性问题:

  1. Clipboard.write() 不能正确复制富文本内容(比如包含换行的内容)。

安卓设备复制失败,报错 NotAllowedError: Write permission denied(写权限被拒绝)。
苹果设备复制出来的内容不对包含了一些 html 标签。

  1. Clipboard.write() 不能处理富文本内容,选用了 vue-clipboard3 插件

vue-clipboard3 可以处理富文本内容,换行通过 \n 实现。

使用方式:

  • 第一步:安装 vue-clipboard3
  • 第二步:在需要使用的页面导入:import useClipboard from 'vue-clipboard3';
  • 第三步:实例化 useClipboard,取到 toClipboard 对象。
  • 第四步:toClipboard 是一个异步方法,使用 await toClipboard(copyInfo) 实现复制到剪贴板。

通过 vue-clipboard3 安卓设备能正常复制。
IOS 复制不了跨域的超链接

  1. vue-clipboard3 不能处理苹果设备跨域复制超链接,选用 document.execCommand('copy') 方法

document.execCommand('copy') 只能用于将选中的内容复制到剪贴板,需要模拟选中的操作:

export const copyText = (text: string) => {
  // 数字没有 .length 不能执行selectText 需要转化成字符串
  const textString = text.toString();
  const input = document.createElement('input');
  input.id = 'copy-input';
  input.readOnly = true; // 防止ios聚焦触发键盘事件
  input.style.position = 'absolute';
  input.style.left = '-1000px';
  input.style.zIndex = '-1000';
  document.body.appendChild(input);
  input.value = textString;

  // ios必须先选中文字且不支持 input.select();
  selectText(input, 0, textString.length);

  input.blur();
  document.body.removeChild(input); // 使用完成后,移除 input 元素,避免占用页面高度

  // input自带的select()方法在苹果端无法进行选择,所以需要自己去写一个类似的方法
  // 选择文本。createTextRange(setSelectionRange)是input方法
  function selectText(textBox, startIndex: number, stopIndex: number) {
    if (textBox.createTextRange) {
      //ie
      const range = textBox.createTextRange();
      range.collapse(true);
      range.moveStart('character', startIndex); //起始光标
      range.moveEnd('character', stopIndex - startIndex); //结束光标
      range.select(); //不兼容苹果
    } else {
      //firefox/chrome
      textBox.setSelectionRange(startIndex, stopIndex);
      textBox.focus();
    }
  }

  console.log(document.execCommand('copy'), 'execCommand');
  if (document.execCommand('copy')) {
    document.execCommand('copy');
    showSuccessToast('复制成功');
  }
};
  1. 通过调用 copyText 自定义函数不能复制到剪贴板

直接调用函数 copyText(link) 不能实现复制,需要用户操作后,比如点了某一按钮再调用 函数 copyText(link)。例如在 vant4(轻量、可定制的移动端组件库)中,点弹框复制按钮时调用:

showDialog({
  confirmButtonColor: '#07d08c',
  confirmButtonText: '复制',
  showCancelButton: false,
  message: '录制已完成,您可将下载地址复制到剪切板,在浏览器中粘贴地址进行下载',
}).then(() => {
  copyText(link);
});