更新记录

1.0.4(2024-11-30) 下载此版本

  • 更新文档

1.0.1.2(2024-11-29) 下载此版本

  • 修复已知BUG

1.0.2(2024-11-25) 下载此版本

  • 修改文档增加体验demo
查看更多

平台兼容性

Vue2 Vue3
×
App 快应用 微信小程序 支付宝小程序 百度小程序 字节小程序 QQ小程序
HBuilderX 4.34,Android:6.0,iOS:不支持,HarmonyNext:支持 × × × × ×
钉钉小程序 快手小程序 飞书小程序 京东小程序
× × × ×
H5-Safari Android Browser 微信浏览器(Android) QQ浏览器(Android) Chrome IE Edge Firefox PC-Safari
× × × × × × × × ×

Scan 扫码

该组件可以集成到应用中,提供实时的扫码功能,适用于多种扫码场景。

支持平台

安卓 ios web 微信小程序 支付宝小程序 QQ小程序
x x x

在线体验扫一扫

<script>
    import { TuiScan, TuiView, TuiCanvas, TuiMixin, ttc, n } from '../../index.uts'
    import { ScanResult } from '@/uni_modules/tui-scan'
    /**
     * Scan 扫码
     * @author TanYuan
     * @description 扫码组件,用于扫描二维码或条形码,支持配置扫描模式、矩形颜色、线条颜色、线条高度、是否显示遮罩等。
     * @property {String} mode 扫描模式
     * @property {String} rectColor 矩形颜色
     * @property {String} lineColor 线条颜色
     * @property {Number} lineHeight 线条高度
     * @property {Boolean} mask 是否显示遮罩
     */
    export default {
        name: "t-scan",
        mixins: [TuiMixin],
        render() : VNode {
            const view = new TuiView()
            view.onClick = () => {
                this.rescan()
            }
            view.extendStyle()
            const scan = new TuiScan()
            scan.onScanned = (e : ScanResult) => {
                this.$emit('scanned', e)
            }
            scan.onPause = (e : boolean) => {
                this.pause = e
                if (!this.pause) {
                    this.drawMask()
                }
            }
            scan.ref = 'tuiscan'
            scan.class = 'twh.100%'
            const mask = new TuiCanvas()
            mask.onInitFinished = this.maskCanvasInit
            mask.class = 'da-twh.100%'
            view(scan)
            view.createSlot('default', null, mask)
            return view.vnode
        },
        data() {
            return {
                canvasMaskCtx: null as CanvasRenderingContext2D | null,
                animationTaskId: 0,
                pause: false
            };
        },
        props: {
            mode: {
                type: String,
                default: 'qr'
            },
            rectColor: {
                type: String,
                default: ''
            },
            lineColor: {
                type: String,
                default: ''
            },
            lineHeight: {
                type: Number,
                default: 2
            },
            mask: {
                type: Boolean,
                default: true
            }
        },
        mounted() {
            if (this.animationTaskId != 0) cancelAnimationFrame(this.animationTaskId)
        },
        methods: {
            rescan() {
                const ins = this.$refs['tuiscan'] as ComponentPublicInstance
                const scan = ins.$refs['nativescan'] as TuiScanElement
                scan.rescan()
            },
            scanImageByURI(url : string) {
                const ins = this.$refs['tuiscan'] as ComponentPublicInstance
                const scan = ins.$refs['nativescan'] as TuiScanElement
                scan.scanImageByURI(url)
            },
            maskCanvasInit(ctx : CanvasContext) {
                this.canvasMaskCtx = ctx.getContext('2d')
                this.drawMask()
            },
            drawMask() {
                const ctx = this.canvasMaskCtx!
                // canvas的宽度和高度
                const canvasWidth = ctx.canvas.offsetWidth;
                const canvasHeight = ctx.canvas.offsetHeight;
                if (!this.mask) {
                    ctx.clearRect(0, 0, canvasWidth, canvasHeight)
                    return
                }
                // 设置矩形框的宽度和高度
                let rectWidth = 300; // 矩形框的宽度
                let rectHeight = 100; // 矩形框的高度
                if (this.mode == 'qr') {
                    rectWidth = 200
                    rectHeight = 200
                }
                // 计算矩形框的起始坐标,使其位于画布中心
                const rectX = (canvasWidth - rectWidth) / 2;
                const rectY = (canvasHeight - rectHeight) / 2;
                // 绘制矩形框
                ctx.lineWidth = 4;
                ctx.globalAlpha = 1;
                ctx.strokeStyle = 'black';
                ctx.globalAlpha = 0.5;
                ctx.fillRect(0, 0, canvasWidth, rectY);
                ctx.fillRect(0, rectY, rectX, rectHeight);
                ctx.fillRect(0, rectY + rectHeight, canvasWidth, canvasHeight - rectHeight - rectY);
                ctx.fillRect(rectX + rectWidth, rectY, canvasWidth - rectWidth - rectX, rectHeight);
                ctx.globalAlpha = 1;
                const rectcolor = ttc(this.type, '', this.rectColor, false)
                ctx.strokeStyle = rectcolor;
                ctx.moveTo(rectX + 15, rectY);
                ctx.lineTo(rectX, rectY);
                ctx.lineTo(rectX, rectY + 15);
                ctx.moveTo(rectX + rectWidth - 15, rectY);
                ctx.lineTo(rectX + rectWidth, rectY);
                ctx.lineTo(rectX + rectWidth, rectY + 15);
                ctx.moveTo(rectX + 15, rectY + rectHeight);
                ctx.lineTo(rectX, rectY + rectHeight);
                ctx.lineTo(rectX, rectY + rectHeight - 15);
                ctx.moveTo(rectX + rectWidth - 15, rectY + rectHeight);
                ctx.lineTo(rectX + rectWidth, rectY + rectHeight);
                ctx.lineTo(rectX + rectWidth, rectY + rectHeight - 15);
                ctx.stroke()
                this.drawScannerLine(rectX, rectY, rectWidth, rectHeight);
            },
            drawScannerLine(rectX : number, rectY : number, rectWidth : number, rectHeight : number) {
                const ctx = this.canvasMaskCtx!;
                const scannerLineHeight = this.lineHeight; // 扫描线的高度
                const scannerLineWidth = rectWidth - 2; // 扫描线的宽度
                let scannerLineY = rectY; // 扫描线的初始Y坐标
                let that = this
                function animateScannerLine() {
                    if (that.animationTaskId != 0) cancelAnimationFrame(that.animationTaskId)
                    if (that.pause) {
                        ctx.clearRect(0, 0, ctx.canvas.offsetWidth, ctx.canvas.offsetHeight)
                        return
                    }
                    ctx.clearRect(rectX + 1, rectY, rectWidth - 1, rectHeight)
                    const linecolor = ttc(that.type, '', that.lineColor, false)
                    ctx.fillStyle = linecolor; // 扫描线的颜色
                    ctx.fillRect(rectX + 1, scannerLineY, scannerLineWidth, scannerLineHeight);

                    // 更新扫描线的位置
                    if (that.mode == 'qr') {
                        scannerLineY += 2; // 扫描线的移动速度
                    } else {
                        scannerLineY += 0.5; // 扫描线的移动速度
                    }
                    if (scannerLineY > rectY + rectHeight - scannerLineHeight) {
                        scannerLineY = rectY; // 重置扫描线的位置
                    }
                    that.animationTaskId = requestAnimationFrame((_ : number) => {
                        animateScannerLine()
                    })
                };
                animateScannerLine()
            }
        }
    }
</script>

Props

名称 描述 类型 默认值
mode 扫描模式 String 'qr'
rectColor 矩形颜色 String ''
lineColor 线条颜色 String ''
lineHeight 线条高度 Number 2
mask 是否显示遮罩 Boolean true

Methods

名称 描述
rescan 重新开始扫描
scanImageByURI 通过URI扫描图片
maskCanvasInit 初始化遮罩Canvas
drawMask 绘制遮罩
drawScannerLine 绘制扫描线

Events

名称 描述 参数
scanned 当扫描到结果时触发 result

隐私、权限声明

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

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

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

许可协议

MIT协议

暂无用户评论。

使用中有什么不明白的地方,就向插件作者提问吧~ 我要提问