更新记录
1.0.4(2024-11-30)
下载此版本
1.0.1.2(2024-11-29)
下载此版本
1.0.2(2024-11-25)
下载此版本
查看更多
平台兼容性
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 |