该组件是一个基于 Vue3 + TypeScript 开发的轻量化工具组件,核心功能为输入链接生成对应二维码,并提供二维码预览、链接复制、二维码下载等一站式操作,适用于会议分享、资源分发等需要快速将链接转化为可扫描形式的场景。

一、核心功能

1. 链接输入与实时响应

  • 提供输入框支持自定义链接输入,默认填充示例链接(https://example.com/share?room=123456&featureCodes=stream1,stream2),方便用户快速体验。
  • 输入过程中触发防抖机制(延迟 500ms),避免频繁生成二维码导致性能消耗,输入完成后自动更新二维码(也可手动点击生成按钮触发)。
  • 输入为空时给出友好警告提示,防止无效操作。

2. 二维码生成与预览

  • 基于 qrcode 库结合 Canvas 实现二维码生成,支持配置二维码尺寸(200x200px)、边距(2px)、容错级别(中等 M 级,兼顾识别率和体积)、颜色(黑色前景 + 白色背景,保证高对比度易扫描)。
  • 生成成功后实时在页面展示二维码预览图,生成失败(如 Canvas 初始化异常、链接无效)给出明确错误提示。
  • 支持链接动态更新:修改输入框链接后,重新生成的二维码会实时替换预览图。

3. 链接复制功能

  • 点击「复制链接」按钮可将当前输入框中的链接复制到系统剪贴板。
  • 复制成功 / 失败均有对应反馈提示,未输入有效链接时按钮禁用,防止误操作。
  • 兼容主流浏览器的剪贴板 API,若浏览器不支持则提示手动复制。

4. 二维码下载功能

  • 点击「下载二维码」按钮可将生成的二维码以 PNG 格式下载到本地,文件名为「分享二维码_时间戳.png」(时间戳确保文件名唯一)。
  • 下载前自动校验二维码是否已生成,未生成时按钮禁用并给出警告提示。
  • 下载完成后自动清理 DOM 临时元素和内存中的 URL 对象,避免内存泄漏。

二、技术特性

  1. 性能优化:通过防抖机制减少输入时的重复生成操作,Canvas 生成后复用元素,避免频繁创建销毁。
  2. 兼容性:基于标准 Canvas API 和剪贴板 API 开发,兼容 Chrome、Firefox、Edge、Safari 等主流浏览器。
  3. 用户体验:操作流程简洁(输入 → 生成 → 预览 / 复制 / 下载),所有关键操作均有反馈提示,按钮状态随场景动态禁用 / 启用。
  4. 资源清理:组件卸载时自动释放二维码图片 URL 内存、取消防抖定时器,避免内存泄漏。

三、使用场景

  • 会议分享:将会议房间链接生成二维码,参会者扫码即可快速加入。
  • 资源分发:将文件下载链接、网页地址转化为二维码,方便线下传播。
  • 系统集成:可嵌入管理后台、会议系统等场景,提供链接快速转化工具。

四、必装依赖(npm 安装清单)

组件运行依赖以下 npm 包,需提前安装:

依赖包名版本要求作用说明
vue^3.2.0+Vue3 核心框架(组件基于 Vue3 语法开发)
typescript^4.5.0+类型校验,确保代码类型安全
qrcode^1.5.1+核心二维码生成库,支持 Canvas 绘制
lodash-es^4.17.0+提供防抖函数(优化输入时的性能)
element-plus^2.0.0+UI 组件库(输入框、按钮、消息提示等)
@types/lodash-es^4.17.0+lodash-es 的 TypeScript 类型声明文件
@types/qrcode^1.5.0+qrcode 库的 TypeScript 类型声明文件

安装命令(一键执行)

bash

运行

npm install vue@^3.2.0 typescript@^4.5.0 qrcode@^1.5.1 lodash-es@^4.17.0 element-plus@^2.0.0 @types/lodash-es@^4.17.0 @types/qrcode@^1.5.0 --save

补充说明

  • 若项目已全局引入 Vue3、TypeScript 或 Element Plus,可跳过对应包的安装(确保版本兼容)。
  • 类型声明文件(@types/xxx)仅用于 TypeScript 项目,纯 JavaScript 项目可省略,但建议保留以获得更好的开发体验。
  • 安装完成后,若 Element Plus 未全局注册,需在组件内单独引入样式(在 <script setup> 开头添加):

    typescript

    运行

    import 'element-plus/dist/index.css'

示例图

代码如下:

<template>
  <div class="qrcode-share-demo">
    <h3>链接生成二维码示例</h3>

    <!-- 链接输入区 -->
    <el-input
      v-model="shareLink"
      placeholder="请输入需要生成二维码的链接"
      class="link-input"
      @input="debounceGenerateQrcode"
    />

    <!-- 功能按钮区 -->
    <div class="btn-group">
      <el-button type="primary" @click="generateQrcode">生成二维码</el-button>
      <el-button type="success" @click="copyLink" :disabled="!qrcodeSrc"
        >复制链接</el-button
      >
      <el-button type="info" @click="downloadQrCode" :disabled="!qrcodeSrc"
        >下载二维码</el-button
      >
    </div>

    <!-- 二维码预览区 -->
    <div class="qrcode-preview" v-if="qrcodeSrc">
      <h4>二维码预览</h4>
      <img :src="qrcodeSrc" alt="分享二维码" class="qrcode-img" />
    </div>

    <!-- 用于生成二维码的Canvas(隐藏) -->
    <canvas ref="qrcodeCanvas" class="qrcode-canvas"></canvas>
  </div>
</template>

<script setup lang="ts">
import { ref, onUnmounted, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import QRCode from 'qrcode' // 改用qrcode库
import { debounce } from 'lodash-es'

// 核心状态
const shareLink = ref<string>(
  'https://example.com/share?room=123456&featureCodes=stream1,stream2',
)
const qrcodeSrc = ref<string>('') // 二维码图片URL
const qrcodeCanvas = ref<HTMLCanvasElement | null>(null) // Canvas元素

// 防抖生成二维码(输入延迟500ms执行)
const debounceGenerateQrcode = debounce(generateQrcode, 500)

/**
 * 生成二维码(核心修复:使用qrcode库直接操作Canvas)
 */
async function generateQrcode() {
  const link = shareLink.value.trim()
  if (!link) {
    ElMessage.warning('请输入有效的链接')
    qrcodeSrc.value = ''
    return
  }

  if (!qrcodeCanvas.value) {
    ElMessage.error('Canvas元素初始化失败')
    return
  }

  try {
    // 清除Canvas原有内容
    const ctx = qrcodeCanvas.value.getContext('2d')
    if (ctx) {
      ctx.clearRect(0, 0, qrcodeCanvas.value.width, qrcodeCanvas.value.height)
    }

    // 生成二维码到Canvas
    await QRCode.toCanvas(qrcodeCanvas.value, link, {
      width: 200, // 二维码尺寸
      margin: 2, // 边距
      errorCorrectionLevel: 'M', // 容错级别
      color: {
        dark: '#000000', // 二维码颜色
        light: '#ffffff', // 背景色
      },
    })

    // 将Canvas转换为图片URL(修复toDataURL报错问题)
    qrcodeSrc.value = qrcodeCanvas.value.toDataURL('image/png', 1.0)
    ElMessage.success('二维码生成成功')
  } catch (err) {
    console.error('生成二维码失败:', err)
    ElMessage.error('生成二维码失败,请重试')
  }
}

/**
 * 复制链接到剪贴板
 */
function copyLink() {
  const link = shareLink.value.trim()
  if (!link) {
    ElMessage.warning('无有效链接可复制')
    return
  }

  navigator.clipboard
    .writeText(link)
    .then(() => ElMessage.success('链接复制成功'))
    .catch(() => ElMessage.error('复制失败,请手动复制'))
}

/**
 * 下载二维码图片
 */
function downloadQrCode() {
  if (!qrcodeSrc.value) {
    ElMessage.warning('暂无二维码可下载')
    return
  }

  const a = document.createElement('a')
  a.href = qrcodeSrc.value
  const fileName = `分享二维码_${new Date().getTime()}.png`
  a.download = fileName
  document.body.appendChild(a)
  a.click()
  setTimeout(() => {
    document.body.removeChild(a)
    URL.revokeObjectURL(qrcodeSrc.value)
  }, 100)
  ElMessage.success('二维码下载成功')
}

// 组件卸载时清理资源
onUnmounted(() => {
  if (qrcodeSrc.value) {
    URL.revokeObjectURL(qrcodeSrc.value)
  }
  debounceGenerateQrcode.cancel()
})

// 初始化生成默认二维码
onMounted(() => {
  // 确保Canvas元素已加载
  setTimeout(generateQrcode, 100)
})
</script>

<style scoped>
.qrcode-share-demo {
  max-width: 500px;
  margin: 20px auto;
  padding: 20px;
  border: 1px solid #eee;
  border-radius: 8px;
}

.link-input {
  margin-bottom: 16px;
}

.btn-group {
  margin-bottom: 20px;
  display: flex;
  gap: 10px;
}

.qrcode-preview {
  text-align: center;
}

.qrcode-img {
  width: 200px;
  height: 200px;
  border: 1px solid #eee;
  padding: 10px;
  border-radius: 4px;
}

/* 隐藏用于生成二维码的Canvas(仅后台生成用) */
.qrcode-canvas {
  display: none;
  width: 200px;
  height: 200px;
}

h3 {
  text-align: center;
  margin-bottom: 20px;
}
</style>

更多推荐