更新记录

1.0.0(2026-03-18)

--


平台兼容性

uni-app(5.0)

Vue2 Vue2插件版本 Vue3 Vue3插件版本 Chrome Chrome插件版本 Safari Safari插件版本 app-vue app-vue插件版本 app-nvue app-nvue插件版本 Android Android插件版本 iOS iOS插件版本 鸿蒙
1.0.0 1.0.0 1.0.0 1.0.0 1.0.0 1.0.0 5.0 1.0.0 12 1.0.0 -
微信小程序 微信小程序插件版本 支付宝小程序 支付宝小程序插件版本 抖音小程序 抖音小程序插件版本 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
1.0.0 1.0.0 1.0.0 - - - - - - - - -

uni-app x(5.03)

Chrome Safari Android iOS 鸿蒙 微信小程序
- - - - - -

ry-qrcode

一款功能强大的 UniApp 二维码生成组件,支持自定义颜色、渐变色、圆角、Logo 等特性,兼容多端。

功能特性

  • 纯 Canvas 绘制,无第三方依赖
  • 支持生成标准二维码,可被微信、支付宝等主流 App 识别
  • 支持自定义颜色(单色/渐变色)
  • 支持随机颜色和随机样式
  • 支持自定义圆角码点
  • 支持添加 Logo(自动提升容错级别)
  • 支持导出图片和 Base64
  • 支持多种容错级别(L/M/Q/H)
  • 全端兼容:H5、微信小程序、支付宝小程序、App 等

安装

方式一:HBuilderX 插件市场导入

在 HBuilderX 中,点击菜单 工具 -> 插件安装 -> 前往插件市场安装,搜索 ry-qrcode 导入。

方式二:手动安装

ry-qrcode 文件夹复制到项目的 uni_modules 目录下。

基础用法

<template>
  <view>
    <ry-qrcode
      ref="qrcodeRef"
      text="https://uniapp.dcloud.net.cn"
      :width="200"
      :height="200"
    />
  </view>
</template>

<script>
export default {
  methods: {
    // 保存二维码图片
    async save() {
      const filePath = await this.$refs.qrcodeRef.save()
      console.log('图片路径:', filePath)
    }
  }
}
</script>

Props 属性

属性名 类型 默认值 说明
text String '' 必填,二维码内容(文本或链接)
width Number 260 二维码宽度(单位:px)
height Number 260 二维码高度(单位:px)
bgColor String '#ffffff' 背景颜色
level String 'M' 容错级别:L(7%)、M(15%)、Q(25%)、H(30%)
radius Number 6 码点圆角半径(单位:px)
logo String '' Logo 图片路径(支持本地路径和网络路径)
logoSize Number 60 Logo 尺寸(单位:px),实际会限制为二维码宽度的 20%
logoRadius Number 8 Logo 圆角半径(单位:px)
autoRandomColor Boolean true 是否自动随机颜色
color String '' 自定义颜色(单色模式)
colorStart String '' 渐变起始色
colorEnd String '' 渐变结束色

颜色优先级

  1. 如果设置了 colorcolorStartcolorEnd,则使用自定义颜色
  2. 如果 autoRandomColortrue 且未设置自定义颜色,则自动随机颜色
  3. 单色模式:只设置 color
  4. 渐变模式:设置 colorStartcolorEnd

Events 事件

事件名 参数 说明
ready - 二维码初始化完成时触发
colorChange colorInfo 颜色变化时触发

colorChange 事件参数

{
  start: '#1677FF',   // 渐变起始色
  end: '#722ED1',     // 渐变结束色
  primary: '#1677FF'  // 主色调
}

Methods 方法

通过 ref 调用组件方法:

this.$refs.qrcodeRef.methodName()
方法名 参数 返回值 说明
save() - Promise\<string> 保存二维码为临时文件,返回文件路径
getBase64() - Promise\<string> 获取二维码 Base64 数据
refresh() - Promise 手动刷新二维码
refreshColor() - Promise 刷新颜色(随机模式下随机新颜色)
randomStyle() - Promise 随机更换样式(颜色+圆角)
setColor(color, colorEnd?) color: 主色, colorEnd: 结束色 Promise 设置自定义颜色
getColors() - Object 获取当前颜色信息
getRadius() - Number 获取当前圆角值

使用示例

1. 基础二维码

<ry-qrcode text="Hello World" />

2. 自定义尺寸和颜色

<ry-qrcode
  text="https://example.com"
  :width="300"
  :height="300"
  color="#1677FF"
  :autoRandomColor="false"
/>

3. 渐变色二维码

<ry-qrcode
  text="https://example.com"
  colorStart="#1677FF"
  colorEnd="#722ED1"
  :autoRandomColor="false"
/>

4. 带 Logo 的二维码

<ry-qrcode
  text="https://example.com"
  logo="/static/logo.png"
  :logoSize="50"
  :logoRadius="8"
/>

注意:添加 Logo 时,组件会自动使用 H 级别容错(30%),以确保二维码可被正常识别。

5. 自定义圆角

<!-- 方形码点 -->
<ry-qrcode
  text="https://example.com"
  :radius="0"
/>

<!-- 圆形码点 -->
<ry-qrcode
  text="https://example.com"
  :radius="10"
/>

6. 监听就绪事件

<template>
  <ry-qrcode
    ref="qrcodeRef"
    text="https://example.com"
    @ready="onQrcodeReady"
  />
</template>

<script>
export default {
  methods: {
    onQrcodeReady() {
      console.log('二维码已就绪,可以安全调用方法了')
      // 此时可以安全地调用 save()、getBase64() 等方法
    }
  }
}
</script>

7. 保存图片到相册

async saveToAlbum() {
  try {
    const filePath = await this.$refs.qrcodeRef.save()

    // #ifdef H5
    uni.showModal({
      title: '提示',
      content: 'H5端请长按图片保存',
      showCancel: false
    })
    // #endif

    // #ifndef H5
    uni.saveImageToPhotosAlbum({
      filePath: filePath,
      success: () => {
        uni.showToast({ title: '保存成功', icon: 'success' })
      },
      fail: (err) => {
        console.error('保存失败', err)
        uni.showToast({ title: '保存失败', icon: 'none' })
      }
    })
    // #endif
  } catch (e) {
    console.error('获取图片失败', e)
  }
}

8. 获取 Base64 数据

async getBase64Data() {
  try {
    const base64 = await this.$refs.qrcodeRef.getBase64()
    console.log('Base64 数据:', base64)
    // 可用于上传到服务器或其他用途
  } catch (e) {
    console.error('获取失败', e)
  }
}

9. 随机样式

// 随机更换颜色
this.$refs.qrcodeRef.refreshColor()

// 随机更换样式(颜色+圆角)
this.$refs.qrcodeRef.randomStyle()

10. 动态设置颜色

// 设置单色
this.$refs.qrcodeRef.setColor('#FF5500')

// 设置渐变色
this.$refs.qrcodeRef.setColor('#1677FF', '#722ED1')

11. 获取当前颜色(可用于同步页面背景)

<template>
  <view :style="{ background: pageBg }">
    <ry-qrcode
      ref="qrcodeRef"
      text="https://example.com"
      @colorChange="onColorChange"
    />
  </view>
</template>

<script>
export default {
  data() {
    return {
      pageBg: '#ffffff'
    }
  },
  methods: {
    onColorChange(colorInfo) {
      // 使用二维码颜色作为页面背景
      this.pageBg = `linear-gradient(135deg, ${colorInfo.start}, ${colorInfo.end})`
    }
  }
}
</script>

完整示例

<template>
  <view class="container" :style="{ background: pageBgStyle }">
    <view class="header">
      <text class="title" :style="{ color: titleColor }">二维码生成器</text>
    </view>

    <!-- 二维码展示区域 -->
    <view class="qrcode-wrapper">
      <ry-qrcode
        ref="qrcodeRef"
        :text="qrText"
        :width="qrSize"
        :height="qrSize"
        :level="errorLevel"
        :radius="cornerRadius"
        :logo="logoUrl"
        :logoSize="logoSize"
        :autoRandomColor="autoColor"
        :color="customColor"
        :colorStart="gradientStart"
        :colorEnd="gradientEnd"
        @colorChange="onColorChange"
        @ready="onQrcodeReady"
      />
    </view>

    <!-- 输入区域 -->
    <view class="input-section">
      <input v-model="qrText" placeholder="请输入文本或链接" />
      <input v-model="logoUrl" placeholder="Logo图片地址(可选)" />
    </view>

    <!-- 操作按钮 -->
    <view class="action-section">
      <button @click="randomStyle">随机样式</button>
      <button @click="refreshColor">换颜色</button>
      <button @click="saveQrcode">保存图片</button>
      <button @click="getBase64Data">获取Base64</button>
    </view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      qrText: 'https://uniapp.dcloud.net.cn',
      qrSize: 220,
      cornerRadius: 6,
      logoUrl: '/static/logo.png',
      logoSize: 50,
      errorLevel: 'H',
      autoColor: true,
      customColor: '',
      gradientStart: '',
      gradientEnd: '',
      pageColorStart: '#1677FF',
      pageColorEnd: '#0056D2',
      isReady: false
    }
  },
  computed: {
    pageBgStyle() {
      return `linear-gradient(180deg, ${this.hexToRgba(this.pageColorStart, 0.15)} 0%, ${this.hexToRgba(this.pageColorEnd, 0.05)} 100%)`
    },
    titleColor() {
      return this.pageColorStart
    }
  },
  methods: {
    onQrcodeReady() {
      this.isReady = true
    },
    onColorChange(colorInfo) {
      this.pageColorStart = colorInfo.start
      this.pageColorEnd = colorInfo.end
    },
    refreshColor() {
      this.$refs.qrcodeRef.refreshColor()
    },
    randomStyle() {
      this.$refs.qrcodeRef.randomStyle()
    },
    async saveQrcode() {
      if (!this.isReady) return
      try {
        const filePath = await this.$refs.qrcodeRef.save()
        // #ifndef H5
        uni.saveImageToPhotosAlbum({
          filePath,
          success: () => uni.showToast({ title: '保存成功', icon: 'success' }),
          fail: () => uni.showToast({ title: '保存失败', icon: 'none' })
        })
        // #endif
        // #ifdef H5
        uni.showModal({ title: '提示', content: 'H5端请长按图片保存', showCancel: false })
        // #endif
      } catch (e) {
        uni.showToast({ title: '操作失败', icon: 'none' })
      }
    },
    async getBase64Data() {
      if (!this.isReady) return
      try {
        const base64 = await this.$refs.qrcodeRef.getBase64()
        console.log('Base64:', base64.substring(0, 100) + '...')
        uni.showToast({ title: '获取成功', icon: 'success' })
      } catch (e) {
        uni.showToast({ title: '获取失败', icon: 'none' })
      }
    },
    hexToRgba(hex, alpha) {
      if (!hex) return `rgba(0,0,0,${alpha})`
      hex = hex.replace('#', '')
      if (hex.length === 3) {
        hex = hex.split('').map(c => c + c).join('')
      }
      const r = parseInt(hex.substring(0, 2), 16)
      const g = parseInt(hex.substring(2, 4), 16)
      const b = parseInt(hex.substring(4, 6), 16)
      return `rgba(${r},${g},${b},${alpha})`
    }
  }
}
</script>

平台兼容性

平台 支持情况 备注
H5 完全支持
微信小程序 完全支持
支付宝小程序 完全支持
百度小程序 完全支持
抖音小程序 完全支持
QQ 小程序 完全支持
App (iOS) 完全支持
App (Android) 完全支持

注意事项

1. Logo 相关

  • Logo 尺寸会自动限制为二维码宽度的 20%,以确保识别率
  • 添加 Logo 时自动使用 H 级别容错
  • Logo 区域不会绘制二维码数据点,确保不影响识别
  • H5 端使用网络图片作为 Logo 时,需确保图片支持跨域

2. 保存图片

  • H5 端无法直接保存到相册,需引导用户长按保存
  • 小程序端需要用户授权相册权限
  • App 端需要在 manifest.json 中配置相册权限

3. 性能优化

  • 组件内部有防并发绘制机制,频繁修改属性不会导致多次重绘
  • 建议在 @ready 事件触发后再调用 save()getBase64() 方法
  • 大尺寸二维码(>500px)可能会有轻微延迟

4. 容错级别说明

级别 容错率 说明
L 7% 低容错,适合无遮挡场景
M 15% 中等容错,默认级别
Q 25% 较高容错
H 30% 最高容错,适合添加 Logo

5. 扫码识别

生成的二维码符合 QR Code 标准,可被以下 App 识别:

  • 微信
  • 支付宝
  • 抖音
  • 系统相机
  • 其他标准二维码扫描器

常见问题

Q: 二维码无法被扫描识别?

A: 请检查以下几点:

  1. 二维码内容是否正确
  2. 如果有 Logo,确保 Logo 不超过二维码的 20%
  3. 颜色对比度是否足够(避免浅色前景+浅色背景)
  4. 尝试使用更高的容错级别

Q: H5 端保存图片失败?

A: H5 端浏览器限制,无法直接保存图片到本地。建议提示用户长按二维码图片保存,或使用 getBase64() 获取数据后上传到服务器生成下载链接。

Q: Logo 图片不显示?

A: 请检查以下几点:

  1. 图片路径是否正确
  2. 网络图片是否支持跨域(H5 端)
  3. 小程序端网络图片需配置合法域名

Q: 如何动态修改二维码内容?

A: 直接修改 text 属性即可,组件会自动重新绘制:

this.qrText = 'https://new-url.com'

Q: 颜色不生效?

A: 如果设置了自定义颜色但不生效,请确保:

  1. autoRandomColor 设置为 false
  2. 颜色格式正确(如 #1677FF

更新日志

v1.0.2

  • 修复多端兼容性问题
  • 优化 canvas 渲染回调机制
  • 添加 width/height/radius 等属性的 watch 监听
  • 添加保存和 Base64 获取的重试机制
  • 优化 Logo 加载使用运行时平台检测

v1.0.1

  • 修复 Logo 遮挡导致无法识别的问题
  • 添加自定义颜色支持(单色/渐变)
  • 添加随机样式功能
  • 添加 ready 事件
  • 添加重试机制提高稳定性

v1.0.0

  • 初始版本发布
  • 支持基础二维码生成
  • 支持圆角、渐变、Logo
  • 支持导出图片和 Base64

License

MIT License

反馈与支持

如有问题或建议,欢迎提交 Issue 或 PR。

隐私、权限声明

1. 本插件需要申请的系统权限列表:

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

暂无用户评论。