首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >js 实现点击触发复制口令到剪贴板,并跳转

js 实现点击触发复制口令到剪贴板,并跳转

作者头像
蓓蕾心晴
发布2026-04-01 07:55:22
发布2026-04-01 07:55:22
1140
举报
文章被收录于专栏:前端小叙前端小叙

vue3 项目,想要使用 js 实现点击触发跳转时,复制口令到剪贴板,注意这里,仅仅是复制到剪贴板。

注意事项:

  • 复制到剪贴板方法必须在用户主动触发手势,click、touchstart、 touchend、keybord 等
  • 触发复制的方法必须在点击后非异步的方法内执行,即必须在用户手势(如 clicktouchstart)事件的同步代码中调用,如果在 setTimeout、promise、事件监听等 内或者后面都会导致执行失败
  • 摇一摇等非用户手势触发的点击这些都属于自动点击,则不会复制成功,会报错:Document is not focused.
代码语言:javascript
复制
/**
 * 复制文本到剪贴板
 * 注意:必须在用户手势(如 click、touchstart)的同步调用链中执行,不能在异步回调中调用!
 * @param {string} text - 要复制的文本
 * @returns {Promise<boolean>} - 是否复制成功
 */
export function copyToClipboard(text) {
  return new Promise((resolve) => {
    // 优先使用现代 Clipboard API
    if (navigator.clipboard && typeof navigator.clipboard.writeText === 'function') {
      navigator.clipboard.writeText(text)
        .then(() => {
          console.log('[copyToClipboard] Clipboard API 复制成功')
          resolve(true)
        })
        .catch((err) => {
          console.warn('[copyToClipboard] Clipboard API 失败:', err.message)
          const success = fallbackCopy(text)
          console.log('[copyToClipboard] 降级方案结果:', success)
          resolve(success)
        })
    } else {
      console.log('[copyToClipboard] Clipboard API 不可用,使用降级方案')
      const success = fallbackCopy(text)
      console.log('[copyToClipboard] 降级方案结果:', success)
      resolve(success)
    }
  })
}

/**
 * 降级复制方案(使用 textarea + execCommand,增强 iOS 兼容性)
 * @param {string} text - 要复制的文本
 * @returns {boolean} - 是否复制成功
 */
function fallbackCopy(text) {
  const textarea = document.createElement('textarea')
  textarea.value = text
  // 关键:设置 contentEditable 为 true,提高 iOS 选中兼容性
  textarea.contentEditable = 'true'
  textarea.style.cssText = `
    position: fixed;
    top: 0;
    left: 0;
    opacity: 0;
    pointer-events: none;
    width: 100px;
    height: 100px;
    z-index: -1;
  `
  document.body.appendChild(textarea)

  // iOS 兼容性处理
  const isIOS = /iPhone|iPad|iPod/i.test(navigator.userAgent)
  let success = false

  try {
    // 聚焦元素(iOS 需要)
    textarea.focus()

    if (isIOS) {
      const range = document.createRange()
      range.selectNodeContents(textarea)
      const selection = window.getSelection()
      selection.removeAllRanges()
      selection.addRange(range)
      textarea.setSelectionRange(0, text.length)
    } else {
      textarea.select()
      textarea.setSelectionRange(0, text.length)
    }

    success = document.execCommand('copy')
    console.log('[fallbackCopy] execCommand 复制结果:', success)
  } catch (err) {
    console.error('[fallbackCopy] execCommand 异常:', err)
    success = false
  } finally {
    document.body.removeChild(textarea)
  }
  return success
}

/**
 * 通过 scheme 打开 APP
 * @param {string} scheme - 完整的 scheme URL
 * @returns {void}
 */
export function openAppByScheme(scheme) {
  const isIOS = /iPhone|iPad|iPod/i.test(navigator.userAgent)

  if (isIOS) {
    // iOS 使用 iframe 方式,避免页面跳转
    const iframe = document.createElement('iframe')
    iframe.style.display = 'none'
    iframe.src = scheme
    document.body.appendChild(iframe)
    setTimeout(() => {
      document.body.removeChild(iframe)
    }, 100)
  } else {
    // Android 直接跳转
    window.location.href = scheme
  }
}

/**
 * 复制口令并打开 APP
 * @param {string} jumpCommand - 口令内容
 * @param {string} schemePrefix - scheme 前缀,默认为抖音极速版
 * @param {object} options - 配置选项
 * @param {number} options.delay - 复制后延迟打开的时间(ms),默认 300ms
 * @returns {Promise<void>}
 */
export async function copyAndOpenApp(jumpCommand, schemePrefix = DEFAULT_SCHEME_PREFIX, options = {}) {
  const { delay = 300 } = options

  if (!jumpCommand) {
    console.warn('[copyAndOpenApp] jumpCommand 为空,跳过复制')
    return
  }

  // 复制口令
  const copied = await copyToClipboard(jumpCommand)

  if (!copied) {
    console.warn('[copyAndOpenApp] 复制失败,但仍尝试打开 APP')
  }

  // 拼接 scheme 并打开 APP
  const scheme = `${schemePrefix}search?keyword=${encodeURIComponent(jumpCommand)}`

  // 延迟打开,确保复制操作完成
  setTimeout(() => {
    openAppByScheme(scheme)
  }, delay)
}

/**
 * 复制口令到剪贴板
 * @param {string} jumpCommand - 口令内容
 */

export async function copyCommand(jumpCommand) {
  if (!jumpCommand) {
    console.warn('[copyCommand] jumpCommand 为空,跳过复制')
    return
  }

  // 复制口令
  const copied = await copyToClipboard(jumpCommand)

  if (!copied) {
    console.warn('[copyCommand] 复制失败,但仍尝试打开 APP')
  }
}

以上方法,如果仅复制口令,则使用  copyCommand,如果还要实现复制口令并打开,则使用 copyAndOpenApp。

常见报错:

  1. NotAllowedError: Failed to execute 'writeText' on 'Clipboard': Write permission denied.在异步函数之后或之内触发复制方法就会报这个错
  2. Document is not focused. 会用户手势触发的点击,执行复制方法就会报这个错
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2026-03-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档