Code前端首页关于Code前端联系我们

Vue3项目里怎么安全、高效、可定制地生成和扫描二维码?踩过的坑全给你整理了

terry 46分钟前 阅读数 14 #Vue

最近接手了一个带订单核销功能的Vue3后台加小程序H5对接项目,核心环节离不开二维码生成和移动端扫描——后台生成核销码,线下门店用H5页面扫,还要支持用户在小程序里生成分享二维码,一开始随便找了个热度最高的插件就上手,结果踩了一堆坑:生成的码加载慢、颜色一调就扫不出来、iOS某些机型H5扫码直接闪退,甚至生成的码还有XSS注入的小风险,折腾了三天两夜,才把功能做稳、做顺,还攒了不少实用技巧,今天就以问答的形式,把这些经验全掏出来,不管你是做电商核销、社交分享还是设备绑定,应该都能用上。

为什么要选专门适配Vue3的二维码插件,而不是用原生JS库直接套?

很多刚接触的朋友会问,不就是生成个二维码吗?网上一堆原生JS库,随便引进来在Vue3的mounted或者setup里调用一下不就行了?别这么想,Vue3的Composition API、响应式系统、TS类型支持这些特性,原生库很难直接用好,适配不好的话,后期维护成本会很高,踩坑概率也更大。

举个例子,原生JS库生成二维码一般会直接操作DOM元素,但Vue3是虚拟DOM驱动的,直接操作DOM不仅不符合框架设计理念,还容易和Vue的更新机制冲突——比如你想根据响应式数据实时改变二维码内容,直接操作DOM可能会导致旧DOM残留,或者内容更新延迟,适配Vue3的插件会自动处理虚拟DOM和真实DOM的同步,把生成逻辑封装成组件或者Composable,用起来就像用element-plus的按钮一样顺手。

再说说TS类型支持,现在稍微正规一点的Vue3项目基本都用TS了,原生JS库要么没有类型声明,要么类型声明不完整,写代码的时候没提示,编译还可能报错,调试起来特别麻烦,专门的Vue3适配插件一般都会有完整的TS类型,编辑器自动补全,类型检查也能帮你提前发现不少低级错误。

市面上主流的Vue3二维码生成插件有哪些?分别适合什么场景?

目前GitHub上Star数比较高、维护也比较活跃的Vue3二维码生成插件主要有三个:vue-qrcode-reader(不对,这个主要是扫描?哦对,扫的放后面说,生成的是qrcode.vue、vue-qrcode-next、vue3-qrcode),这三个插件我在项目里都试过,各有优缺点,得根据自己的需求选。

qrcode.vue

这个是我最早用的,Star数最高,社区也最成熟,它是基于原生的qrcode.js库封装的Vue组件,支持生成SVG和Canvas两种格式的二维码,可定制性很强,基本能满足90%的生成需求——比如调整大小、边距、前景色、背景色、添加中心Logo、支持纠错级别调整,甚至还能自定义二维码的码点样式(圆角、圆点、方形带圆角这些)。

不过qrcode.vue也有个小缺点:它的Logo参数是直接传图片URL的,没有做图片预加载和尺寸自适应,如果你传的Logo比较大或者加载慢,二维码中心可能会出现空白或者Logo变形的情况,需要自己额外写逻辑处理,它默认是用Canvas渲染的,在旧版本的Safari浏览器(比如iOS 12之前的)上可能会有渲染模糊的问题,不过现在这种旧版本的用户已经很少了,基本可以忽略。

这个插件适合大部分场景,尤其是需要高度定制码点样式或者生成静态海报嵌入二维码的项目。

vue-qrcode-next

这个插件是专门为Vue3重构的,不是像qrcode.vue那样兼容Vue2和Vue3的,所以代码更轻量,渲染速度也更快一点,它的核心功能和qrcode.vue差不多,也支持SVG和Canvas渲染、调整参数、添加Logo,但码点样式的定制性稍微弱一点,只有圆角、方形两种,没有圆点或者更复杂的样式。

不过vue-qrcode-next有个很大的优点:它做了图片预加载和尺寸自适应,传Logo的时候不用自己写额外逻辑,中心Logo会自动居中、缩放,不会变形,也不会出现空白,它的TS类型声明更完整、更规范,用起来特别爽。

这个插件适合不需要太复杂码点样式、追求轻量和渲染速度、用TS开发的项目,比如电商订单后台生成简单的核销码,或者小程序H5分享页面生成分享码。

vue3-qrcode

这个插件的定位是“极简、无依赖”——它没有基于任何原生JS库,自己实现了二维码生成算法,所以打包体积特别小,压缩之后只有几KB,几乎不会增加项目的首屏加载时间,不过也因为是自己实现的,可定制性比较差,只支持调整大小、边距、前景色、背景色、纠错级别,不能添加Logo,也不能自定义码点样式。

这个插件适合对打包体积要求极高、只需要生成最基础二维码的项目,比如嵌入到轻量级的营销活动H5页面,或者集成到物联网设备的配置页面。

用qrcode.vue或者vue-qrcode-next生成二维码时,有哪些容易踩的坑?怎么解决?

刚才说了这两个插件适合大部分场景,但我在项目里踩了不少坑,现在给大家列出来,省得你们再走弯路。

iOS某些机型Canvas渲染的二维码扫不出来

这个是我踩的第一个大坑,当时后台生成的核销码,安卓手机不管用什么APP扫都能扫出来,iOS 15及以上的Safari和微信扫也没问题,但iOS 14.8及以下的微信扫不出来,一开始以为是微信版本的问题,后来换了iOS 14.8的Safari扫还是不行,折腾了好久才找到原因。

后来查了相关资料才知道,旧版本的Safari对Canvas的抗锯齿处理有问题,当二维码的尺寸比较小(比如小于150px),或者码点是圆角的时候,抗锯齿会让码点之间的边界变得模糊,扫码设备识别不出来。

解决方法也很简单,有两个:

  1. 优先用SVG渲染,SVG是矢量图,不管尺寸多大都不会模糊,也不会有抗锯齿的问题,兼容性也很好,现在几乎所有的浏览器都支持SVG,两个插件切换渲染格式都很简单,只要把render-type属性改成“svg”就行。
  2. 如果必须用Canvas渲染,就把二维码的尺寸设置得大一点,至少180px,同时把码点样式改成默认的方形,不要用圆角或者圆点。

添加Logo之后二维码扫不出来

这个也是很多人会遇到的问题,一开始我以为是Logo太大了,把Logo缩到了二维码的1/5还是扫不出来,后来仔细看了纠错级别的说明才明白。

二维码有四个纠错级别:L(7%)、M(15%)、Q(25%)、H(30%),级别越高,二维码能容忍的损坏或者遮挡面积越大,如果添加Logo,至少要把纠错级别设置成Q或者H,不然Logo遮挡的面积超过了纠错级别,扫码设备就识别不出来了。

Logo最好是方形的,背景色和二维码的背景色一致,不然Logo周围的空白也会被当成遮挡,影响识别率,如果Logo不是方形的,可以在PS或者Figma里把它裁剪成方形,或者用CSS给Logo容器加个背景色。

还有一个小技巧:如果两个插件都有Logo圆角的参数,最好把Logo的圆角稍微调小一点,或者直接去掉,因为Logo的圆角也会被当成小面积的遮挡,影响识别率。

根据响应式数据实时更新二维码时,旧二维码残留

这个就是我刚才说的,原生JS库直接操作DOM容易出现的问题,适配Vue3的插件虽然会自动处理,但如果参数设置不对,还是会出现旧二维码残留的情况。

比如qrcode.vue,如果只改变了二维码的内容,没有改变key属性,Vue可能会复用旧的DOM元素,导致旧二维码的Canvas/SVG没有被完全清除,新的二维码覆盖在旧的上面,看起来乱糟糟的,扫码设备也可能扫到旧的内容。

解决方法也很简单,给组件加一个动态的key属性,key的值可以绑定到二维码的内容上,或者每次更新内容的时候生成一个随机数,这样Vue就会销毁旧的DOM元素,重新创建新的,不会有残留。

Vue3 SSR项目中生成二维码报错

如果你的项目是用Nuxt3或者VitePress做的SSR项目,直接用这两个插件可能会报错,因为它们在mounted之前就会尝试操作DOM,而SSR项目在服务端渲染的时候是没有DOM的。

解决方法有两个:

  1. 用Vue的组件把二维码组件包裹起来,这样二维码组件只会在客户端渲染,不会在服务端执行。
  2. 如果是用Nuxt3的话,可以把插件注册成客户端插件,或者在组件里用useClientOnly钩子判断当前是不是客户端,是客户端再渲染二维码组件。

怎么在Vue3项目里实现扫码功能?有没有好用的适配Vue3的插件?

刚才说了生成的问题,现在说说扫描的问题,市面上适配Vue3的扫码插件主要有两个:vue-qrcode-reader和vue3-qr-reader。

vue-qrcode-reader

这个插件是目前Star数最高、维护也最活跃的Vue3扫码插件,我在项目里用的就是这个,它支持扫描二维码和条形码,兼容性很好,现在几乎所有的主流浏览器(Chrome、Firefox、Safari、微信内置浏览器)都支持,iOS 11及以上的Safari和微信扫起来特别流畅,安卓手机也没问题。

它的核心功能包括:自动打开摄像头、实时预览摄像头画面、自动识别二维码/条形码、支持切换前后摄像头、支持设置扫描区域、支持自定义UI,甚至还能支持从相册里选择图片识别。

vue3-qr-reader

这个插件是专门为Vue3重构的,代码更轻量,打包体积更小,但功能比vue-qrcode-reader稍微弱一点,不支持扫描条形码,也不支持自定义扫描区域的边框样式,只有默认的绿色边框。

这个插件适合对打包体积要求极高、只需要扫描二维码、不需要自定义UI的项目。

用vue-qrcode-reader实现扫码功能时,有哪些容易踩的坑?怎么解决?

扫码功能的坑比生成的更多,主要是因为摄像头权限、浏览器兼容性、性能这些问题,我在项目里踩了好几个,现在给大家列出来。

iOS微信H5页面扫码闪退

这个是我踩的最大的一个坑,当时项目上线前测试,iOS 14.8及以下的微信H5页面一打开扫码组件就直接闪退,iOS 15及以上的没问题,安卓手机也没问题,折腾了两天才找到原因。

后来查了相关资料才知道,旧版本的微信内置浏览器对Vue的Teleport组件有问题,而vue-qrcode-reader默认是用Teleport组件把扫描区域的UI挂载到body上的,所以就会导致闪退。

解决方法也很简单,vue-qrcode-reader提供了一个no-teleport属性,只要把这个属性设置成true,扫描区域的UI就会挂载到当前组件的父元素上,不会用Teleport组件,也就不会闪退了,不过设置成true之后,扫描区域的UI可能会被父元素的overflow属性遮挡,所以需要把父元素的overflow属性设置成visible,或者给扫描区域的UI加个z-index属性,让它浮在最上面。

iOS Safari扫码权限获取失败

这个也是很多人会遇到的问题,iOS Safari对摄像头权限的要求特别严格,必须满足两个条件才能获取:

  1. 页面必须是HTTPS协议的,HTTP协议的页面(除了localhost)不能获取摄像头权限。
  2. 获取摄像头权限的代码必须在用户的交互事件(比如点击按钮、触摸屏幕)之后执行,不能在页面加载完成之后自动获取。

很多朋友会在页面的mounted或者onMounted钩子函数里自动打开摄像头,这样iOS Safari就会直接拒绝权限,不会弹出权限请求框。

解决方法也很简单:

  1. 把项目部署到HTTPS服务器上,本地开发的话用localhost或者127.0.0.1没问题,或者用Vite的https配置开启本地HTTPS服务器。
  2. 不要在页面加载完成之后自动打开摄像头,而是加一个“点击扫码”的按钮,在按钮的点击事件里执行打开摄像头的代码。

实时预览画面卡顿,或者识别率低

这个主要是因为性能和参数设置的问题,vue-qrcode-reader默认的分辨率比较高,每秒扫描的次数也比较多,会消耗大量的CPU和内存,导致实时预览画面卡顿,尤其是在一些配置比较低的手机上。

解决方法也很简单,调整两个参数:

  1. 把resolution属性设置得低一点,比如640x480或者480x360,分辨率越低,消耗的CPU和内存越少,实时预览画面越流畅,但识别率也会稍微降一点,需要平衡一下。
  2. 把scan-delay属性设置得高一点,比如500或者1000,scan-delay是两次扫描之间的间隔时间,单位是毫秒,间隔时间越长,消耗的CPU和内存越少,但识别速度也会稍微降一点。

提高识别率还有几个小技巧:

  1. 把扫描区域设置得小一点,刚好框住二维码就行,不要占满整个屏幕,这样扫描设备只需要处理扫描区域内的画面,识别速度和识别率都会提高。
  2. 提醒用户把二维码放在光线充足的地方,不要反光,不要模糊,这样识别率会更高。
  3. 如果只需要扫描二维码,不需要扫描条形码,可以把formats属性设置成['qr_code'],这样插件就不会浪费CPU和内存去识别条形码,识别速度和识别率都会提高。

从相册里选择图片识别失败

这个主要是因为图片太大或者图片格式的问题,很多手机拍的照片或者截图都特别大,分辨率甚至超过了4K,插件处理起来需要消耗大量的时间和内存,甚至会直接崩溃。

解决方法也很简单,在选择图片之后,先把图片压缩一下,再传给插件识别,图片压缩可以用compressorjs库,这个库是专门为前端图片压缩设计的,支持压缩JPG、PNG、GIF、WebP等格式的图片,压缩率很高,还能保持图片的清晰度。

compressorjs库也有适配Vue3的版本,叫vue-compressorjs,用起来更顺手,直接封装成组件就行。

怎么保证二维码生成和扫描的安全性?

很多朋友可能会忽略二维码的安全性,但其实二维码的安全性很重要,尤其是在生成分享二维码或者扫描用户提供的二维码的时候。

生成二维码的安全性

生成二维码的时候,主要的安全风险是XSS注入——如果二维码的内容是用户输入的,比如用户在分享页面填写了自己的昵称,然后生成包含昵称的分享链接二维码,用户如果输入了恶意的脚本代码,虽然脚本代码不会直接在二维码里执行,但如果扫码设备识别之后自动打开链接,或者把内容显示在页面上,就可能会导致XSS注入。

解决方法也很简单:

  1. 对用户输入的内容进行严格的过滤和转义,不要直接把用户输入的内容放到二维码里。
  2. 生成分享链接的时候,最好用后端生成的短链接,不要直接把用户输入的内容放到链接里,短链接可以由后端统一管理,也能防止XSS注入。
  3. 如果必须把用户输入的内容放到链接里,最好对链接进行签名,后端验证签名之后再处理请求,防止用户篡改链接。

扫描二维码的安全性

扫描二维码的时候,主要的安全风险是恶意链接——用户可能会扫描到包含恶意链接的二维码,比如钓鱼网站链接、下载病毒的链接,扫码设备识别之后自动打开链接,就可能会导致用户的信息泄露或者设备中毒。

解决方法也很简单:

  1. 扫描到链接之后,不要自动打开,而是先把链接显示在页面上,让用户确认之后再打开。
  2. 对扫描到的链接进行安全检测,比如检查链接的域名是不是白名单里的,如果不是白名单里的,就提醒用户谨慎打开。
  3. 如果是在小程序里扫描二维码,最好用小程序的wx.scanCodeAPI,这个API会自动过滤掉一些恶意链接,还能支持识别小程序码。

今天给大家分享了Vue3项目里安全、高效、可定制地生成和扫描二维码的方法,包括主流插件的选择、踩过的坑和解决方法、安全性的保证,希望能帮到大家。

最后再给大家提个醒:插件只是工具,要根据自己的需求选择合适的插件,不要盲目追求Star数高或者功能多的插件,适合自己的才是最好的,一定要做好测试,尤其是兼容性测试,不同的浏览器、不同的机型、不同的系统版本表现可能会不一样,一定要多测试几遍,确保功能稳定、做顺。

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

热门