useClipboard.js 2.43 KB
import { ref } from 'vue';

/**
 * 跨端剪贴板组合式函数 (JavaScript 版)
 */
export function useClipboard() {
  const isCopying = ref(false);

  const copyText = async (text, options = {}) => {
    if (!text) return false;
    if (isCopying.value) return false; // 简易防抖锁

    isCopying.value = true;
    const successText = options.successText || '复制成功';
    const failText = options.failText || '复制失败';

    return new Promise((resolve) => {
      // #ifdef MP-WEIXIN || APP-PLUS || MP-ALIPAY
      uni.setClipboardData({
        data: text,
        showToast: false, // 隐藏原生沉浸式提示,采用全端统一的自定义 Toast
        success: () => {
          uni.showToast({
            title: successText,
            icon: 'success',
            duration: 1500,
          });
          resolve(true);
        },
        fail: (err) => {
          console.error('Clipboard Error:', err);
          uni.showToast({
            title: failText,
            icon: 'none',
          });
          resolve(false);
        },
        complete: () => {
          isCopying.value = false;
        },
      });
      // #endif

      // #ifdef H5
      if (navigator.clipboard && window.isSecureContext) {
        navigator.clipboard
          .writeText(text)
          .then(() => {
            uni.showToast({ title: successText, icon: 'success' });
            resolve(true);
          })
          .catch(() => {
            fallbackCopy(text, successText, failText, resolve);
          })
          .finally(() => {
            isCopying.value = false;
          });
      } else {
        fallbackCopy(text, successText, failText, resolve);
        isCopying.value = false;
      }
      // #endif
    });
  };

  // H5 降级方案
  const fallbackCopy = (text, successText, failText, resolve) => {
    const textarea = document.createElement('textarea');
    textarea.value = text;
    textarea.style.position = 'fixed';
    textarea.style.opacity = '0';
    document.body.appendChild(textarea);
    textarea.select();
    try {
      const successful = document.execCommand('copy');
      uni.showToast({
        title: successful ? successText : failText,
        icon: successful ? 'success' : 'none',
      });
      resolve(successful);
    } catch (err) {
      uni.showToast({ title: failText, icon: 'none' });
      resolve(false);
    }
    document.body.removeChild(textarea);
  };

  return {
    copyText,
    isCopying,
  };
}