js实现复制文本图片等功能

实现右击复制页面渲染好的html标签内容,网上看了很多文章都不适用,感觉有些乱七八糟的看不懂,有些文章已经过时了,我本来也是想去用这种方法的:document.execCommand(),但已经废弃了,我还要兼容客户端的,不过这个复制文本不管是剪贴还是复制都差不多类似,所以就灵活运用场景了。
目前业务需求是仅支持文本和图片的复制:所以我真对这两个做了重点的笔记,如果需要其他类型的内容支持,可以参考:MIME类型列表(就是文本类型,别被名词劝退了)

  1. 第一种:navigator.clipboard:
    处于chrome的安全机制,仅支持localhost端口或https的路径
	const copyHandler = async () => {
        try {
          /**
           * 复制文字
           */
          await navigator.clipboard.write([
            new ClipboardItem({
              'text/plain': new Blob(['text align font size'], { type: 'text/plain' })
            })
          ]);
    
          const imgURL = 'http://www.deathghost.cn/public/images/touch-icon-120.png';
          const data = await fetch(imgURL);
          const blob = await data.blob();
          /**
           * 复制图片
           */
          await navigator.clipboard.write([
            new ClipboardItem({
              [blob.type]: blob
            })
          ]);
          const html = '<div>'+
            `<img src='${imgURL}' width="100" />`+
            `<p>${imgURL}</p>`+
          '</div>';
          
          /**
           * 复制html
           */
          await navigator.clipboard.write([
            new ClipboardItem({
              'text/html': new Blob([html], { type: 'text/html' })
            })
          ]);
        } catch(err: any) {
          console.error(err.name, err.message);
        }
  }
  1. 第二种:document.execCommand(‘copy’)
 const target: any = document.createElement('div');
    target.id = 'tempTarget';
    target.style.opacity = '0';
    target.innerHTML = `<div>\
    22222222222222222222222\
    <i style="display:inline-block" cosmo-type="cosmo-img" contentEditable="false"><img contentEditable="false" style="width: 200px;height: 100px;object-fit:cover" src='${audioIcon}'/></i>\
    </div>`;
    document.body.appendChild(target);
    try {
      const range = document.createRange();
      const sel: any = window.getSelection()
      range.selectNode(target);
      // 注意:removeAllRanges必须放在addRange之前,
      // 否则虽然会打印复制成功,但并未复制上内容
      sel.removeAllRanges();
      sel.addRange(range);
      document.execCommand('copy');
      console.log('复制成功')
    } catch (e) {
      console.log('复制失败')
    }
    target.parentElement.removeChild(target);

3.使用实例:

const copyHandler = async () => {
    console.log(_settingsMsg.chatRss, rightInfo, '===----');
    console.log(dealWithDom(_settingsMsg.chatRss, rightInfo), '=====000000000000  rightInfo');
    // 复制 参考:https://developer.mozilla.org/zh-CN/docs/Web/API/ClipboardItem
    // 复制示例模板:new Blob(['copyStatus! 标签'])
    await navigator.clipboard?.write([
      new ClipboardItem({
        'text/plain': new Blob([dealWithDom(_settingsMsg.chatRss, rightInfo)], {
          type: 'text/plain',
        }),
      }),
    ]);
  };



/**
 * 复制和重新编辑、草稿等公用方法
 * @param baseUrl: 后端返回域名
 * list: 就是当前一条的聊天记录信息
 * id?: 草稿中的返回id
 * url?: 草稿中是base64的会用本地的域名
 */
export const dealWithDom = (baseUrl: string, list: { message: any[] }, id?: string, url = '') => {
  // id存在
  let num = 1;
  // 要复制数据的枚举
  const imageDomFun = (item: { path: string; content: string }) => {
    const isBase64 = (item.path || item.content).includes(';base64');
    const str = `<img cosmo-type="${
      isBase64 ? 'cosmo-img' : 'cosmo-upload-img'
    }" style="width: 200px;height: 100px;object-fit:cover" src="${
      (isBase64 ? '' : baseUrl) + (item.path || item.content)
    }"/>`;
    num++;
    return str;
  };

  const setContextEnum = {
    image: imageDomFun,
    'upload-image': imageDomFun,
    text: (item: { content: string }) => {
      return `${item.content}`;
    },
    emo: (item: { content: string }) => {
      const newItem = emoDefaultList.find((element) => `[${element.status}]` === item.content);
      return newItem
        ? `<img src="${newItem.path}" alt="${newItem.status}" cosmo-type="cosmo-emo" />`
        : '';
    },
    at: (item: { content: string; userId: string }) =>
      `<input type="button" id="${num}" disabled="true" class="atlist" value="${item.content} " cosmo-type="cosmo-@" userid="${item.userId}" style="font-style: normal; color: rgb(20, 135, 251); user-select: none;">`,
  };

  // 将循环中的得到的各个类型标签都赋值给writeSpan
  let writeSpan = '';
  // 判断message是否为数组并且数组长度大于0
  if (list?.message && list.message.length) {
    // 循环处理类型获取所对应的数据
    list.message.forEach((ele: { type: string; content: string }) => {
      if (setContextEnum[ele.type]) {
        writeSpan += setContextEnum[ele.type](ele);
      } else {
        writeSpan += ele.content;
      }
    });
  }
  return writeSpan;
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值