init
This commit is contained in:
160
uni_modules/lime-qrcode/components/l-qrcode/ios/index.uts
Normal file
160
uni_modules/lime-qrcode/components/l-qrcode/ios/index.uts
Normal file
@@ -0,0 +1,160 @@
|
||||
// export * from '../qrcode'
|
||||
export * from '@/uni_modules/lime-qrcodegen/utssdk/interface';
|
||||
import { type QRCodePropsTypes , type ImageSettings, type QRCodeCallback } from '@/uni_modules/lime-qrcodegen/utssdk/interface'
|
||||
|
||||
import { qrcodegen } from './qrcodegen'
|
||||
const Ecc = qrcodegen.QrCode.Ecc
|
||||
const QrCode = qrcodegen.QrCode
|
||||
type Modules = boolean[][];
|
||||
type Excavation = { x : number; y : number; w : number; h : number };
|
||||
type ImageSettingExcavation = {
|
||||
x: number
|
||||
y: number
|
||||
h: number
|
||||
w: number
|
||||
excavation: Excavation
|
||||
}
|
||||
const ERROR_LEVEL_MAP = {
|
||||
L: Ecc.LOW,
|
||||
M: Ecc.MEDIUM,
|
||||
Q: Ecc.QUARTILE,
|
||||
H: Ecc.HIGH,
|
||||
};
|
||||
|
||||
const DEFAULT_SIZE:number = 128;
|
||||
const DEFAULT_LEVEL:string = 'L';
|
||||
// const DEFAULT_BGCOLOR:string = '#FFFFFF';
|
||||
const DEFAULT_FGCOLOR:string = '#000000';
|
||||
const DEFAULT_INCLUDEMARGIN:boolean = false;
|
||||
|
||||
const SPEC_MARGIN_SIZE : number = 4;
|
||||
const DEFAULT_MARGIN_SIZE : number = 0;
|
||||
|
||||
// This is *very* rough estimate of max amount of QRCode allowed to be covered.
|
||||
// It is "wrong" in a lot of ways (area is a terrible way to estimate, it
|
||||
// really should be number of modules covered), but if for some reason we don't
|
||||
// get an explicit height or width, I'd rather default to something than throw.
|
||||
const DEFAULT_IMG_SCALE = 0.1;
|
||||
|
||||
// We could just do this in generatePath, except that we want to support
|
||||
// non-Path2D canvas, so we need to keep it an explicit step.
|
||||
function excavateModules(modules : Modules, excavation : Excavation) : Modules {
|
||||
const ox = excavation.x
|
||||
const oy = excavation.y
|
||||
const oh = excavation.h
|
||||
const ow = excavation.w
|
||||
return modules.slice().map((row, y):boolean[] => {
|
||||
if (y < oy || y >= oy + oh) {
|
||||
return row;
|
||||
}
|
||||
return row.map((cell, x):boolean => {
|
||||
if (x < ox || x >= ox + ow) {
|
||||
return cell;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getImageSettings(
|
||||
cells : Modules,
|
||||
size : number,
|
||||
margin : number,
|
||||
imageSettings: ImageSettings | null
|
||||
) : ImageSettingExcavation | null {
|
||||
if (imageSettings == null) {
|
||||
return null;
|
||||
}
|
||||
// const result : UTSJSONObject = {}
|
||||
const numCells = cells.length + margin * 2;
|
||||
const defaultSize = Math.floor(size * DEFAULT_IMG_SCALE);
|
||||
const scale = numCells / size;
|
||||
|
||||
const width = imageSettings.width
|
||||
const height = imageSettings.height
|
||||
const ox = imageSettings.x
|
||||
const oy = imageSettings.y
|
||||
const excavate = imageSettings.excavate
|
||||
|
||||
const w = (width > 0 ? width : defaultSize) * scale;
|
||||
const h = (height > 0 ? height: defaultSize) * scale;
|
||||
const x = ox == null ? cells.length / 2 - w / 2 : ox * scale;
|
||||
const y = oy == null ? cells.length / 2 - h / 2 : oy * scale;
|
||||
|
||||
let excavation: Excavation = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: 0,
|
||||
h: 0,
|
||||
};
|
||||
if (excavate) {
|
||||
let floorX = Math.floor(x);
|
||||
let floorY = Math.floor(y);
|
||||
let ceilW = Math.ceil(w + x - floorX);
|
||||
let ceilH = Math.ceil(h + y - floorY);
|
||||
// excavation = { x: floorX, y: floorY, w: ceilW, h: ceilH };
|
||||
excavation.x = floorX
|
||||
excavation.y = floorY
|
||||
excavation.w = ceilW
|
||||
excavation.h = ceilH
|
||||
}
|
||||
|
||||
return { x, y, h, w, excavation } as ImageSettingExcavation;
|
||||
}
|
||||
function getMarginSize(includeMargin : boolean, marginSize: number|null) : number {
|
||||
if (marginSize != null) {
|
||||
return Math.floor(marginSize);
|
||||
}
|
||||
return includeMargin ? SPEC_MARGIN_SIZE : DEFAULT_MARGIN_SIZE;
|
||||
}
|
||||
export class QRCodeCanvas {
|
||||
ctx : DrawableContext
|
||||
constructor(ctx : DrawableContext) {
|
||||
this.ctx = ctx
|
||||
}
|
||||
render(props : QRCodePropsTypes, cb : QRCodeCallback | null=null) {
|
||||
const ctx = this.ctx
|
||||
const value = props.value
|
||||
const size = props.size ?? DEFAULT_SIZE
|
||||
const level = props.level ?? DEFAULT_LEVEL
|
||||
const fgColor = props.fgColor ?? DEFAULT_FGCOLOR
|
||||
const includeMargin = props.includeMargin || DEFAULT_INCLUDEMARGIN
|
||||
const marginSize = props.marginSize
|
||||
const imageSettings = props.imageSettings
|
||||
if (value == null || value == '') {
|
||||
return;
|
||||
}
|
||||
let cells = QrCode.encodeText(value, ERROR_LEVEL_MAP[level] as Ecc).getModules();
|
||||
const margin = getMarginSize(includeMargin, marginSize);
|
||||
const numCells = cells.length + margin * 2;
|
||||
const scale = (size / numCells);
|
||||
const calculatedImageSettings = getImageSettings(
|
||||
cells,
|
||||
size,
|
||||
margin,
|
||||
imageSettings
|
||||
)
|
||||
const haveImageToRender = calculatedImageSettings != null
|
||||
const excavation: Excavation | null = haveImageToRender ? calculatedImageSettings?.excavation : null
|
||||
|
||||
if(haveImageToRender && excavation != null) {
|
||||
cells = excavateModules(cells, excavation);
|
||||
}
|
||||
ctx.reset()
|
||||
// ctx.clearRect(0, 0, size, size)
|
||||
// ctx.fillStyle = bgColor;
|
||||
// ctx.fillRect(0, 0, numCells, numCells);
|
||||
ctx.fillStyle = fgColor;
|
||||
cells.forEach(function (row, rdx) {
|
||||
row.forEach(function (cell, cdx) {
|
||||
if (cell) {
|
||||
ctx.fillRect((cdx + margin) * scale, (rdx + margin) * scale, scale, scale);
|
||||
}
|
||||
});
|
||||
});
|
||||
ctx.update()
|
||||
if(cb != null){
|
||||
cb(cells)
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
300
uni_modules/lime-qrcode/components/l-qrcode/l-qrcode.uvue
Normal file
300
uni_modules/lime-qrcode/components/l-qrcode/l-qrcode.uvue
Normal file
@@ -0,0 +1,300 @@
|
||||
<template>
|
||||
<!-- #ifndef APP || WEB -->
|
||||
<canvas :style="styles" v-if="use2d" type="2d" :canvas-id="canvasId" :id="canvasId"></canvas>
|
||||
<canvas :style="styles" v-else :canvas-id="canvasId" :id="canvasId"></canvas>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef APP -->
|
||||
<view class="l-qrcode" ref="drawableRef" :style="[styles]">
|
||||
<image class="l-qrcode__icon" v-if="icon" :src="icon" :style="[iconStyle]"></image>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef WEB -->
|
||||
<view class="l-qrcode" ref="drawableRef" :style="[styles]"></view>
|
||||
<!-- #endif -->
|
||||
</template>
|
||||
<script lang="uts" setup>
|
||||
/**
|
||||
* QRCode 二维码组件
|
||||
* @description 用于生成二维码图形,支持自定义图标和样式配置
|
||||
* <br>插件类型:LQrcodeComponentPublicInstance
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?name=lime-qrcode
|
||||
*
|
||||
* @property {string} value 二维码内容(支持文本/URL等)
|
||||
* @property {string} icon 中心图标路径(支持本地/网络路径)
|
||||
* @property {number | string} size 二维码尺寸
|
||||
* @property {number | string} iconSize 中心图标尺寸
|
||||
* @property {number} marginSize 二维码外边距(默认:0)
|
||||
* @property {string} color 二维码颜色(默认:#000000)
|
||||
* @property {string} bgColor 背景颜色(默认:#ffffff)
|
||||
* @property {boolean} bordered 显示边框(默认:false)
|
||||
* @property {'L' | 'M' | 'Q' | 'H'} errorLevel 容错等级(默认:'H')
|
||||
* @value L 可恢复7%的数据
|
||||
* @value M 可恢复15%的数据
|
||||
* @value Q 可恢复25%的数据
|
||||
* @value H 可恢复30%的数据
|
||||
* @property {boolean} useCanvasToTempFilePath 使用canvas生成临时路径(H5端可能需要)
|
||||
* @property {boolean} use2d 启用2D上下文渲染(性能优化,默认:false)
|
||||
*/
|
||||
import { type PropType, nextTick } from 'vue'
|
||||
// #ifndef APP
|
||||
import { createImage } from '@/uni_modules/lime-shared/createImage'
|
||||
import { getCanvas, isCanvas2d } from './useCanvas'
|
||||
import { QRCodeCanvas } from './qrcode.js';
|
||||
import { QRCodePropsTypes , ImageSettings } from './type'
|
||||
// #endif
|
||||
// #ifdef APP-ANDROID || APP-HARMONY
|
||||
import { QRCodeCanvas, type QRCodePropsTypes , type ImageSettings } from '@/uni_modules/lime-qrcodegen'
|
||||
// #endif
|
||||
// #ifdef APP-IOS
|
||||
import { QRCodeCanvas, type QRCodePropsTypes , type ImageSettings } from './ios'
|
||||
// #endif
|
||||
// import { addUnit } from '@/uni_modules/lime-shared/addUnit'
|
||||
// import { unitConvert } from '@/uni_modules/lime-shared/unitConvert'
|
||||
// import { toBoolean } from '@/uni_modules/lime-shared/toBoolean'
|
||||
import { addUnit, unitConvert } from './utils'
|
||||
import { LQrcodeFailCallback, LQrcodeCompleteCallback, LQrcodeSuccessCallback} from './type'
|
||||
|
||||
const name = 'l-qrcode'
|
||||
const props = defineProps({
|
||||
value: {
|
||||
type: String
|
||||
},
|
||||
icon: {
|
||||
type: String
|
||||
},
|
||||
// #ifdef APP-ANDROID
|
||||
size: {
|
||||
type: Object,
|
||||
default: 160
|
||||
},
|
||||
iconSize: {
|
||||
type: Object,
|
||||
default: 40
|
||||
},
|
||||
// #endif
|
||||
// #ifndef APP-ANDROID
|
||||
size: {
|
||||
type: [Number, String],
|
||||
default: 160
|
||||
},
|
||||
iconSize: {
|
||||
type: [Number, String],
|
||||
default: 40
|
||||
},
|
||||
// #endif
|
||||
marginSize: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: '#000'
|
||||
},
|
||||
bgColor: {
|
||||
type: String,
|
||||
default: 'transparent'
|
||||
},
|
||||
bordered: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
errorLevel: {
|
||||
type: String as PropType<'L' | 'M' | 'Q' | 'H'>,
|
||||
default: 'M' // 'L' | 'M' | 'Q' | 'H'
|
||||
},
|
||||
useCanvasToTempFilePath: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
use2d: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
// status: {
|
||||
// type: String as PropType<'active'|'expired'|'loading'>,
|
||||
// default: 'active' // active | expired | loading
|
||||
// }
|
||||
})
|
||||
const emits = defineEmits(['success'])
|
||||
const context = getCurrentInstance();
|
||||
const canvasId = `l-qrcode${context!.uid}`
|
||||
const styles = computed<Map<string, any>>(():Map<string, any>=>{
|
||||
const style = new Map<string, any>()
|
||||
const size = addUnit(props.size);
|
||||
if(size!=null){
|
||||
style.set('width', size)
|
||||
style.set('height', size)
|
||||
}
|
||||
style.set('background', props.bgColor)
|
||||
return style
|
||||
})
|
||||
// #ifdef APP
|
||||
const iconStyle = computed<Map<string, any>>(():Map<string, any>=>{
|
||||
const style = new Map<string, any>()
|
||||
const size = addUnit(props.iconSize);
|
||||
// if(size!=null){
|
||||
style.set('width', size)
|
||||
style.set('height', size)
|
||||
// }
|
||||
return style
|
||||
})
|
||||
// #endif
|
||||
const drawableRef = ref<UniElement|null>(null);
|
||||
// #ifndef APP
|
||||
let canvas:HTMLCanvasElement|null = null
|
||||
// #endif
|
||||
let qrcode:QRCodeCanvas|null = null
|
||||
|
||||
const canvasToTempFilePath = (options: UTSJSONObject)=>{
|
||||
const format = options.getString('format') ?? 'png';
|
||||
const fail = options.get('fail') as LQrcodeFailCallback | null;
|
||||
const complete = options.get('complete') as LQrcodeCompleteCallback | null;
|
||||
const success = options.get('success') as LQrcodeSuccessCallback | null;
|
||||
// #ifdef APP
|
||||
const newOptions = {
|
||||
format,
|
||||
fail,
|
||||
complete,
|
||||
success,
|
||||
} as TakeSnapshotOptions
|
||||
drawableRef.value!.takeSnapshot(newOptions)
|
||||
// #endif
|
||||
// #ifdef WEB
|
||||
success?.({
|
||||
tempFilePath: canvas?.toDataURL('image/'+format)
|
||||
})
|
||||
// #endif
|
||||
|
||||
}
|
||||
const render = ()=>{
|
||||
const param:QRCodePropsTypes = {
|
||||
value: props.value,
|
||||
size: unitConvert(props.size),
|
||||
fgColor: props.color,
|
||||
level: ['L', 'M', 'Q', 'H'].includes(props.errorLevel) ? props.errorLevel : 'M',
|
||||
marginSize: props.marginSize,
|
||||
includeMargin: props.bordered,
|
||||
imageSettings: null,
|
||||
} as QRCodePropsTypes
|
||||
// #ifdef APP-HARMONY
|
||||
param.value = props.value
|
||||
param.size = unitConvert(props.size)
|
||||
param.fgColor = props.color
|
||||
param.level = ['L', 'M', 'Q', 'H'].includes(props.errorLevel) ? props.errorLevel : 'M'
|
||||
param.marginSize = props.marginSize
|
||||
param.includeMargin = props.bordered
|
||||
param.imageSettings = null
|
||||
// #endif
|
||||
if(props.icon != null){
|
||||
// if(toBoolean(props.iconSize) && toBoolean(props.icon)){
|
||||
const size = unitConvert(props.iconSize)
|
||||
param.imageSettings = {
|
||||
src: props.icon,
|
||||
width: size,
|
||||
height: size,
|
||||
excavate: true
|
||||
} as ImageSettings
|
||||
|
||||
// #ifdef APP-HARMONY
|
||||
param.imageSettings.src = props.icon
|
||||
param.imageSettings.width = size
|
||||
param.imageSettings.height = size
|
||||
param.imageSettings.excavate = true
|
||||
// #endif
|
||||
}
|
||||
qrcode?.render(param)
|
||||
if(props.useCanvasToTempFilePath){
|
||||
setTimeout(()=>{
|
||||
canvasToTempFilePath({
|
||||
success: (res: TakeSnapshotSuccess)=>{
|
||||
emits('success', res.tempFilePath)
|
||||
}
|
||||
})
|
||||
},100)
|
||||
}
|
||||
}
|
||||
defineExpose({
|
||||
canvasToTempFilePath
|
||||
})
|
||||
onMounted(()=>{
|
||||
nextTick(()=>{
|
||||
// #ifdef APP
|
||||
requestAnimationFrame(()=> {
|
||||
drawableRef.value?.getBoundingClientRectAsync()?.then(res => {
|
||||
const ctx = drawableRef.value!.getDrawableContext();
|
||||
qrcode = new QRCodeCanvas(ctx!)
|
||||
watchEffect(()=>{
|
||||
render()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// #endif
|
||||
// #ifdef WEB
|
||||
canvas = document.createElement('canvas')
|
||||
canvas!.style.width = '100%'
|
||||
canvas!.style.height = '100%'
|
||||
drawableRef.value!.appendChild(canvas!)
|
||||
qrcode = new QRCodeCanvas(canvas, {
|
||||
pixelRatio: uni.getSystemInfoSync().pixelRatio,
|
||||
createImage: () => {
|
||||
const image = new Image();
|
||||
// @ts-ignore
|
||||
image.crossOrigin = 'anonymous';
|
||||
return image;
|
||||
}
|
||||
})
|
||||
watchEffect(()=>{
|
||||
render()
|
||||
})
|
||||
// #endif
|
||||
// #ifndef APP || WEB
|
||||
getCanvas(canvasId, { context }).then(res => {
|
||||
canvas = res;
|
||||
qrcode = new QRCodeCanvas(res, {
|
||||
path2D: false,
|
||||
pixelRatio: isCanvas2d && props.use2d ? uni.getSystemInfoSync().pixelRatio : 1,
|
||||
createImage
|
||||
})
|
||||
watchEffect(()=>{
|
||||
render()
|
||||
})
|
||||
})
|
||||
// #endif
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
onUnmounted(()=>{
|
||||
// #ifdef WEB
|
||||
canvas?.remove();
|
||||
// #endif
|
||||
qrcode = null;
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.l-qrcode {
|
||||
position: relative;
|
||||
background-color: aqua;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
&-mask {
|
||||
position: absolute;
|
||||
// inset: 0;
|
||||
// inset-block-start: 0;
|
||||
// inset-inline-start: 0;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
// width: 100%;
|
||||
// height: 100%;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
line-height: 1.5714285714285714;
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
249
uni_modules/lime-qrcode/components/l-qrcode/l-qrcode.vue
Normal file
249
uni_modules/lime-qrcode/components/l-qrcode/l-qrcode.vue
Normal file
@@ -0,0 +1,249 @@
|
||||
<template>
|
||||
<view class="l-qrcode" :style="[styles]">
|
||||
<!-- #ifndef APP-NVUE -->
|
||||
<canvas :style="styles" v-if="use2d" type="2d" :canvas-id="canvasId" :id="canvasId"></canvas>
|
||||
<canvas :style="styles" v-else :canvas-id="canvasId" :id="canvasId"></canvas>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef APP-NVUE -->
|
||||
<web-view
|
||||
ref="qrcodeRef"
|
||||
@pagefinish="onFinished"
|
||||
@error="onError"
|
||||
@onPostMessage="onMessage"
|
||||
:style="styles" src="/uni_modules/lime-qrcode/hybrid/html/index.html?v=1"></web-view>
|
||||
<!-- #endif -->
|
||||
<!-- <view class="l-qrcode-mask" v-if="['loading', 'expired'].includes(props.status)">
|
||||
<l-loading v-if="props.status == 'loading'"></l-loading>
|
||||
<view class="l-qrcode-expired" v-if="props.status == 'expired'">
|
||||
<slot></slot>
|
||||
</view>
|
||||
</view> -->
|
||||
</view>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* QRCode 二维码组件
|
||||
* @description 用于生成二维码图形,支持自定义图标和样式配置
|
||||
* <br>插件类型:LQrcodeComponentPublicInstance
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?name=lime-qrcode
|
||||
*
|
||||
* @property {string} value 二维码内容(支持文本/URL等)
|
||||
* @property {string} icon 中心图标路径(支持本地/网络路径)
|
||||
* @property {number | string} size 二维码尺寸
|
||||
* @property {number | string} iconSize 中心图标尺寸
|
||||
* @property {number} marginSize 二维码外边距(默认:0)
|
||||
* @property {string} color 二维码颜色(默认:#000000)
|
||||
* @property {string} bgColor 背景颜色(默认:#ffffff)
|
||||
* @property {boolean} bordered 显示边框(默认:false)
|
||||
* @property {'L' | 'M' | 'Q' | 'H'} errorLevel 容错等级(默认:'H')
|
||||
* @value L 可恢复7%的数据
|
||||
* @value M 可恢复15%的数据
|
||||
* @value Q 可恢复25%的数据
|
||||
* @value H 可恢复30%的数据
|
||||
* @property {boolean} useCanvasToTempFilePath 使用canvas生成临时路径(H5端可能需要)
|
||||
* @property {boolean} use2d 启用2D上下文渲染(性能优化,默认:false)
|
||||
*/
|
||||
import { computed, defineComponent, getCurrentInstance, watch, onUnmounted, onMounted } from '@/uni_modules/lime-shared/vue';
|
||||
import QRCodeProps from './props'
|
||||
// #ifndef APP-NVUE
|
||||
import { getCanvas, isCanvas2d } from './useCanvas'
|
||||
import { QRCodeCanvas } from './qrcode.js';
|
||||
// #endif
|
||||
import { addUnit } from '@/uni_modules/lime-shared/addUnit'
|
||||
import { createImage } from '@/uni_modules/lime-shared/createImage'
|
||||
import { unitConvert } from '@/uni_modules/lime-shared/unitConvert'
|
||||
import { isBase64 } from '@/uni_modules/lime-shared/isBase64'
|
||||
import { pathToBase64 } from '@/uni_modules/lime-shared/pathToBase64'
|
||||
import { debounce } from '@/uni_modules/lime-shared/debounce'
|
||||
const name = 'l-qrcode'
|
||||
export default defineComponent({
|
||||
name,
|
||||
props: QRCodeProps,
|
||||
emits: ['success'],
|
||||
setup(props, {emit}) {
|
||||
const context = getCurrentInstance();
|
||||
const canvasId = `l-qrcode${context.uid}`
|
||||
const styles = computed(() => `width: ${addUnit(props.size)}; height: ${addUnit(props.size)};`)
|
||||
let qrcode = null
|
||||
let canvas = null
|
||||
const qrCodeProps = computed(() => {
|
||||
const { value, icon, size, color, bgColor, bordered, iconSize, errorLevel, marginSize } = props
|
||||
const imageSettings = {
|
||||
src: icon,
|
||||
x: undefined,
|
||||
y: undefined,
|
||||
height: unitConvert(iconSize),
|
||||
width: unitConvert(iconSize),
|
||||
excavate: true,
|
||||
}
|
||||
return {
|
||||
value,
|
||||
size: unitConvert(size),
|
||||
level: errorLevel,
|
||||
bgColor,
|
||||
fgColor: color,
|
||||
imageSettings: icon ? imageSettings : undefined,
|
||||
includeMargin: bordered,
|
||||
marginSize: marginSize ?? 0
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
// #ifdef APP-NVUE
|
||||
const stacks = new Map()
|
||||
// #endif
|
||||
const canvasToTempFilePath = debounce((args: UniNamespace.CanvasToTempFilePathRes) => {
|
||||
if(!canvas) return
|
||||
// #ifndef APP-NVUE
|
||||
const copyArgs = Object.assign({
|
||||
canvasId,
|
||||
canvas: null
|
||||
}, args)
|
||||
|
||||
if (isCanvas2d && props.use2d) {
|
||||
// copyArgs.canvas = canvas
|
||||
const tempFilePath = canvas.toDataURL();
|
||||
copyArgs.success({
|
||||
tempFilePath
|
||||
})
|
||||
return
|
||||
}
|
||||
if ('toTempFilePath' in canvas) {
|
||||
canvas.toTempFilePath(copyArgs)
|
||||
} else {
|
||||
uni.canvasToTempFilePath(copyArgs, context);
|
||||
}
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
if(!stacks.size) {
|
||||
const flie = 'file-' + Math.random();
|
||||
const stack = {args, time: +new Date()}
|
||||
stacks.set(`${flie}`, stack)
|
||||
canvas.toDataURL(flie)
|
||||
setTimeout(() => {
|
||||
const stack = stacks.get(flie)
|
||||
if(stack && 'fail' in stack.args) {
|
||||
stack.args.fail({
|
||||
error: '超时'
|
||||
})
|
||||
stacks.delete(flie)
|
||||
}
|
||||
},5000)
|
||||
}
|
||||
// #endif
|
||||
})
|
||||
const useCanvasToTempFilePath = () => {
|
||||
if(props.useCanvasToTempFilePath) {
|
||||
canvasToTempFilePath({
|
||||
success(res: UniNamespace.CanvasToTempFilePathRes) {
|
||||
emit('success', res.tempFilePath)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
// #ifdef APP-NVUE
|
||||
const onFinished = () => {
|
||||
const { pixelRatio } = uni.getSystemInfoSync()
|
||||
canvas = {
|
||||
toDataURL(flie: string) {
|
||||
const ref: any = context.refs['qrcodeRef'];
|
||||
if(ref) {
|
||||
ref?.evalJS(`toDataURL('${flie}')`)
|
||||
}
|
||||
}
|
||||
};
|
||||
qrcode = {
|
||||
async render(props: any) {
|
||||
const ref: any = context.refs['qrcodeRef'];
|
||||
const { src } = props.imageSettings || { };
|
||||
if(!ref) return
|
||||
if(src && !isBase64(src) && !/^http/.test(src) && /^\/static/.test(src)) {
|
||||
props.imageSettings.src = await pathToBase64(src)
|
||||
}
|
||||
const _props = JSON.stringify(Object.assign({}, props, {pixelRatio}));
|
||||
ref?.evalJS(`render(${_props})`);
|
||||
}
|
||||
}
|
||||
qrcode.render(qrCodeProps.value)
|
||||
useCanvasToTempFilePath()
|
||||
}
|
||||
const onError = () => {
|
||||
console.warn('lime-qrcode 加载失败')
|
||||
}
|
||||
const onMessage = (e: any) => {
|
||||
const {detail:{data: [res]}} = e
|
||||
if(res.event == 'toDataURL') {
|
||||
const {file, image, msg} = res.data;
|
||||
const stack = stacks.get(file)
|
||||
if(stack && image && 'success' in stack.args) {
|
||||
stack.args.success({tempFilePath: image})
|
||||
stacks.delete(file)
|
||||
} else if(stack && 'fails' in stack.args) {
|
||||
stack.args.fail({error: msg})
|
||||
stacks.delete(file)
|
||||
}
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
const propsWatch = watch(props, () => {
|
||||
if (qrcode) {
|
||||
qrcode.render(qrCodeProps.value)
|
||||
useCanvasToTempFilePath()
|
||||
}
|
||||
})
|
||||
onMounted(() => {
|
||||
// #ifndef APP-NVUE
|
||||
getCanvas(canvasId, { context }).then(res => {
|
||||
canvas = res;
|
||||
qrcode = new QRCodeCanvas(res, {
|
||||
path2D: false,
|
||||
pixelRatio: isCanvas2d && props.use2d ? uni.getSystemInfoSync().pixelRatio : 1,
|
||||
createImage
|
||||
})
|
||||
qrcode.render(qrCodeProps.value)
|
||||
useCanvasToTempFilePath()
|
||||
})
|
||||
// #endif
|
||||
})
|
||||
onUnmounted(() => {
|
||||
propsWatch && propsWatch()
|
||||
})
|
||||
return {
|
||||
canvasId,
|
||||
styles,
|
||||
props,
|
||||
canvasToTempFilePath,
|
||||
|
||||
// #ifdef APP-NVUE
|
||||
onFinished,
|
||||
onError,
|
||||
onMessage
|
||||
// #endif
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.l-qrcode {
|
||||
position: relative;
|
||||
|
||||
&-mask {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
// inset-block-start: 0;
|
||||
// inset-inline-start: 0;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
// width: 100%;
|
||||
// height: 100%;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
line-height: 1.5714285714285714;
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
40
uni_modules/lime-qrcode/components/l-qrcode/props.ts
Normal file
40
uni_modules/lime-qrcode/components/l-qrcode/props.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
// @ts-nocheck
|
||||
// import type { PropType } from './vue'
|
||||
export default {
|
||||
value: String,
|
||||
icon: String,
|
||||
size: {
|
||||
type: [Number, String],
|
||||
default: 160
|
||||
},
|
||||
iconSize: {
|
||||
type: [Number, String],
|
||||
default: 40
|
||||
},
|
||||
marginSize: Number,
|
||||
color: {
|
||||
type: String,
|
||||
default: '#000'
|
||||
},
|
||||
bgColor: {
|
||||
type: String,
|
||||
default: 'transparent'
|
||||
},
|
||||
bordered: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
errorLevel: {
|
||||
type: String as PropType<'L'|'M'|'Q'|'H'>,
|
||||
default: 'M' // 'L' | 'M' | 'Q' | 'H'
|
||||
},
|
||||
useCanvasToTempFilePath: Boolean,
|
||||
use2d: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
// status: {
|
||||
// type: String as PropType<'active'|'expired'|'loading'>,
|
||||
// default: 'active' // active | expired | loading
|
||||
// }
|
||||
}
|
6
uni_modules/lime-qrcode/components/l-qrcode/qrcode.js
Normal file
6
uni_modules/lime-qrcode/components/l-qrcode/qrcode.js
Normal file
File diff suppressed because one or more lines are too long
48
uni_modules/lime-qrcode/components/l-qrcode/type.ts
Normal file
48
uni_modules/lime-qrcode/components/l-qrcode/type.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
// @ts-nocheck
|
||||
export type ImageSettings = {
|
||||
width: number
|
||||
height: number
|
||||
x?: number
|
||||
y?: number
|
||||
excavate: boolean
|
||||
}
|
||||
export type QRCodePropsTypes = {
|
||||
value?: string
|
||||
size?: number
|
||||
fgColor?: string
|
||||
level?: string
|
||||
marginSize: number
|
||||
includeMargin: boolean
|
||||
imageSettings?: ImageSettings
|
||||
}
|
||||
|
||||
export type QRCodeCallback = (cells : boolean[][]) => void
|
||||
|
||||
export type Excavation = {
|
||||
x: number
|
||||
y: number
|
||||
h: number
|
||||
w: number
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 成功回调函数定义
|
||||
*/
|
||||
export type TakeSnapshotSuccessCallback = (res: TakeSnapshotSuccess) => void
|
||||
/**
|
||||
* 失败回调函数定义
|
||||
*/
|
||||
export type TakeSnapshotFailCallback = (res: TakeSnapshotFail) => void
|
||||
/**
|
||||
* 完成回调函数定义
|
||||
*/
|
||||
export type TakeSnapshotCompleteCallback = (res: any) => void
|
||||
|
||||
|
||||
export type LQrcodeFailCallback = TakeSnapshotFailCallback
|
||||
export type LQrcodeCompleteCallback = TakeSnapshotCompleteCallback
|
||||
export type LQrcodeSuccessCallback = TakeSnapshotSuccessCallback
|
78
uni_modules/lime-qrcode/components/l-qrcode/useCanvas.ts
Normal file
78
uni_modules/lime-qrcode/components/l-qrcode/useCanvas.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
|
||||
// @ts-nocheck
|
||||
import type { ComponentInternalInstance } from '@/uni_modules/lime-shared/vue'
|
||||
import { getRect } from '@/uni_modules/lime-shared/getRect'
|
||||
import { canIUseCanvas2d } from '@/uni_modules/lime-shared/canIUseCanvas2d'
|
||||
export const isCanvas2d = canIUseCanvas2d()
|
||||
|
||||
export async function getCanvas(canvasId: string, options: {context: ComponentInternalInstance}) {
|
||||
let { context } = options
|
||||
// #ifdef MP || VUE2
|
||||
if (context.proxy) context = context.proxy
|
||||
// #endif
|
||||
return getRect('#' + canvasId, context, isCanvas2d).then(res => {
|
||||
if(res.node){
|
||||
return res.node
|
||||
} else {
|
||||
const ctx = uni.createCanvasContext(canvasId, context)
|
||||
return {
|
||||
getContext(type: string) {
|
||||
if(type == '2d') {
|
||||
return ctx
|
||||
}
|
||||
},
|
||||
width: res.width,
|
||||
height: res.height,
|
||||
}
|
||||
// #ifdef H5
|
||||
// canvas.value = context.proxy.$el.querySelector('#'+ canvasId)
|
||||
// #endif
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// #ifndef H5 || APP-NVUE
|
||||
class Image {
|
||||
currentSrc: string | null = null
|
||||
naturalHeight: number = 0
|
||||
naturalWidth: number = 0
|
||||
width: number = 0
|
||||
height: number = 0
|
||||
tagName: string = 'IMG'
|
||||
path: any = ''
|
||||
crossOrigin: any = ''
|
||||
referrerPolicy: any = ''
|
||||
onload: () => void
|
||||
onerror: () => void
|
||||
constructor() {}
|
||||
set src(src) {
|
||||
this.currentSrc = src
|
||||
uni.getImageInfo({
|
||||
src,
|
||||
success: (res) => {
|
||||
this.path = res.path
|
||||
this.naturalWidth = this.width = res.width
|
||||
this.naturalHeight = this.height = res.height
|
||||
this.onload()
|
||||
},
|
||||
fail: () => {
|
||||
this.onerror()
|
||||
}
|
||||
})
|
||||
}
|
||||
get src() {
|
||||
return this.currentSrc
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
|
||||
export function createImage(canvas: WechatMiniprogram.Canvas) {
|
||||
if(canvas && canvas.createImage) {
|
||||
return canvas.createImage()
|
||||
} else if(typeof window != 'undefined' && window.Image) {
|
||||
return new window.Image()
|
||||
}
|
||||
// #ifndef H5 || APP-NVUE
|
||||
return new Image()
|
||||
// #endif
|
||||
}
|
35
uni_modules/lime-qrcode/components/l-qrcode/utils.uts
Normal file
35
uni_modules/lime-qrcode/components/l-qrcode/utils.uts
Normal file
@@ -0,0 +1,35 @@
|
||||
export function addUnit(value: any|null):string{
|
||||
if(value == null){
|
||||
return ''
|
||||
}
|
||||
value = `${value}`
|
||||
return /^(-)?\d+(\\.\d+)?$/.test(value) ? `${value}px` : value
|
||||
}
|
||||
|
||||
export function unitConvert(value: any|null): number{
|
||||
if(typeof value == 'number'){
|
||||
return value as number
|
||||
}
|
||||
if(typeof value == 'string'){
|
||||
value = `${value}`
|
||||
if(/^(-)?\d+(\\.\d+)?$/.test(value)){
|
||||
return parseFloat(value);
|
||||
}
|
||||
|
||||
const reg = /^-?([0-9]+)?([.]{1}[0-9]+){0,1}(em|rpx|px|%)$/g;
|
||||
const results = reg.exec(value);
|
||||
if (results == null) {
|
||||
return 0;
|
||||
}
|
||||
const unit = results[3];
|
||||
const v = parseFloat(value);
|
||||
if (unit == 'rpx') {
|
||||
const { windowWidth } = uni.getWindowInfo()
|
||||
return windowWidth / 750 * v;
|
||||
}
|
||||
if (unit == 'px') {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user