react —— 复制定制化带有标题的二维码

1. 生成二维码直接借助qrcode这个npm库即可生成二维码,但接到的需求要求是在鼠标点击的附近展示出二维码,点击弹窗里面的复制按钮即可赋值带标题的二维码图片到剪切板,实现效果如下图:

 

主要实现要点:

1.利用qrcode 生成二维码;

2.蚂蚁金服组件气泡弹窗Popover,弹出点击位置弹窗;

3. 点击复制时,利用domimage这个npm包,直接将dom布局转化成图片;

4. base64图片转成blob对象,创建剪切板对象;

编写如下组件

import React, { useRef, useState, Fragment } from 'react';
import { Button, message, Popover } from 'antd';
import styles from './index.less';
import { base64ToBlob, copyToClipboard } from '@/utils/utils';
import QRcode from 'qrcode';
import domtoimage from 'dom-to-image';

interface dataProp {
  selectPaperTitle: string;
  url: string;
  menu: string;
}

const QrcodeMenu: React.FC<dataProp> = (props) => {
  const { selectPaperTitle, url, menu } = props;
  const [qrcodeUrl, setQrCodeUrl] = useState<string>(url);
  const imgDom = useRef<any>(null);
  const content = (
    <Fragment>
      <div ref={imgDom} className={styles.container}>
        <div className={styles.title}>{selectPaperTitle}</div>
        <img className={styles.img} src={qrcodeUrl} alt="链接二维码" />
      </div>
      <div className={styles.btncontainer}>
        <Button
          className={styles.btn}
          type="primary"
          onClick={() => {
            try {
              domtoimage.toPng(imgDom?.current).then((codeurl: string) => {
                copyToClipboard(base64ToBlob(codeurl));
                message.success('二维码复制成功');
              });
            } catch {
              message.error('二维码复制失败');
            }
          }}
        >
          复制
        </Button>
      </div>
    </Fragment>
  );
  return (
    <Popover
      onVisibleChange={async (visible: any) => {
        if (visible) {
          QRcode.toDataURL(url, { margin: 0, width: 160 }).then((res) => setQrCodeUrl(res));
        }
      }}
      autoAdjustOverflow={false}
      overlayClassName={styles.menu}
      placement="leftBottom"
      content={content}
      trigger={['hover']}
    >
      {menu}
    </Popover>
  );
};
export default QrcodeMenu;

2.复制到剪切板的功能实现:

utils.js文件

// 复制png图片到粘贴板
export function copyToClipboard(blob: Blob | null) {
  if (blob) {
    const clipboardItem: any = new ClipboardItem({ [blob.type]: blob });
    navigator?.clipboard?.write([clipboardItem]);
  }
}

/**
 * base64转blob
 */
export function base64ToBlob(urlData: string, type?: string) {
  const arr = urlData.split(',');
  const mime = arr[0]?.match(/:(.*?);/)?.[1] || type;
  // 去掉url的头,并转化为byte
  const bytes = window.atob(arr[1]);
  // 处理异常,将ascii码小于0的转换为大于0
  const ab = new ArrayBuffer(bytes.length);
  // 生成视图(直接针对内存):8位无符号整数,长度1个字节
  const ia = new Uint8Array(ab);
  for (let i = 0; i < bytes.length; i += 1) {
    ia[i] = bytes.charCodeAt(i);
  }
  return new Blob([ab], {
    type: mime,
  });
}

3. index.less

.container {
  padding: 16px;
  background: #fff;
  .title {
    margin-bottom: 16px;
    color: rgba(0, 0, 0, 0.85);
    font-weight: 400;
    font-size: 12px;
    font-family: PingFangSC-Regular, PingFang SC;
    line-height: 20px;
  }
  .img {
    display: block;
    margin: 0 auto;
  }
  .btn {
    display: block;
    margin: 0 auto;
  }
}
.btncontainer {
  text-align: center;
}
.menu {
  width: 240px;
  padding-right: 0;
  background: #fff;
  border-radius: 2px;
  box-shadow: 0 9px 28px 8px rgba(0, 0, 0, 0.05), 0 6px 16px 0 rgba(0, 0, 0, 0.08),
    0 3px 6px -4px rgba(0, 0, 0, 0.12);
  :global {
    .ant-popover-arrow {
      display: none;
    }
    .ant-popover-inner-content {
      height: auto;
      padding: 0 0 16px;
    }
  }
}

4. 引入方式:

<QrcodeMenu selectPaperTitle={r.title} menu={'二维码'} url={r.url} />

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值