提交 4880ca5a 编写于 作者: DCloud_JSON's avatar DCloud_JSON

- 新增 使用uni-id-pages的账号信息的状态管理功能

上级 27c252ad
## 2.0.4(2022-09-21)
- 新增 使用uni-id-pages的账号信息的状态管理功能
## 2.0.3(2022-09-20)
- 更新 依赖的`uni-ui`组件为最新版本(注意:该版本的`uni-form`相关组件将自定义节点设置成[虚拟节点](https://uniapp.dcloud.net.cn/tutorial/vue-api.html#%E5%85%B6%E4%BB%96%E9%85%8D%E7%BD%AE)))
- 更新 依赖的`uni_module`-> `uni-id-pages`为 v1.0.19版 修复 小程序端,使用将自定义节点设置成虚拟节点的uni-ui组件,导致的样式错乱问题
......
> 插件来源:[https://ext.dcloud.net.cn/plugin?id=1287](https://ext.dcloud.net.cn/plugin?id=1287)
##### 以下是作者写的插件介绍:
# uQRCode
### 云函数版二维码生成插件explain-qrcode现已发布,URL化后一句代码即可生成,有网就有二维码,100%生成成功,不会因为平台差异,设备差异导致生成失败,无需在前端做适配和兼容,极力推荐。插件地址:[explain-qrcode云函数二维码生成](https://ext.dcloud.net.cn/plugin?id=3359)
uQRCode 生成方式简单,可扩展性高,如有复杂需求可通过自定义组件或修改源码完成需求。已测试H5、微信小程序、iPhoneXsMax真机。
本示例项目中的自定义组件旨在抛砖引玉,有其他需求的朋友可自行扩展,自定义组件参考 ``/components/uni-qrcode/uni-qrcode.vue`` ,自定义组件使用案例参考 ``/pages/component/qrcode/qrcode.vue``
联系方式:QQ540000228。
最近一次用于更新代码的 HBuilder X 版本为 2.8.11。
### 二维码
**什么是QR码**
QR码属于矩阵式二维码中的一个种类,由DENSO(日本电装)公司开发,由JIS和ISO将其标准化。
**QR码的特点**
一是高速读取(QR就是取自“Quick Response”的首字母),通过摄像头从拍摄到解码到显示内容也就三秒左右,对摄像的角度也没有什么要求;
二是高容量、高密度,理论上内容经过压缩处理后可以存7089个数字,4296个字母和数字混合字符,2953个8位字节数据,1817个汉字;
三是支持纠错处理,按照QR码的标准文档说明,QR码的纠错分为4个级别,分别是:
- level L : 最大 7% 的错误能够被纠正;
- level M : 最大 15% 的错误能够被纠正;
- level Q : 最大 25% 的错误能够被纠正;
- level H : 最大 30% 的错误能够被纠正;
四是结构化,看似无规则的图形,其实对区域有严格的定义。
更多二维码介绍及原理:[https://blog.csdn.net/jason_ldh/article/details/11801355](https://blog.csdn.net/jason_ldh/article/details/11801355)
### 使用方式
``script`` 中引用组件
```javascript
import uQRCode from '@/common/uqrcode.js'
```
``template`` 中创建 ``<canvas></canvas>``
```html
<canvas canvas-id="qrcode" style="width: 354px;height: 354px;" ></canvas>
```
``script`` 中调用 ``make()`` 方法
```javascript
export default {
methods: {
async make() {
// 回调方式
uQRCode.make({
canvasId: 'qrcode',
componentInstance: this,
text: 'uQRCode',
size: 354,
margin: 10,
backgroundColor: '#ffffff',
foregroundColor: '#000000',
fileType: 'jpg',
errorCorrectLevel: uQRCode.errorCorrectLevel.H,
success: res => {
console.log(res)
}
})
// Promise
uQRCode.make({
canvasId: 'qrcode',
componentInstance: this,
text: 'uQRCode',
size: 354,
margin: 10,
backgroundColor: '#ffffff',
foregroundColor: '#000000',
fileType: 'jpg',
errorCorrectLevel: uQRCode.errorCorrectLevel.H
}).then(res => {
console.log(res)
})
// 同步等待
var res = await uQRCode.make({
canvasId: 'qrcode',
componentInstance: this,
text: 'uQRCode',
size: 354,
margin: 10,
backgroundColor: '#ffffff',
foregroundColor: '#000000',
fileType: 'jpg',
errorCorrectLevel: uQRCode.errorCorrectLevel.H
})
console.log(res)
}
}
}
```
### 属性说明
|属性名|说明|
|---|:---|
|errorCorrectLevel|纠错等级,包含 `errorCorrectLevel.L``errorCorrectLevel.M``errorCorrectLevel.Q``errorCorrectLevel.H` 四个级别,`L`: 最大 7% 的错误能够被纠正;`M`: 最大 15% 的错误能够被纠正;`Q`: 最大 25% 的错误能够被纠正;`H`: 最大 30% 的错误能够被纠正。|
|defaults|二维码生成参数的默认值。|
### 方法说明
|方法名|说明|
|---|:---|
|[make](#makeoptions)|生成二维码。|
### make(options)
生成二维码
**options参数说明:**
|参数|类型|必填|说明|
|---|---|---|:---|
|canvasId|String|是|画布标识,传入 `<canvas></canvas>``canvas-id`|
|componentInstance|Object|否|自定义组件实例 `this` ,表示在这个自定义组件下查找拥有 `canvas-id``<canvas></canvas>` ,如果省略,则不在任何自定义组件内查找|
|text|String|是|二维码内容|
|size|Number|否|画布尺寸大小,请与 `<canvas></canvas>` 所设 `width``height` 保持一致(默认:`354`)|
|margin|Number|否|边距,二维码实际尺寸会根据所设边距值进行缩放调整(默认:`0`)|
|backgroundColor|String|否|背景色,若设置为透明背景, `fileType` 需设置为 `'png'` , 然后设置背景色为 `'rgba(255,255,255,0)'` 即可(默认:`'#ffffff'`)|
|foregroundColor|String|否|前景色(默认:`'#000000'`)|
|fileType|String|否|输出图片的类型,只支持 `'jpg'``'png'`(默认:`'png'`)|
|errorCorrectLevel|Number|否|纠错等级,参考属性说明 `errorCorrectLevel`(默认:`errorCorrectLevel.H`)|
### 使用建议
canvas在二维码生成中请当做一个生成工具来看待,它的作用仅是绘制出二维码。应把生成回调得到的资源保存并使用,显示用image图片组件,原因是方便操作,例如调整大小,或是H5端长按保存或识别,所以canvas应将它放在看不见的地方。不能用`display:none;overflow:hidden;`隐藏,否则生成空白。这里推荐canvas的隐藏样式代码
```html
<style>
.canvas-hide {
/* 1 */
position: fixed;
right: 100vw;
bottom: 100vh;
/* 2 */
z-index: -9999;
/* 3 */
opacity: 0;
}
</style>
```
### 常见问题
**二维码生成不完整**
canvas宽高必须和size一致,并且size的单位是px,如果canvas的单位是rpx,那么不同设备屏幕分辨率不一样,rpx转换成px后的画布尺寸不足以放下全部内容,实际绘制图案超出,就会出现不完整的情况。
**如何扫码跳转指定网页**
text参数直接放入完整的网页地址即可,例如:`https://ext.dcloud.net.cn/plugin?id=1287`。微信客户端不能是ip地址。
**小程序、APP报错**
canvas不支持放在 `slot` 插槽,请尽量放在模板根节点,也就是第一个 `<view></view>` 标签里面
**H5长按识别**
canvas无法长按识别,长按识别需要是图片才行,所以只需将回调过来的资源用image组件显示即可。
### Tips
- 示例项目中的图片采集于互联网,仅作为案例展示,不作为广告/商业,如有侵权,请告知删除。下载使用的用户,请勿把示例项目中的图片应用到你的项目。
\ No newline at end of file
<template>
<view>
<canvas :id="cid" :canvas-id="cid" :style="{width: `${size}px`, height: `${size}px`}" />
</view>
</template>
<script>
import uQRCode from './uqrcode.js'
export default {
props: {
cid: {
type: String,
default(){
return Date.now()+Math.random()+'';
}
},
text: {
type: String,
required: true
},
size: {
type: Number,
default: uni.upx2px(200)
},
margin: {
type: Number,
default: 0
},
backgroundColor: {
type: String,
default: '#ffffff'
},
foregroundColor: {
type: String,
default: '#000000'
},
backgroundImage: {
type: String
},
logo: {
type: String
},
makeOnLoad: {
type: Boolean,
default: false
}
},
data() {
return {
}
},
mounted() {
if (this.makeOnLoad) {
this.make()
}
},
methods: {
async make() {
var options = {
canvasId: this.cid,
componentInstance: this,
text: this.text,
size: this.size,
margin: this.margin,
backgroundColor: this.backgroundImage ? 'rgba(255,255,255,0)' : this.backgroundColor,
foregroundColor: this.foregroundColor
}
var filePath = await this.makeSync(options)
if (this.backgroundImage) {
filePath = await this.drawBackgroundImageSync(filePath)
}
if (this.logo) {
filePath = await this.drawLogoSync(filePath)
}
this.makeComplete(filePath)
},
makeComplete(filePath) {
this.$emit('makeComplete', filePath)
},
drawBackgroundImage(options) {
var ctx = uni.createCanvasContext(this.cid, this)
ctx.drawImage(this.backgroundImage, 0, 0, this.size, this.size)
ctx.drawImage(options.filePath, 0, 0, this.size, this.size)
ctx.draw(false, () => {
uni.canvasToTempFilePath({
canvasId: this.cid,
success: res => {
options.success && options.success(res.tempFilePath)
},
fail: error => {
options.fail && options.fail(error)
}
}, this)
})
},
async drawBackgroundImageSync(filePath) {
return new Promise((resolve, reject) => {
this.drawBackgroundImage({
filePath: filePath,
success: res => {
resolve(res)
},
fail: error => {
reject(error)
}
})
})
},
fillRoundRect(ctx, r, x, y, w, h) {
ctx.save()
ctx.translate(x, y)
ctx.beginPath()
ctx.arc(w - r, h - r, r, 0, Math.PI / 2)
ctx.lineTo(r, h)
ctx.arc(r, h - r, r, Math.PI / 2, Math.PI)
ctx.lineTo(0, r)
ctx.arc(r, r, r, Math.PI, Math.PI * 3 / 2)
ctx.lineTo(w - r, 0)
ctx.arc(w - r, r, r, Math.PI * 3 / 2, Math.PI * 2)
ctx.lineTo(w, h - r)
ctx.closePath()
ctx.setFillStyle('#ffffff')
ctx.fill()
ctx.restore()
},
drawLogo(options) {
var ctx = uni.createCanvasContext(this.cid, this)
ctx.drawImage(options.filePath, 0, 0, this.size, this.size)
var logoSize = this.size / 4
var logoX = this.size / 2 - logoSize / 2
var logoY = logoX
var borderSize = logoSize + 10
var borderX = this.size / 2 - borderSize / 2
var borderY = borderX
var borderRadius = 5
this.fillRoundRect(ctx, borderRadius, borderX, borderY, borderSize, borderSize)
ctx.drawImage(this.logo, logoX, logoY, logoSize, logoSize)
ctx.draw(false, () => {
uni.canvasToTempFilePath({
canvasId: this.cid,
success: res => {
options.success && options.success(res.tempFilePath)
},
fail: error => {
options.fail && options.fail(error)
}
}, this)
})
},
async drawLogoSync(filePath) {
return new Promise((resolve, reject) => {
this.drawLogo({
filePath: filePath,
success: res => {
resolve(res)
},
fail: error => {
reject(error)
}
})
})
},
async makeSync(options) {
return new Promise((resolve, reject) => {
uQRCode.make({
canvasId: options.canvasId,
componentInstance: options.componentInstance,
text: options.text,
size: options.size,
margin: options.margin,
backgroundColor: options.backgroundColor,
foregroundColor: options.foregroundColor,
success: res => {
resolve(res)
},
fail: error => {
reject(error)
}
})
})
}
}
}
</script>
//---------------------------------------------------------------------
// github https://github.com/Sansnn/uQRCode
//---------------------------------------------------------------------
let uQRCode = {};
(function() {
//---------------------------------------------------------------------
// QRCode for JavaScript
//
// Copyright (c) 2009 Kazuhiko Arase
//
// URL: http://www.d-project.com/
//
// Licensed under the MIT license:
// http://www.opensource.org/licenses/mit-license.php
//
// The word "QR Code" is registered trademark of
// DENSO WAVE INCORPORATED
// http://www.denso-wave.com/qrcode/faqpatent-e.html
//
//---------------------------------------------------------------------
//---------------------------------------------------------------------
// QR8bitByte
//---------------------------------------------------------------------
function QR8bitByte(data) {
this.mode = QRMode.MODE_8BIT_BYTE;
this.data = data;
}
QR8bitByte.prototype = {
getLength: function(buffer) {
return this.data.length;
},
write: function(buffer) {
for (var i = 0; i < this.data.length; i++) {
// not JIS ...
buffer.put(this.data.charCodeAt(i), 8);
}
}
};
//---------------------------------------------------------------------
// QRCode
//---------------------------------------------------------------------
function QRCode(typeNumber, errorCorrectLevel) {
this.typeNumber = typeNumber;
this.errorCorrectLevel = errorCorrectLevel;
this.modules = null;
this.moduleCount = 0;
this.dataCache = null;
this.dataList = new Array();
}
QRCode.prototype = {
addData: function(data) {
var newData = new QR8bitByte(data);
this.dataList.push(newData);
this.dataCache = null;
},
isDark: function(row, col) {
if (row < 0 || this.moduleCount <= row || col < 0 || this.moduleCount <= col) {
throw new Error(row + "," + col);
}
return this.modules[row][col];
},
getModuleCount: function() {
return this.moduleCount;
},
make: function() {
// Calculate automatically typeNumber if provided is < 1
if (this.typeNumber < 1) {
var typeNumber = 1;
for (typeNumber = 1; typeNumber < 40; typeNumber++) {
var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, this.errorCorrectLevel);
var buffer = new QRBitBuffer();
var totalDataCount = 0;
for (var i = 0; i < rsBlocks.length; i++) {
totalDataCount += rsBlocks[i].dataCount;
}
for (var i = 0; i < this.dataList.length; i++) {
var data = this.dataList[i];
buffer.put(data.mode, 4);
buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber));
data.write(buffer);
}
if (buffer.getLengthInBits() <= totalDataCount * 8)
break;
}
this.typeNumber = typeNumber;
}
this.makeImpl(false, this.getBestMaskPattern());
},
makeImpl: function(test, maskPattern) {
this.moduleCount = this.typeNumber * 4 + 17;
this.modules = new Array(this.moduleCount);
for (var row = 0; row < this.moduleCount; row++) {
this.modules[row] = new Array(this.moduleCount);
for (var col = 0; col < this.moduleCount; col++) {
this.modules[row][col] = null; //(col + row) % 3;
}
}
this.setupPositionProbePattern(0, 0);
this.setupPositionProbePattern(this.moduleCount - 7, 0);
this.setupPositionProbePattern(0, this.moduleCount - 7);
this.setupPositionAdjustPattern();
this.setupTimingPattern();
this.setupTypeInfo(test, maskPattern);
if (this.typeNumber >= 7) {
this.setupTypeNumber(test);
}
if (this.dataCache == null) {
this.dataCache = QRCode.createData(this.typeNumber, this.errorCorrectLevel, this.dataList);
}
this.mapData(this.dataCache, maskPattern);
},
setupPositionProbePattern: function(row, col) {
for (var r = -1; r <= 7; r++) {
if (row + r <= -1 || this.moduleCount <= row + r) continue;
for (var c = -1; c <= 7; c++) {
if (col + c <= -1 || this.moduleCount <= col + c) continue;
if ((0 <= r && r <= 6 && (c == 0 || c == 6)) ||
(0 <= c && c <= 6 && (r == 0 || r == 6)) ||
(2 <= r && r <= 4 && 2 <= c && c <= 4)) {
this.modules[row + r][col + c] = true;
} else {
this.modules[row + r][col + c] = false;
}
}
}
},
getBestMaskPattern: function() {
var minLostPoint = 0;
var pattern = 0;
for (var i = 0; i < 8; i++) {
this.makeImpl(true, i);
var lostPoint = QRUtil.getLostPoint(this);
if (i == 0 || minLostPoint > lostPoint) {
minLostPoint = lostPoint;
pattern = i;
}
}
return pattern;
},
createMovieClip: function(target_mc, instance_name, depth) {
var qr_mc = target_mc.createEmptyMovieClip(instance_name, depth);
var cs = 1;
this.make();
for (var row = 0; row < this.modules.length; row++) {
var y = row * cs;
for (var col = 0; col < this.modules[row].length; col++) {
var x = col * cs;
var dark = this.modules[row][col];
if (dark) {
qr_mc.beginFill(0, 100);
qr_mc.moveTo(x, y);
qr_mc.lineTo(x + cs, y);
qr_mc.lineTo(x + cs, y + cs);
qr_mc.lineTo(x, y + cs);
qr_mc.endFill();
}
}
}
return qr_mc;
},
setupTimingPattern: function() {
for (var r = 8; r < this.moduleCount - 8; r++) {
if (this.modules[r][6] != null) {
continue;
}
this.modules[r][6] = (r % 2 == 0);
}
for (var c = 8; c < this.moduleCount - 8; c++) {
if (this.modules[6][c] != null) {
continue;
}
this.modules[6][c] = (c % 2 == 0);
}
},
setupPositionAdjustPattern: function() {
var pos = QRUtil.getPatternPosition(this.typeNumber);
for (var i = 0; i < pos.length; i++) {
for (var j = 0; j < pos.length; j++) {
var row = pos[i];
var col = pos[j];
if (this.modules[row][col] != null) {
continue;
}
for (var r = -2; r <= 2; r++) {
for (var c = -2; c <= 2; c++) {
if (r == -2 || r == 2 || c == -2 || c == 2 ||
(r == 0 && c == 0)) {
this.modules[row + r][col + c] = true;
} else {
this.modules[row + r][col + c] = false;
}
}
}
}
}
},
setupTypeNumber: function(test) {
var bits = QRUtil.getBCHTypeNumber(this.typeNumber);
for (var i = 0; i < 18; i++) {
var mod = (!test && ((bits >> i) & 1) == 1);
this.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 - 3] = mod;
}
for (var i = 0; i < 18; i++) {
var mod = (!test && ((bits >> i) & 1) == 1);
this.modules[i % 3 + this.moduleCount - 8 - 3][Math.floor(i / 3)] = mod;
}
},
setupTypeInfo: function(test, maskPattern) {
var data = (this.errorCorrectLevel << 3) | maskPattern;
var bits = QRUtil.getBCHTypeInfo(data);
// vertical
for (var i = 0; i < 15; i++) {
var mod = (!test && ((bits >> i) & 1) == 1);
if (i < 6) {
this.modules[i][8] = mod;
} else if (i < 8) {
this.modules[i + 1][8] = mod;
} else {
this.modules[this.moduleCount - 15 + i][8] = mod;
}
}
// horizontal
for (var i = 0; i < 15; i++) {
var mod = (!test && ((bits >> i) & 1) == 1);
if (i < 8) {
this.modules[8][this.moduleCount - i - 1] = mod;
} else if (i < 9) {
this.modules[8][15 - i - 1 + 1] = mod;
} else {
this.modules[8][15 - i - 1] = mod;
}
}
// fixed module
this.modules[this.moduleCount - 8][8] = (!test);
},
mapData: function(data, maskPattern) {
var inc = -1;
var row = this.moduleCount - 1;
var bitIndex = 7;
var byteIndex = 0;
for (var col = this.moduleCount - 1; col > 0; col -= 2) {
if (col == 6) col--;
while (true) {
for (var c = 0; c < 2; c++) {
if (this.modules[row][col - c] == null) {
var dark = false;
if (byteIndex < data.length) {
dark = (((data[byteIndex] >>> bitIndex) & 1) == 1);
}
var mask = QRUtil.getMask(maskPattern, row, col - c);
if (mask) {
dark = !dark;
}
this.modules[row][col - c] = dark;
bitIndex--;
if (bitIndex == -1) {
byteIndex++;
bitIndex = 7;
}
}
}
row += inc;
if (row < 0 || this.moduleCount <= row) {
row -= inc;
inc = -inc;
break;
}
}
}
}
};
QRCode.PAD0 = 0xEC;
QRCode.PAD1 = 0x11;
QRCode.createData = function(typeNumber, errorCorrectLevel, dataList) {
var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel);
var buffer = new QRBitBuffer();
for (var i = 0; i < dataList.length; i++) {
var data = dataList[i];
buffer.put(data.mode, 4);
buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber));
data.write(buffer);
}
// calc num max data.
var totalDataCount = 0;
for (var i = 0; i < rsBlocks.length; i++) {
totalDataCount += rsBlocks[i].dataCount;
}
if (buffer.getLengthInBits() > totalDataCount * 8) {
throw new Error("code length overflow. (" +
buffer.getLengthInBits() +
">" +
totalDataCount * 8 +
")");
}
// end code
if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
buffer.put(0, 4);
}
// padding
while (buffer.getLengthInBits() % 8 != 0) {
buffer.putBit(false);
}
// padding
while (true) {
if (buffer.getLengthInBits() >= totalDataCount * 8) {
break;
}
buffer.put(QRCode.PAD0, 8);
if (buffer.getLengthInBits() >= totalDataCount * 8) {
break;
}
buffer.put(QRCode.PAD1, 8);
}
return QRCode.createBytes(buffer, rsBlocks);
}
QRCode.createBytes = function(buffer, rsBlocks) {
var offset = 0;
var maxDcCount = 0;
var maxEcCount = 0;
var dcdata = new Array(rsBlocks.length);
var ecdata = new Array(rsBlocks.length);
for (var r = 0; r < rsBlocks.length; r++) {
var dcCount = rsBlocks[r].dataCount;
var ecCount = rsBlocks[r].totalCount - dcCount;
maxDcCount = Math.max(maxDcCount, dcCount);
maxEcCount = Math.max(maxEcCount, ecCount);
dcdata[r] = new Array(dcCount);
for (var i = 0; i < dcdata[r].length; i++) {
dcdata[r][i] = 0xff & buffer.buffer[i + offset];
}
offset += dcCount;
var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
var rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() - 1);
var modPoly = rawPoly.mod(rsPoly);
ecdata[r] = new Array(rsPoly.getLength() - 1);
for (var i = 0; i < ecdata[r].length; i++) {
var modIndex = i + modPoly.getLength() - ecdata[r].length;
ecdata[r][i] = (modIndex >= 0) ? modPoly.get(modIndex) : 0;
}
}
var totalCodeCount = 0;
for (var i = 0; i < rsBlocks.length; i++) {
totalCodeCount += rsBlocks[i].totalCount;
}
var data = new Array(totalCodeCount);
var index = 0;
for (var i = 0; i < maxDcCount; i++) {
for (var r = 0; r < rsBlocks.length; r++) {
if (i < dcdata[r].length) {
data[index++] = dcdata[r][i];
}
}
}
for (var i = 0; i < maxEcCount; i++) {
for (var r = 0; r < rsBlocks.length; r++) {
if (i < ecdata[r].length) {
data[index++] = ecdata[r][i];
}
}
}
return data;
}
//---------------------------------------------------------------------
// QRMode
//---------------------------------------------------------------------
var QRMode = {
MODE_NUMBER: 1 << 0,
MODE_ALPHA_NUM: 1 << 1,
MODE_8BIT_BYTE: 1 << 2,
MODE_KANJI: 1 << 3
};
//---------------------------------------------------------------------
// QRErrorCorrectLevel
//---------------------------------------------------------------------
var QRErrorCorrectLevel = {
L: 1,
M: 0,
Q: 3,
H: 2
};
//---------------------------------------------------------------------
// QRMaskPattern
//---------------------------------------------------------------------
var QRMaskPattern = {
PATTERN000: 0,
PATTERN001: 1,
PATTERN010: 2,
PATTERN011: 3,
PATTERN100: 4,
PATTERN101: 5,
PATTERN110: 6,
PATTERN111: 7
};
//---------------------------------------------------------------------
// QRUtil
//---------------------------------------------------------------------
var QRUtil = {
PATTERN_POSITION_TABLE: [
[],
[6, 18],
[6, 22],
[6, 26],
[6, 30],
[6, 34],
[6, 22, 38],
[6, 24, 42],
[6, 26, 46],
[6, 28, 50],
[6, 30, 54],
[6, 32, 58],
[6, 34, 62],
[6, 26, 46, 66],
[6, 26, 48, 70],
[6, 26, 50, 74],
[6, 30, 54, 78],
[6, 30, 56, 82],
[6, 30, 58, 86],
[6, 34, 62, 90],
[6, 28, 50, 72, 94],
[6, 26, 50, 74, 98],
[6, 30, 54, 78, 102],
[6, 28, 54, 80, 106],
[6, 32, 58, 84, 110],
[6, 30, 58, 86, 114],
[6, 34, 62, 90, 118],
[6, 26, 50, 74, 98, 122],
[6, 30, 54, 78, 102, 126],
[6, 26, 52, 78, 104, 130],
[6, 30, 56, 82, 108, 134],
[6, 34, 60, 86, 112, 138],
[6, 30, 58, 86, 114, 142],
[6, 34, 62, 90, 118, 146],
[6, 30, 54, 78, 102, 126, 150],
[6, 24, 50, 76, 102, 128, 154],
[6, 28, 54, 80, 106, 132, 158],
[6, 32, 58, 84, 110, 136, 162],
[6, 26, 54, 82, 110, 138, 166],
[6, 30, 58, 86, 114, 142, 170]
],
G15: (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0),
G18: (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0),
G15_MASK: (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1),
getBCHTypeInfo: function(data) {
var d = data << 10;
while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) {
d ^= (QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15)));
}
return ((data << 10) | d) ^ QRUtil.G15_MASK;
},
getBCHTypeNumber: function(data) {
var d = data << 12;
while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) {
d ^= (QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18)));
}
return (data << 12) | d;
},
getBCHDigit: function(data) {
var digit = 0;
while (data != 0) {
digit++;
data >>>= 1;
}
return digit;
},
getPatternPosition: function(typeNumber) {
return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1];
},
getMask: function(maskPattern, i, j) {
switch (maskPattern) {
case QRMaskPattern.PATTERN000:
return (i + j) % 2 == 0;
case QRMaskPattern.PATTERN001:
return i % 2 == 0;
case QRMaskPattern.PATTERN010:
return j % 3 == 0;
case QRMaskPattern.PATTERN011:
return (i + j) % 3 == 0;
case QRMaskPattern.PATTERN100:
return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0;
case QRMaskPattern.PATTERN101:
return (i * j) % 2 + (i * j) % 3 == 0;
case QRMaskPattern.PATTERN110:
return ((i * j) % 2 + (i * j) % 3) % 2 == 0;
case QRMaskPattern.PATTERN111:
return ((i * j) % 3 + (i + j) % 2) % 2 == 0;
default:
throw new Error("bad maskPattern:" + maskPattern);
}
},
getErrorCorrectPolynomial: function(errorCorrectLength) {
var a = new QRPolynomial([1], 0);
for (var i = 0; i < errorCorrectLength; i++) {
a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0));
}
return a;
},
getLengthInBits: function(mode, type) {
if (1 <= type && type < 10) {
// 1 - 9
switch (mode) {
case QRMode.MODE_NUMBER:
return 10;
case QRMode.MODE_ALPHA_NUM:
return 9;
case QRMode.MODE_8BIT_BYTE:
return 8;
case QRMode.MODE_KANJI:
return 8;
default:
throw new Error("mode:" + mode);
}
} else if (type < 27) {
// 10 - 26
switch (mode) {
case QRMode.MODE_NUMBER:
return 12;
case QRMode.MODE_ALPHA_NUM:
return 11;
case QRMode.MODE_8BIT_BYTE:
return 16;
case QRMode.MODE_KANJI:
return 10;
default:
throw new Error("mode:" + mode);
}
} else if (type < 41) {
// 27 - 40
switch (mode) {
case QRMode.MODE_NUMBER:
return 14;
case QRMode.MODE_ALPHA_NUM:
return 13;
case QRMode.MODE_8BIT_BYTE:
return 16;
case QRMode.MODE_KANJI:
return 12;
default:
throw new Error("mode:" + mode);
}
} else {
throw new Error("type:" + type);
}
},
getLostPoint: function(qrCode) {
var moduleCount = qrCode.getModuleCount();
var lostPoint = 0;
// LEVEL1
for (var row = 0; row < moduleCount; row++) {
for (var col = 0; col < moduleCount; col++) {
var sameCount = 0;
var dark = qrCode.isDark(row, col);
for (var r = -1; r <= 1; r++) {
if (row + r < 0 || moduleCount <= row + r) {
continue;
}
for (var c = -1; c <= 1; c++) {
if (col + c < 0 || moduleCount <= col + c) {
continue;
}
if (r == 0 && c == 0) {
continue;
}
if (dark == qrCode.isDark(row + r, col + c)) {
sameCount++;
}
}
}
if (sameCount > 5) {
lostPoint += (3 + sameCount - 5);
}
}
}
// LEVEL2
for (var row = 0; row < moduleCount - 1; row++) {
for (var col = 0; col < moduleCount - 1; col++) {
var count = 0;
if (qrCode.isDark(row, col)) count++;
if (qrCode.isDark(row + 1, col)) count++;
if (qrCode.isDark(row, col + 1)) count++;
if (qrCode.isDark(row + 1, col + 1)) count++;
if (count == 0 || count == 4) {
lostPoint += 3;
}
}
}
// LEVEL3
for (var row = 0; row < moduleCount; row++) {
for (var col = 0; col < moduleCount - 6; col++) {
if (qrCode.isDark(row, col) &&
!qrCode.isDark(row, col + 1) &&
qrCode.isDark(row, col + 2) &&
qrCode.isDark(row, col + 3) &&
qrCode.isDark(row, col + 4) &&
!qrCode.isDark(row, col + 5) &&
qrCode.isDark(row, col + 6)) {
lostPoint += 40;
}
}
}
for (var col = 0; col < moduleCount; col++) {
for (var row = 0; row < moduleCount - 6; row++) {
if (qrCode.isDark(row, col) &&
!qrCode.isDark(row + 1, col) &&
qrCode.isDark(row + 2, col) &&
qrCode.isDark(row + 3, col) &&
qrCode.isDark(row + 4, col) &&
!qrCode.isDark(row + 5, col) &&
qrCode.isDark(row + 6, col)) {
lostPoint += 40;
}
}
}
// LEVEL4
var darkCount = 0;
for (var col = 0; col < moduleCount; col++) {
for (var row = 0; row < moduleCount; row++) {
if (qrCode.isDark(row, col)) {
darkCount++;
}
}
}
var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;
lostPoint += ratio * 10;
return lostPoint;
}
};
//---------------------------------------------------------------------
// QRMath
//---------------------------------------------------------------------
var QRMath = {
glog: function(n) {
if (n < 1) {
throw new Error("glog(" + n + ")");
}
return QRMath.LOG_TABLE[n];
},
gexp: function(n) {
while (n < 0) {
n += 255;
}
while (n >= 256) {
n -= 255;
}
return QRMath.EXP_TABLE[n];
},
EXP_TABLE: new Array(256),
LOG_TABLE: new Array(256)
};
for (var i = 0; i < 8; i++) {
QRMath.EXP_TABLE[i] = 1 << i;
}
for (var i = 8; i < 256; i++) {
QRMath.EXP_TABLE[i] = QRMath.EXP_TABLE[i - 4] ^
QRMath.EXP_TABLE[i - 5] ^
QRMath.EXP_TABLE[i - 6] ^
QRMath.EXP_TABLE[i - 8];
}
for (var i = 0; i < 255; i++) {
QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]] = i;
}
//---------------------------------------------------------------------
// QRPolynomial
//---------------------------------------------------------------------
function QRPolynomial(num, shift) {
if (num.length == undefined) {
throw new Error(num.length + "/" + shift);
}
var offset = 0;
while (offset < num.length && num[offset] == 0) {
offset++;
}
this.num = new Array(num.length - offset + shift);
for (var i = 0; i < num.length - offset; i++) {
this.num[i] = num[i + offset];
}
}
QRPolynomial.prototype = {
get: function(index) {
return this.num[index];
},
getLength: function() {
return this.num.length;
},
multiply: function(e) {
var num = new Array(this.getLength() + e.getLength() - 1);
for (var i = 0; i < this.getLength(); i++) {
for (var j = 0; j < e.getLength(); j++) {
num[i + j] ^= QRMath.gexp(QRMath.glog(this.get(i)) + QRMath.glog(e.get(j)));
}
}
return new QRPolynomial(num, 0);
},
mod: function(e) {
if (this.getLength() - e.getLength() < 0) {
return this;
}
var ratio = QRMath.glog(this.get(0)) - QRMath.glog(e.get(0));
var num = new Array(this.getLength());
for (var i = 0; i < this.getLength(); i++) {
num[i] = this.get(i);
}
for (var i = 0; i < e.getLength(); i++) {
num[i] ^= QRMath.gexp(QRMath.glog(e.get(i)) + ratio);
}
// recursive call
return new QRPolynomial(num, 0).mod(e);
}
};
//---------------------------------------------------------------------
// QRRSBlock
//---------------------------------------------------------------------
function QRRSBlock(totalCount, dataCount) {
this.totalCount = totalCount;
this.dataCount = dataCount;
}
QRRSBlock.RS_BLOCK_TABLE = [
// L
// M
// Q
// H
// 1
[1, 26, 19],
[1, 26, 16],
[1, 26, 13],
[1, 26, 9],
// 2
[1, 44, 34],
[1, 44, 28],
[1, 44, 22],
[1, 44, 16],
// 3
[1, 70, 55],
[1, 70, 44],
[2, 35, 17],
[2, 35, 13],
// 4
[1, 100, 80],
[2, 50, 32],
[2, 50, 24],
[4, 25, 9],
// 5
[1, 134, 108],
[2, 67, 43],
[2, 33, 15, 2, 34, 16],
[2, 33, 11, 2, 34, 12],
// 6
[2, 86, 68],
[4, 43, 27],
[4, 43, 19],
[4, 43, 15],
// 7
[2, 98, 78],
[4, 49, 31],
[2, 32, 14, 4, 33, 15],
[4, 39, 13, 1, 40, 14],
// 8
[2, 121, 97],
[2, 60, 38, 2, 61, 39],
[4, 40, 18, 2, 41, 19],
[4, 40, 14, 2, 41, 15],
// 9
[2, 146, 116],
[3, 58, 36, 2, 59, 37],
[4, 36, 16, 4, 37, 17],
[4, 36, 12, 4, 37, 13],
// 10
[2, 86, 68, 2, 87, 69],
[4, 69, 43, 1, 70, 44],
[6, 43, 19, 2, 44, 20],
[6, 43, 15, 2, 44, 16],
// 11
[4, 101, 81],
[1, 80, 50, 4, 81, 51],
[4, 50, 22, 4, 51, 23],
[3, 36, 12, 8, 37, 13],
// 12
[2, 116, 92, 2, 117, 93],
[6, 58, 36, 2, 59, 37],
[4, 46, 20, 6, 47, 21],
[7, 42, 14, 4, 43, 15],
// 13
[4, 133, 107],
[8, 59, 37, 1, 60, 38],
[8, 44, 20, 4, 45, 21],
[12, 33, 11, 4, 34, 12],
// 14
[3, 145, 115, 1, 146, 116],
[4, 64, 40, 5, 65, 41],
[11, 36, 16, 5, 37, 17],
[11, 36, 12, 5, 37, 13],
// 15
[5, 109, 87, 1, 110, 88],
[5, 65, 41, 5, 66, 42],
[5, 54, 24, 7, 55, 25],
[11, 36, 12],
// 16
[5, 122, 98, 1, 123, 99],
[7, 73, 45, 3, 74, 46],
[15, 43, 19, 2, 44, 20],
[3, 45, 15, 13, 46, 16],
// 17
[1, 135, 107, 5, 136, 108],
[10, 74, 46, 1, 75, 47],
[1, 50, 22, 15, 51, 23],
[2, 42, 14, 17, 43, 15],
// 18
[5, 150, 120, 1, 151, 121],
[9, 69, 43, 4, 70, 44],
[17, 50, 22, 1, 51, 23],
[2, 42, 14, 19, 43, 15],
// 19
[3, 141, 113, 4, 142, 114],
[3, 70, 44, 11, 71, 45],
[17, 47, 21, 4, 48, 22],
[9, 39, 13, 16, 40, 14],
// 20
[3, 135, 107, 5, 136, 108],
[3, 67, 41, 13, 68, 42],
[15, 54, 24, 5, 55, 25],
[15, 43, 15, 10, 44, 16],
// 21
[4, 144, 116, 4, 145, 117],
[17, 68, 42],
[17, 50, 22, 6, 51, 23],
[19, 46, 16, 6, 47, 17],
// 22
[2, 139, 111, 7, 140, 112],
[17, 74, 46],
[7, 54, 24, 16, 55, 25],
[34, 37, 13],
// 23
[4, 151, 121, 5, 152, 122],
[4, 75, 47, 14, 76, 48],
[11, 54, 24, 14, 55, 25],
[16, 45, 15, 14, 46, 16],
// 24
[6, 147, 117, 4, 148, 118],
[6, 73, 45, 14, 74, 46],
[11, 54, 24, 16, 55, 25],
[30, 46, 16, 2, 47, 17],
// 25
[8, 132, 106, 4, 133, 107],
[8, 75, 47, 13, 76, 48],
[7, 54, 24, 22, 55, 25],
[22, 45, 15, 13, 46, 16],
// 26
[10, 142, 114, 2, 143, 115],
[19, 74, 46, 4, 75, 47],
[28, 50, 22, 6, 51, 23],
[33, 46, 16, 4, 47, 17],
// 27
[8, 152, 122, 4, 153, 123],
[22, 73, 45, 3, 74, 46],
[8, 53, 23, 26, 54, 24],
[12, 45, 15, 28, 46, 16],
// 28
[3, 147, 117, 10, 148, 118],
[3, 73, 45, 23, 74, 46],
[4, 54, 24, 31, 55, 25],
[11, 45, 15, 31, 46, 16],
// 29
[7, 146, 116, 7, 147, 117],
[21, 73, 45, 7, 74, 46],
[1, 53, 23, 37, 54, 24],
[19, 45, 15, 26, 46, 16],
// 30
[5, 145, 115, 10, 146, 116],
[19, 75, 47, 10, 76, 48],
[15, 54, 24, 25, 55, 25],
[23, 45, 15, 25, 46, 16],
// 31
[13, 145, 115, 3, 146, 116],
[2, 74, 46, 29, 75, 47],
[42, 54, 24, 1, 55, 25],
[23, 45, 15, 28, 46, 16],
// 32
[17, 145, 115],
[10, 74, 46, 23, 75, 47],
[10, 54, 24, 35, 55, 25],
[19, 45, 15, 35, 46, 16],
// 33
[17, 145, 115, 1, 146, 116],
[14, 74, 46, 21, 75, 47],
[29, 54, 24, 19, 55, 25],
[11, 45, 15, 46, 46, 16],
// 34
[13, 145, 115, 6, 146, 116],
[14, 74, 46, 23, 75, 47],
[44, 54, 24, 7, 55, 25],
[59, 46, 16, 1, 47, 17],
// 35
[12, 151, 121, 7, 152, 122],
[12, 75, 47, 26, 76, 48],
[39, 54, 24, 14, 55, 25],
[22, 45, 15, 41, 46, 16],
// 36
[6, 151, 121, 14, 152, 122],
[6, 75, 47, 34, 76, 48],
[46, 54, 24, 10, 55, 25],
[2, 45, 15, 64, 46, 16],
// 37
[17, 152, 122, 4, 153, 123],
[29, 74, 46, 14, 75, 47],
[49, 54, 24, 10, 55, 25],
[24, 45, 15, 46, 46, 16],
// 38
[4, 152, 122, 18, 153, 123],
[13, 74, 46, 32, 75, 47],
[48, 54, 24, 14, 55, 25],
[42, 45, 15, 32, 46, 16],
// 39
[20, 147, 117, 4, 148, 118],
[40, 75, 47, 7, 76, 48],
[43, 54, 24, 22, 55, 25],
[10, 45, 15, 67, 46, 16],
// 40
[19, 148, 118, 6, 149, 119],
[18, 75, 47, 31, 76, 48],
[34, 54, 24, 34, 55, 25],
[20, 45, 15, 61, 46, 16]
];
QRRSBlock.getRSBlocks = function(typeNumber, errorCorrectLevel) {
var rsBlock = QRRSBlock.getRsBlockTable(typeNumber, errorCorrectLevel);
if (rsBlock == undefined) {
throw new Error("bad rs block @ typeNumber:" + typeNumber + "/errorCorrectLevel:" + errorCorrectLevel);
}
var length = rsBlock.length / 3;
var list = new Array();
for (var i = 0; i < length; i++) {
var count = rsBlock[i * 3 + 0];
var totalCount = rsBlock[i * 3 + 1];
var dataCount = rsBlock[i * 3 + 2];
for (var j = 0; j < count; j++) {
list.push(new QRRSBlock(totalCount, dataCount));
}
}
return list;
}
QRRSBlock.getRsBlockTable = function(typeNumber, errorCorrectLevel) {
switch (errorCorrectLevel) {
case QRErrorCorrectLevel.L:
return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];
case QRErrorCorrectLevel.M:
return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];
case QRErrorCorrectLevel.Q:
return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];
case QRErrorCorrectLevel.H:
return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];
default:
return undefined;
}
}
//---------------------------------------------------------------------
// QRBitBuffer
//---------------------------------------------------------------------
function QRBitBuffer() {
this.buffer = new Array();
this.length = 0;
}
QRBitBuffer.prototype = {
get: function(index) {
var bufIndex = Math.floor(index / 8);
return ((this.buffer[bufIndex] >>> (7 - index % 8)) & 1) == 1;
},
put: function(num, length) {
for (var i = 0; i < length; i++) {
this.putBit(((num >>> (length - i - 1)) & 1) == 1);
}
},
getLengthInBits: function() {
return this.length;
},
putBit: function(bit) {
var bufIndex = Math.floor(this.length / 8);
if (this.buffer.length <= bufIndex) {
this.buffer.push(0);
}
if (bit) {
this.buffer[bufIndex] |= (0x80 >>> (this.length % 8));
}
this.length++;
}
};
//---------------------------------------------------------------------
// Support Chinese
//---------------------------------------------------------------------
function utf16To8(text) {
var result = '';
var c;
for (var i = 0; i < text.length; i++) {
c = text.charCodeAt(i);
if (c >= 0x0001 && c <= 0x007F) {
result += text.charAt(i);
} else if (c > 0x07FF) {
result += String.fromCharCode(0xE0 | c >> 12 & 0x0F);
result += String.fromCharCode(0x80 | c >> 6 & 0x3F);
result += String.fromCharCode(0x80 | c >> 0 & 0x3F);
} else {
result += String.fromCharCode(0xC0 | c >> 6 & 0x1F);
result += String.fromCharCode(0x80 | c >> 0 & 0x3F);
}
}
return result;
}
uQRCode = {
errorCorrectLevel: QRErrorCorrectLevel,
defaults: {
size: 354,
margin: 0,
backgroundColor: '#ffffff',
foregroundColor: '#000000',
fileType: 'png', // 'jpg', 'png'
errorCorrectLevel: QRErrorCorrectLevel.H,
typeNumber: -1
},
make: function(options) {
return new Promise((reslove, reject) => {
var defaultOptions = {
canvasId: options.canvasId,
componentInstance: options.componentInstance,
text: options.text,
size: this.defaults.size,
margin: this.defaults.margin,
backgroundColor: this.defaults.backgroundColor,
foregroundColor: this.defaults.foregroundColor,
fileType: this.defaults.fileType,
errorCorrectLevel: this.defaults.errorCorrectLevel,
typeNumber: this.defaults.typeNumber
};
if (options) {
for (var i in options) {
defaultOptions[i] = options[i];
}
}
options = defaultOptions;
if (!options.canvasId) {
console.error('uQRCode: Please set canvasId!');
return;
}
function createCanvas() {
var qrcode = new QRCode(options.typeNumber, options.errorCorrectLevel);
qrcode.addData(utf16To8(options.text));
qrcode.make();
var ctx = uni.createCanvasContext(options.canvasId, options.componentInstance);
ctx.setFillStyle(options.backgroundColor);
ctx.fillRect(0, 0, options.size, options.size);
var tileW = (options.size - options.margin * 2) / qrcode.getModuleCount();
var tileH = tileW;
for (var row = 0; row < qrcode.getModuleCount(); row++) {
for (var col = 0; col < qrcode.getModuleCount(); col++) {
var style = qrcode.isDark(row, col) ? options.foregroundColor : options.backgroundColor;
ctx.setFillStyle(style);
var x = Math.round(col * tileW) + options.margin;
var y = Math.round(row * tileH) + options.margin;
var w = Math.ceil((col + 1) * tileW) - Math.floor(col * tileW);
var h = Math.ceil((row + 1) * tileW) - Math.floor(row * tileW);
ctx.fillRect(x, y, w, h);
}
}
setTimeout(function() {
ctx.draw(false, (function() {
setTimeout(function() {
uni.canvasToTempFilePath({
canvasId: options.canvasId,
fileType: options.fileType,
width: options.size,
height: options.size,
destWidth: options.size,
destHeight: options.size,
success: function(res) {
let resData; // 将统一为base64格式
let tempFilePath = res.tempFilePath; // H5为base64,其他为相对路径
// #ifdef H5
resData = tempFilePath;
options.success && options.success(resData);
reslove(resData);
// #endif
// #ifdef APP-PLUS
const path = plus.io.convertLocalFileSystemURL(tempFilePath) // 绝对路径
let fileReader = new plus.io.FileReader();
fileReader.readAsDataURL(path);
fileReader.onloadend = res => {
resData = res.target.result;
options.success && options.success(resData);
reslove(resData);
};
// #endif
// #ifdef MP-WEIXIN || MP-QQ || MP-TOUTIAO
uni.getFileSystemManager().readFile({
filePath: tempFilePath,
encoding: 'base64',
success: res => {
resData = 'data:image/png;base64,' + res.data;
options.success && options.success(resData);
reslove(resData);
}
})
// #endif
// #ifndef H5 || APP-PLUS || MP-WEIXIN || MP-QQ || MP-TOUTIAO
if (plus) {
const path = plus.io.convertLocalFileSystemURL(tempFilePath) // 绝对路径
let fileReader = new plus.io.FileReader();
fileReader.readAsDataURL(path);
fileReader.onloadend = res => {
resData = res.target.result;
options.success && options.success(resData);
reslove(resData);
};
} else {
uni.request({
url: tempFilePath,
method: 'GET',
responseType: 'arraybuffer',
success: res => {
resData = `data:image/png;base64,${uni.arrayBufferToBase64(res.data)}`; // 把arraybuffer转成base64
options.success && options.success(resData);
reslove(resData);
}
})
}
// #endif
},
fail: function(error) {
options.fail && options.fail(error);
reject(error);
},
complete: function(res) {
options.complete && options.complete(res);
}
}, options.componentInstance);
}, options.text.length + 100);
})());
}, 150);
}
createCanvas();
});
}
}
})()
export default uQRCode
<template>
<view class="uni-section" nvue>
<view v-if="type" class="uni-section__head">
<view :class="type" class="uni-section__head-tag" />
</view>
<view class="uni-section__content">
<text :class="{'distraction':!subTitle}" class="uni-section__content-title">{{ title }}</text>
<text v-if="subTitle" class="uni-section__content-sub">{{ subTitle }}</text>
</view>
<slot />
</view>
</template>
<script>
/**
* Section 标题栏
* @description 标题栏
* @property {String} type = [line|circle] 标题装饰类型
* @value line 竖线
* @value circle 圆形
* @property {String} title 主标题
* @property {String} subTitle 副标题
*/
export default {
name: 'UniSection',
props: {
type: {
type: String,
default: ''
},
title: {
type: String,
default: ''
},
subTitle: {
type: String,
default: ''
}
},
data() {
return {}
},
watch: {
title(newVal) {
if (uni.report && newVal !== '') {
uni.report('title', newVal)
}
}
},
methods: {
onClick() {
this.$emit('click')
}
}
}
</script>
<style lang="scss" scoped>
.uni-section {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
margin-top: 10px;
flex-direction: row;
align-items: center;
padding: 0 10px;
height: 50px;
background-color: $uni-bg-color-grey;
/* #ifdef APP-NVUE */
// border-bottom-color: $uni-border-color;
// border-bottom-style: solid;
// border-bottom-width: 0.5px;
/* #endif */
font-weight: normal;
}
/* #ifndef APP-NVUE */
// .uni-section:after {
// position: absolute;
// bottom: 0;
// right: 0;
// left: 0;
// height: 1px;
// content: '';
// -webkit-transform: scaleY(.5);
// transform: scaleY(.5);
// background-color: $uni-border-color;
// }
/* #endif */
.uni-section__head {
flex-direction: row;
justify-content: center;
align-items: center;
margin-right: 10px;
}
.line {
height: 15px;
background-color: $uni-text-color-disable;
border-radius: 5px;
width: 3px;
}
.circle {
width: 8px;
height: 8px;
border-top-right-radius: 50px;
border-top-left-radius: 50px;
border-bottom-left-radius: 50px;
border-bottom-right-radius: 50px;
background-color: $uni-text-color-disable;
}
.uni-section__content {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
flex: 1;
color: $uni-text-color;
}
.uni-section__content-title {
font-size: $uni-font-size-base;
color: $uni-text-color;
}
.distraction {
flex-direction: row;
align-items: center;
}
.uni-section__content-sub {
font-size: $uni-font-size-sm;
color: $uni-text-color-grey;
}
</style>
{
"id": "uni-starter",
"displayName": "uni-starter",
"version": "2.0.3",
"version": "2.0.4",
"description": "云端一体应用快速开发基本项目模版",
"keywords": [
"login",
......@@ -14,8 +14,8 @@
"engines": {
"HBuilderX": "^3.2.6"
},
"dcloudext": {
"sale": {
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
},
......@@ -31,11 +31,11 @@
"data": "无",
"permissions": "无"
},
"npmurl": "",
"type": "unicloud-template-project"
"npmurl": "",
"type": "unicloud-template-project"
},
"uni_modules": {
"dependencies": [
"dependencies": [
"uni-id-pages"
],
"encrypt": [],
......@@ -67,8 +67,8 @@
"阿里": "u",
"百度": "u",
"字节跳动": "u",
"QQ": "u",
"京东": "u"
"QQ": "u",
"京东": "u"
},
"快应用": {
"华为": "u",
......@@ -81,5 +81,7 @@
}
}
},
"dependencies": {}
"dependencies": {
"qrcodejs2": "^0.0.2"
}
}
......@@ -122,13 +122,13 @@
"style": {
"navigationBarTitleText": "注销账号"
}
},
{
"path": "uni_modules/uni-id-pages/pages/userinfo/userinfo",
"style": {
"navigationBarTitleText": "个人资料"
}
},{
},
{
"path": "uni_modules/uni-id-pages/pages/userinfo/userinfo",
"style": {
"navigationBarTitleText": "个人资料"
}
}, {
"path": "uni_modules/uni-id-pages/pages/userinfo/bind-mobile/bind-mobile",
"style": {
"navigationBarTitleText": "绑定手机号码"
......@@ -175,33 +175,30 @@
"enablePullDownRefresh": false,
"navigationBarTitleText": "修改密码"
}
}, {
"path": "uni_modules/uni-id-pages/pages/register/register-by-email",
"style": {
"navigationBarTitleText": "邮箱验证码注册"
}
}, {
"path": "uni_modules/uni-id-pages/pages/retrieve/retrieve-by-email",
"style": {
"navigationBarTitleText": "通过邮箱重置密码"
}
}, {
"path": "uni_modules/uni-id-pages/pages/register/register-admin",
"style": {
"enablePullDownRefresh": false,
"navigationBarTitleText": "注册管理员账号"
}
}
,{
"path": "uni_modules/uni-id-pages/pages/register/register-by-email",
"style": {
"navigationBarTitleText": "邮箱验证码注册"
}
}
,{
"path": "uni_modules/uni-id-pages/pages/retrieve/retrieve-by-email",
"style": {
"navigationBarTitleText": "通过邮箱重置密码"
}
}
,{
"path": "uni_modules/uni-id-pages/pages/register/register-admin",
"style": {
"enablePullDownRefresh": false,
"navigationBarTitleText": "注册管理员账号"
}
}
],
"globalStyle": {
// #ifdef H5
"h5": {
"titleNView":false
},
// #endif
],
"globalStyle": {
// #ifdef H5
"h5": {
"titleNView": false
},
// #endif
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-starter",
"navigationBarBackgroundColor": "#FFFFFF",
......@@ -245,12 +242,12 @@
"selectedIconPath": "static/tabbar/me_active.png",
"text": "我的"
}]
},
"uniIdRouter": {
"loginPage": "uni_modules/uni-id-pages/pages/login/login-withoutpwd",
"needLogin": [
"/uni_modules/uni-id-pages/pages/userinfo/userinfo"
],
"resToLogin": true
},
"uniIdRouter": {
"loginPage": "uni_modules/uni-id-pages/pages/login/login-withoutpwd",
"needLogin": [
"/uni_modules/uni-id-pages/pages/userinfo/userinfo"
],
"resToLogin": true
}
}
......@@ -2,39 +2,39 @@
<view class="warp">
<!-- #ifdef APP-PLUS -->
<status-bar />
<!-- #endif -->
<!-- #endif -->
<!-- banner -->
<unicloud-db ref="bannerdb" v-slot:default="{data, loading, error, options}" collection="opendb-banner"
field="_id,bannerfile,open_url,title" @load="onqueryload">
<!-- 当无banner数据时显示占位图 -->
<image v-if="!(loading||data.length)" class="banner-image" src="/static/grid/empty.png" mode="aspectFill" :draggable="false" />
<uni-swiper-dot v-else class="uni-swiper-dot-box" @clickItem="clickItem" :info="data"
:current="current" field="content">
<swiper class="swiper-box" @change="changeSwiper" :current="swiperDotIndex">
<swiper-item v-for="(item, index) in data" :key="item._id">
<view class="swiper-item" @click="clickBannerItem(item)">
<image class="banner-image" :src="item.bannerfile.url" mode="aspectFill" :draggable="false" />
</view>
</swiper-item>
</swiper>
</uni-swiper-dot>
</unicloud-db>
<!-- 宫格 -->
<!-- banner -->
<unicloud-db ref="bannerdb" v-slot:default="{data, loading, error, options}" collection="opendb-banner"
field="_id,bannerfile,open_url,title" @load="onqueryload">
<!-- 当无banner数据时显示占位图 -->
<image v-if="!(loading||data.length)" class="banner-image" src="/static/grid/empty.png" mode="aspectFill" :draggable="false" />
<uni-swiper-dot v-else class="uni-swiper-dot-box" @clickItem="clickItem" :info="data"
:current="current" field="content">
<swiper class="swiper-box" @change="changeSwiper" :current="swiperDotIndex">
<swiper-item v-for="(item, index) in data" :key="item._id">
<view class="swiper-item" @click="clickBannerItem(item)">
<image class="banner-image" :src="item.bannerfile.url" mode="aspectFill" :draggable="false" />
</view>
</swiper-item>
</swiper>
</uni-swiper-dot>
</unicloud-db>
<!-- 宫格 -->
<uni-section :title="$t('grid.grid')" style="margin: 0;" type="line"></uni-section>
<view class="example-body">
<uni-grid :column="3" :highlight="true" @change="change">
<template v-for="(item,i) in gridList">
<uni-grid-item :index="i" :key="i"
v-if="i<3 || i>2&&i<6&&hasLogin || i>5&&uniIDHasRole('admin')"
>
<view class="grid-item-box" style="background-color: #fff;">
<!-- <image :src="'/static/grid/c'+(i+1)+'.png'" class="image" mode="aspectFill" /> -->
<text class="big-number">{{i+1}}</text>
<text class="text">{{item}}</text>
</view>
</uni-grid-item>
<view class="example-body">
<uni-grid :column="3" :highlight="true" @change="change">
<template v-for="(item,i) in gridList">
<uni-grid-item :index="i" :key="i"
v-if="i<3 || i>2&&i<6&&hasLogin || i>5&&uniIDHasRole('admin')"
>
<view class="grid-item-box" style="background-color: #fff;">
<!-- <image :src="'/static/grid/c'+(i+1)+'.png'" class="image" mode="aspectFill" /> -->
<text class="big-number">{{i+1}}</text>
<text class="text">{{item}}</text>
</view>
</uni-grid-item>
</template>
</uni-grid>
</view>
......@@ -51,25 +51,25 @@
return {
gridList: [],
current: 0,
swiperDotIndex: 0,
swiperDotIndex: 0,
hasLogin:false
}
},
onShow() {
this.hasLogin = uniCloud.getCurrentUserInfo().tokenExpired > Date.now()
},
onLoad() {
let gridList = []
for (var i = 0; i < 3; i++) {
gridList.push( this.$t('grid.visibleToAll') )
}
for (var i = 0; i < 3; i++) {
gridList.push( this.$t('grid.invisibleToTourists') )
}
for (var i = 0; i < 3; i++) {
gridList.push( this.$t('grid.adminVisible') )
}
this.gridList = gridList
onShow() {
this.hasLogin = uniCloud.getCurrentUserInfo().tokenExpired > Date.now()
},
onLoad() {
let gridList = []
for (var i = 0; i < 3; i++) {
gridList.push( this.$t('grid.visibleToAll') )
}
for (var i = 0; i < 3; i++) {
gridList.push( this.$t('grid.invisibleToTourists') )
}
for (var i = 0; i < 3; i++) {
gridList.push( this.$t('grid.adminVisible') )
}
this.gridList = gridList
},
methods: {
change(e) {
......@@ -81,7 +81,7 @@
/**
* banner加载后触发的回调
*/
onqueryload(data) {
onqueryload(data) {
},
changeSwiper(e) {
this.current = e.detail.current
......@@ -151,13 +151,13 @@
width: 50rpx;
height: 50rpx;
}
.big-number{
font-size: 50rpx;
font-weight: 700;
font-stretch: condensed;
font-style:oblique;
}
.big-number{
font-size: 50rpx;
font-weight: 700;
font-stretch: condensed;
font-style:oblique;
}
.text {
text-align: center;
......@@ -210,16 +210,16 @@
}
/* #ifndef APP-NVUE || VUE3*/
/deep/
::v-deep
/* #endif */
.uni-searchbar__box {
border-width: 0;
}
/* #ifndef APP-NVUE || VUE3 */
/deep/
::v-deep
/* #endif */
.uni-input-placeholder {
font-size: 28rpx;
}
</style>
</style>
......@@ -378,7 +378,7 @@
/* #ifdef APP-PLUS */
/* #ifndef APP-NVUE || VUE3*/
/deep/
::v-deep
/* #endif */
.uni-searchbar {
padding-left: 0;
......@@ -387,14 +387,14 @@
/* #endif */
/* #ifndef APP-NVUE || VUE3*/
/deep/
::v-deep
/* #endif */
.uni-searchbar__box {
border-width: 0;
}
/* #ifndef APP-NVUE || VUE3 */
/deep/
::v-deep
/* #endif */
.uni-input-placeholder {
font-size: 28rpx;
......
......@@ -4,8 +4,11 @@
<image class="logoImg" :src="about.logo"></image>
<text class="tip appName">{{about.appName}}</text>
<text class="tip">Version {{version}}</text>
<!--Sansnn-uQRCode组件来源,插件市场:https://ext.dcloud.net.cn/plugin?id=1287 微调后-->
<Sansnn-uQRCode :text="about.download" :makeOnLoad="true" class="qrcode"></Sansnn-uQRCode>
<view class="qrcode">
<!--uqrcode 组件来源,插件Sansnn-uQRCode 链接地址:https://ext.dcloud.net.cn/plugin?id=1287-->
<uqrcode :size="100" canvas-id="qrcode" :value="about.download"></uqrcode>
</view>
<text class="tip">{{$t('about.sacnQR')}} {{about.appName}} {{$t('about.client')}}</text>
</view>
<view class="copyright">
......@@ -20,11 +23,15 @@
</template>
<script>
// #ifdef APP
import UniShare from '@/uni_modules/uni-share/js_sdk/uni-share.js';
import UniShare from '@/uni_modules/uni-share/js_sdk/uni-share.js';
const uniShare = new UniShare()
// #endif
import uniIdPagesConfig from '@/uni_modules/uni-id-pages/config.js';
import uqrcode from "@/uni_modules/Sansnn-uQRCode/components/uqrcode/uqrcode"
export default {
components:{
uqrcode
},
// #ifdef APP
onBackPress({from}) {
if(from=='backbutton'){
......@@ -74,7 +81,7 @@
uni.setNavigationBarTitle({
title: this.$t('about.about')+ " " + this.about.appName
})
this.year = (new Date).getFullYear()
this.year = (new Date).getFullYear()
},
onNavigationBarButtonTap() {
let {
......@@ -154,7 +161,7 @@
</script>
<style lang="scss" scoped>
/* #ifndef APP-NVUE */
view {
view{
display: flex;
box-sizing: border-box;
flex-direction: column;
......@@ -193,9 +200,14 @@
font-weight: 500;
}
.qrcode {
margin-top: 60rpx;
}
.qrcode ,.qrcode .uqrcode{
margin: 10px 0;
width: 100px;
height: 100px;
/* #ifndef APP-NVUE */
display: block;
/* #endif */
}
.copyright {
font-size: 32rpx;
......
<template>
<view class="content">
<!-- 功能列表 -->
<uni-list class="mt10" :border="false">
<uni-list class="mt10" :border="false">
<uni-list-item :title="$t('settings.userInfo')" to="/uni_modules/uni-id-pages/pages/userinfo/userinfo" link="navigateTo"></uni-list-item>
<uni-list-item v-if="userInfo.mobile" :title="$t('settings.changePassword')" :to="'/pages/ucenter/login-page/pwd-retrieve/pwd-retrieve?phoneNumber='+ userInfo.mobile" link="navigateTo"></uni-list-item>
</uni-list>
......@@ -27,24 +27,27 @@
</template>
<script>
import pushServer from './dc-push/push.js';
import common from '@/uni_modules/uni-id-pages/common/common.js';
import pushServer from './dc-push/push.js';
import {
store,
mutations
} from '@/uni_modules/uni-id-pages/common/store.js'
export default {
data() {
return {
pushServer:pushServer,
supportMode:[],
pushIsOn:"wait",
currentLanguage:"",
currentLanguage:"",
userInfo:{}
}
},
computed: {
hasLogin(){
return uniCloud.getCurrentUserInfo().tokenExpired > Date.now()
},
i18nEnable(){
return getApp().globalData.config.i18n.enable
hasLogin(){
return store.hasLogin
},
i18nEnable(){
return getApp().globalData.config.i18n.enable
}
},
onLoad() {
......@@ -63,9 +66,9 @@
console.log(err);
}
})
// #endif
// #endif
},
onShow() {
onShow() {
// 检查手机端获取推送是否开启
//#ifdef APP-PLUS
setTimeout(()=>{
......@@ -73,16 +76,16 @@
},300)
//#endif
},
methods: {
async changeLoginState(){
if(this.hasLogin){
await common.logout()
}else{
uni.redirectTo({
url: '/uni_modules/uni-id-pages/pages/login/login-withoutpwd',
});
}
},
methods: {
async changeLoginState(){
if(this.hasLogin){
await mutations.logout()
}else{
uni.redirectTo({
url: '/uni_modules/uni-id-pages/pages/login/login-withoutpwd',
});
}
},
/**
* 开始生物认证
*/
......@@ -219,10 +222,10 @@
language = globalData.locale = 'en'
}
uni.setStorageSync('CURRENT_LANG', language)
getApp().globalData.$i18n.locale = language
this.currentLanguage = res.tapIndex?'简体中文':'English'
if(uni.setLocale){
uni.setLocale(language)
getApp().globalData.$i18n.locale = language
this.currentLanguage = res.tapIndex?'简体中文':'English'
if(uni.setLocale){
uni.setLocale(language)
}
uni.reLaunch({
url: '/pages/list/list',
......@@ -290,10 +293,10 @@
margin-top: 10px;
}
/* #ifndef APP-NVUE || VUE3 */
.content /deep/ .uni-list {
.content ::v-deep .uni-list {
background-color: #F9F9F9;
}
.content /deep/ .uni-list-item--disabled,.list-item {
.content ::v-deep .uni-list-item--disabled,.list-item {
height: 50px;
margin-bottom: 1px;
}
......
<template>
<view class="center">
<uni-sign-in ref="signIn"></uni-sign-in>
<uni-sign-in ref="signIn"></uni-sign-in>
<view class="userInfo" @click.capture="toUserInfo">
<cloud-image width="150rpx" height="150rpx" v-if="hasLogin&&userInfo.avatar_file&&userInfo.avatar_file.url" :src="userInfo.avatar_file.url"></cloud-image>
<image v-else class="logo-img" src="@/static/uni-center/defaultAvatarUrl.png"></image>
......@@ -37,7 +37,11 @@
import UniShare from '@/uni_modules/uni-share/js_sdk/uni-share.js';
const uniShare = new UniShare()
// #endif
const db = uniCloud.database();
const db = uniCloud.database();
import {
store,
mutations
} from '@/uni_modules/uni-id-pages/common/store.js'
export default {
// #ifdef APP
onBackPress({from}) {
......@@ -132,9 +136,7 @@
"style": "solid", // 边框样式
"radius": "100%" // 边框圆角,支持百分比
}
},
userInfo:{},
hasLogin:false
}
}
},
onLoad() {
......@@ -149,21 +151,13 @@
//#endif
},
onShow() {
this.hasLogin = uniCloud.getCurrentUserInfo().tokenExpired > Date.now()
if(this.hasLogin){
this.getUserInfo()
}
},
computed: {
test:{
get(){
console.log(this._test,Date.now());
this._test = Date.now()
return ''
},
set(){
}
userInfo() {
return store.userInfo
},
hasLogin(){
return store.hasLogin
},
// #ifdef APP-PLUS
appVersion() {
......@@ -175,19 +169,6 @@
}
},
methods: {
getUserInfo(e) {
const db = uniCloud.database();
db.collection('uni-id-users').where("'_id' == $cloudEnv_uid").field('mobile,nickname,avatar_file').get().then(res => {
console.log({res});
this.userInfo = res.result.data[0]
console.log('this.userInfo', this.userInfo);
}).catch(e => {
this.userInfo = {}
console.log(e.message, e.errCode);
}).finally(e => {
// console.log(e);
})
},
toSettings() {
uni.navigateTo({
url: "/pages/ucenter/settings/settings"
......
......@@ -31,7 +31,7 @@ export default {
//口号
"slogan": "云端一体应用快速开发模版",
//应用的链接,用于分享到第三方平台和生成关于我们页的二维码
"download": "",
"download": "https://itunes.apple.com/cn/app/hello-uni-app/id1417078253?mt=8",
//version
"version":"1.0.0" //用于非app端显示,app端自动获取
},
......
## 3.5.1(2022-08-11)
v3.5.1
修复vue3引入报错;
修复vue导出临时文件失败;
修复在其他dom元素更新时,可能导致二维码重新渲染;
修复size重新赋值导致组件偏移、闪烁。
<!-- ---------------------------------------------------------------------
// uQRCode二维码生成插件 v3.5.1
//
// uQRCode是一款基于Javascript环境开发的二维码生成插件,适用所有Javascript运行环境的前端应用和Node.js。
//
// Copyright (c) Sansnn uQRCode All rights reserved.
//
// Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
//
// github地址:
// https://github.com/Sansnn/uQRCode
//
// npm地址:
// https://www.npmjs.com/package/@uqrcode/uni-app
//
// uni-app插件市场地址:
// https://ext.dcloud.net.cn/plugin?id=1287
//
// 复制使用请保留本段注释,感谢支持开源!
//
--------------------------------------------------------------------- -->
<template>
<view class="uqrcode" :class="{ 'uqrcode-hide': hide }" :style="{ width: `${templateOptions.width}px`, height: `${templateOptions.height}px` }">
<!-- 画布 -->
<!-- #ifndef MP-WEIXIN || APP-NVUE -->
<canvas
class="uqrcode-canvas"
:id="canvasId"
:canvas-id="canvasId"
:style="{
width: `${templateOptions.canvasWidth}px`,
height: `${templateOptions.canvasHeight}px`,
transform: `scale(${size / templateOptions.canvasWidth}, ${size / templateOptions.canvasHeight})`
}"
@click="onClick"
v-if="templateOptions.canvasDisplay"
></canvas>
<!-- #endif -->
<!-- 微信小程序非2d模式不支持transform所以使用canvas2d -->
<!-- #ifdef MP-WEIXIN -->
<canvas
class="uqrcode-canvas"
type="2d"
:id="canvasId"
:canvas-id="canvasId"
:style="{
width: `${templateOptions.canvasWidth}px`,
height: `${templateOptions.canvasHeight}px`
}"
@click="onClick"
v-if="templateOptions.canvasDisplay"
></canvas>
<!-- #endif -->
<!-- nvue用gcanvas -->
<!-- #ifdef APP-NVUE -->
<gcanvas
class="uqrcode-canvas"
ref="gcanvas"
:style="{
width: `${templateOptions.canvasWidth}px`,
height: `${templateOptions.canvasHeight}px`
}"
@click="onClick"
v-if="templateOptions.canvasDisplay"
></gcanvas>
<!-- #endif -->
<!-- H5保存提示 -->
<!-- #ifdef H5 -->
<view class="uqrcode-h5-save" v-if="isH5Save">
<image class="uqrcode-h5-save-image" :src="tempFilePath"></image>
<text class="uqrcode-h5-save-text">若保存失败,请长按二维码进行保存</text>
<view class="uqrcode-h5-save-close" @click="isH5Save = false">
<view class="uqrcode-h5-save-close-before"></view>
<view class="uqrcode-h5-save-close-after"></view>
</view>
</view>
<!-- #endif -->
<!-- 加载效果,可在此替换 -->
<view class="uqrcode-makeing" v-if="makeing">
<image
class="uqrcode-makeing-image"
:style="{ width: `${size / 4}px`, height: `${size / 4}px` }"
src="data:image/gif;base64,R0lGODlhAAEAAfIEAOHh4SSsWuDg4N3d3f///wAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/wtYTVAgRGF0YVhNUDw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDYuMC1jMDAyIDc5LjE2NDQ4OCwgMjAyMC8wNy8xMC0yMjowNjo1MyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIDIyLjAgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjAyODhGMzM4RDEwMTExRUM4MDhCRkVBQkE2QUZDQzkwIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjAyODhGMzM5RDEwMTExRUM4MDhCRkVBQkE2QUZDQzkwIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDI4OEYzMzZEMTAxMTFFQzgwOEJGRUFCQTZBRkNDOTAiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDI4OEYzMzdEMTAxMTFFQzgwOEJGRUFCQTZBRkNDOTAiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4B//79/Pv6+fj39vX08/Lx8O/u7ezr6uno5+bl5OPi4eDf3t3c29rZ2NfW1dTT0tHQ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"
></image>
</view>
<!-- 错误处理,可在此替换 -->
<view class="uqrcode-error" v-if="inError"><text class="uqrcode-error-message">Error, see console.</text></view>
</view>
</template>
<script>
// #ifdef VUE3
import { toRaw } from 'vue';
// #endif
/* 引入uQRCode核心js */
import UQRCode from '../../js_sdk/uqrcode';
/* 引入nvue所需模块 */
// #ifdef APP-NVUE
import { enable, WeexBridge } from '../../js_sdk/gcanvas';
const modal = weex.requireModule('modal');
// #endif
export default {
name: 'uqrcode',
props: {
/**
* canvas组件id
*/
canvasId: {
type: String,
required: true // canvasId在微信小程序初始值不能为空,created中赋值也不行,必须给一个值,否则挂载组件后无法绘制
},
/**
* 二维码内容
*/
value: {
type: [String, Number]
},
/**
* 二维码大小
*/
size: {
type: [String, Number],
default: 200
},
/**
* 选项
*/
options: {
type: Object,
default: () => {
return {};
}
},
/**
* 导出的文件类型
*/
fileType: {
type: String,
default: 'png'
},
/**
* 是否初始化组件后就开始生成
*/
start: {
type: Boolean,
default: true
},
/**
* 是否数据发生改变自动重绘
*/
auto: {
type: Boolean,
default: false
},
/**
* 隐藏组件
*/
hide: {
type: Boolean,
default: false
}
},
data() {
return {
canvas: undefined,
canvasContext: undefined,
makeDelegate: undefined,
drawDelegate: undefined,
toTempFilePathDelegate: undefined,
makeing: false,
drawing: false,
inError: false,
isH5Save: false,
tempFilePath: '',
templateOptions: {
width: 0, // 组件宽度
height: 0,
canvasWidth: 0, // canvas宽度
canvasHeight: 0,
canvasDisplay: false
},
uqrcodeOptions: {
data: ''
},
makeingPattern: [
[
[true, true, true, false, false, false, false, true, true, true],
[true, true, true, false, false, false, false, true, true, true],
[true, true, true, false, false, false, false, true, true, true],
[true, true, true, false, false, false, false, true, true, true],
[true, true, true, false, false, false, false, true, true, true],
[true, true, true, false, false, false, false, true, true, true],
[true, true, true, false, false, false, false, true, true, true],
[true, true, true, true, true, true, true, true, true, true],
[true, true, true, true, true, true, true, true, true, true],
[true, true, true, true, true, true, true, true, true, true]
],
[
[true, true, true, true, true, true, true, true, true, true],
[true, true, true, true, true, true, true, true, true, true],
[true, true, true, true, true, true, true, true, true, true],
[true, true, true, false, false, false, false, true, true, true],
[true, true, true, false, false, false, false, true, true, true],
[true, true, true, false, false, false, false, true, true, true],
[true, true, true, false, false, false, false, false, false, false],
[true, true, true, true, true, true, false, true, true, true],
[true, true, true, true, true, true, false, true, true, true],
[true, true, true, true, true, true, false, true, true, true]
],
[
[true, true, true, true, true, true, true, true, true, true],
[true, true, true, true, true, true, true, true, true, true],
[true, true, true, true, true, true, true, true, true, true],
[true, true, true, false, false, false, false, true, true, true],
[true, true, true, false, false, false, false, true, true, true],
[true, true, true, true, true, true, true, false, false, false],
[true, true, true, true, true, true, true, false, false, false],
[true, true, true, true, true, true, true, false, false, false],
[true, true, true, false, false, false, false, true, true, true],
[true, true, true, false, false, false, false, true, true, true]
],
[
[true, true, true, true, true, true, true, true, true, true],
[true, true, true, true, true, true, true, true, true, true],
[true, true, true, true, true, true, true, true, true, true],
[true, true, true, false, false, false, false, false, false, false],
[true, true, true, false, false, false, false, false, false, false],
[true, true, true, false, false, false, false, false, false, false],
[true, true, true, false, false, false, false, false, false, false],
[true, true, true, true, true, true, true, true, true, true],
[true, true, true, true, true, true, true, true, true, true],
[true, true, true, true, true, true, true, true, true, true]
]
]
};
},
watch: {
value: {
handler() {
if (this.auto) {
this.remake();
}
}
},
size: {
handler() {
if (this.auto) {
this.remake();
}
}
},
options: {
handler() {
if (this.auto) {
this.remake();
}
},
deep: true
},
makeing: {
handler(val) {
if (!val) {
if (typeof this.toTempFilePathDelegate === 'function') {
this.toTempFilePathDelegate();
}
}
}
}
},
mounted() {
this.templateOptions.canvasWidth = this.size;
this.templateOptions.canvasHeight = this.size;
if (this.start) {
this.make();
}
},
methods: {
/**
* 获取模板选项
*/
getTemplateOptions() {
return UQRCode.deepReplace(this.templateOptions, {
width: this.size,
height: this.size
});
},
/**
* 获取插件选项
*/
getUqrcodeOptions() {
return UQRCode.deepReplace(this.options, {
data: String(this.value),
size: Number(this.size)
});
},
/**
* 重置画布
*/
resetCanvas(callback) {
this.templateOptions.canvasDisplay = false;
this.$nextTick(() => {
this.templateOptions.canvasDisplay = true;
this.$nextTick(() => {
callback && callback();
});
});
},
/**
* 绘制二维码
*/
async draw(callback = success => {}) {
if (this.drawing) {
this.drawDelegate = () => {
this.draw(callback);
};
}
this.drawing = true;
this.inError = false;
if (!this.canvasId) {
console.error('[uQRCode]: canvasId must be set!');
this.inError = true;
callback(false);
return;
}
if (!this.value) {
console.error('[uQRCode]: value must be set!');
this.inError = true;
callback(false);
return;
}
/* 组件数据 */
this.templateOptions = this.getTemplateOptions();
/* uQRCode选项 */
this.uqrcodeOptions = this.getUqrcodeOptions();
/* 纠错等级兼容字母写法 */
if (typeof this.uqrcodeOptions.errorCorrectLevel === 'string') {
this.uqrcodeOptions.errorCorrectLevel = UQRCode.errorCorrectLevel[this.uqrcodeOptions.errorCorrectLevel];
}
/* nvue不支持动态修改gcanvas尺寸,除nvue外,默认使用useDynamicSize */
// #ifndef APP-NVUE
if (typeof this.options.useDynamicSize === 'undefined') {
this.uqrcodeOptions.useDynamicSize = true;
}
// #endif
// #ifdef APP-NVUE
this.uqrcodeOptions.useDynamicSize = false;
// #endif
/* 获取uQRCode实例 */
const qr = new UQRCode();
/* 设置uQRCode选项 */
qr.setOptions(this.uqrcodeOptions);
/* 调用制作二维码方法 */
qr.make();
/* 获取canvas上下文 */
// #ifndef MP-WEIXIN || APP-NVUE
/* uniapp获取canvas上下文方式 */
const canvasContext = (this.canvasContext = uni.createCanvasContext(this.canvasId, this));
/* 使用dynamicSize,可以解决小块间出现白线问题,再通过scale缩放至size,使其达到所设尺寸 */
this.templateOptions.canvasWidth = qr.dynamicSize;
this.templateOptions.canvasHeight = qr.dynamicSize;
/* uniapp获取图像方式 */
UQRCode.loadImage = function(src) {
return new Promise((resolve, reject) => {
uni.getImageInfo({
src,
success: res => {
resolve(res.path);
},
fail: err => {
reject(err);
}
});
});
};
// #endif
// #ifdef MP-WEIXIN
/* 微信小程序获取canvas上下文方式 */
const canvas = (this.canvas = await new Promise(resolve => {
uni
.createSelectorQuery()
.in(this) // 在组件内使用需要
.select(`#${this.canvasId}`)
.fields({
node: true,
size: true
})
.exec(res => {
resolve(res[0].node);
});
}));
const canvasContext = (this.canvasContext = canvas.getContext('2d'));
/* 2d的组件设置宽高与实际canvas绘制宽高不是一个,打个比方,组件size=200,canvas.width设置为100,那么绘制出来就是100=200,组件size=400,canvas.width设置为800,绘制大小还是800=400,所以无需理会下方返回的dynamicSize是多少,按dpr重新赋值给canvas即可 */
this.templateOptions.canvasWidth = qr.size;
this.templateOptions.canvasHeight = qr.size;
/* 使用dynamicSize+scale,可以解决小块间出现白线问题,dpr可以解决模糊问题 */
const dpr = uni.getSystemInfoSync().pixelRatio;
canvas.width = qr.dynamicSize * dpr;
canvas.height = qr.dynamicSize * dpr;
canvasContext.scale(dpr, dpr);
/* 微信小程序获取图像方式 */
UQRCode.loadImage = function(src) {
/* 小程序下获取网络图片信息需先配置download域名白名单才能生效 */
return new Promise((resolve, reject) => {
const img = canvas.createImage();
img.src = src;
img.onload = () => {
resolve(img);
};
img.onerror = err => {
reject(err);
};
});
};
// #endif
// #ifdef APP-NVUE
/* NVue获取canvas上下文方式 */
const gcanvas = this.$refs['gcanvas'];
const canvas = enable(gcanvas, {
bridge: WeexBridge
});
const canvasContext = (this.canvasContext = canvas.getContext('2d'));
/* NVue获取图像方式 */
UQRCode.loadImage = function(src) {
return new Promise((resolve, reject) => {
/* getImageInfo在nvue的bug:获取同一个路径的图片信息,同一时间第一次获取成功,后续失败,猜测是写入本地时产生文件写入冲突,所以没有返回,特别是对于网络资源 --- js部分已实现队列绘制,已解决此问题 */
uni.getImageInfo({
src,
success: res => {
resolve(res.path);
},
fail: err => {
reject(err);
}
});
});
};
// #endif
/* 设置uQRCode实例的canvas上下文 */
qr.canvasContext = canvasContext;
/* 延时等待页面重新绘制完毕 */
setTimeout(() => {
/* 调用绘制方法将二维码图案绘制到canvas上 */
qr.drawCanvas()
.then(() => {
if (this.drawDelegate) {
/* 高频重绘纠正 */
this.drawDelegate();
this.drawDelegate = undefined;
} else {
this.drawing = false;
callback(true);
}
})
.catch(() => {
if (this.drawDelegate) {
this.drawDelegate();
this.drawDelegate = undefined;
} else {
this.inError = true;
this.drawing = false;
callback(false);
}
});
}, 300);
},
/**
* 生成二维码
*/
make() {
this.makeing = true;
this.resetCanvas(() => {
clearTimeout(this.makeDelegate);
this.makeDelegate = setTimeout(() => {
this.draw(res => {
this.makeing = false;
this.complete(res);
});
}, 300);
});
},
/**
* 重新生成
*/
remake() {
this.make();
},
/**
* 生成完成
*/
complete(success = true) {
setTimeout(() => {
this.$emit('complete', {
success
});
}, 300);
},
/**
* 导出临时路径
*/
toTempFilePath(callback = {}) {
if (typeof callback.success != 'function') {
callback.success = () => {};
}
if (typeof callback.fail != 'function') {
callback.fail = () => {};
}
if (typeof callback.complete != 'function') {
callback.complete = () => {};
}
if (this.makeing) {
/* 如果还在生成状态,那当前操作将托管到委托,监听生成完成后再通过委托复调当前方法 */
this.toTempFilePathDelegate = () => {
this.toTempFilePath(callback);
};
return;
} else {
this.toTempFilePathDelegate = null;
}
// #ifndef MP-WEIXIN || APP-NVUE
uni.canvasToTempFilePath(
{
canvasId: this.canvasId,
fileType: this.fileType,
width: this.templateOptions.canvasWidth,
height: this.templateOptions.canvasHeight,
success: res => {
callback.success(res);
},
fail: err => {
callback.fail(err);
},
complete: () => {
callback.complete();
}
},
this
);
// #endif
// #ifdef MP-WEIXIN
/* 需要将 data:image/png;base64, 这段去除 writeFile 才能正常打开文件,否则是损坏文件,无法打开*/
const reg = new RegExp('^data:image/png;base64,', 'g');
// #ifdef VUE3
const dataURL = toRaw(this.canvas).toDataURL().replace(reg, '');
// #endif
// #ifndef VUE3
const dataURL = this.canvas.toDataURL().replace(reg, '');
// #endif
const fs = wx.getFileSystemManager();
const tempFilePath = `${wx.env.USER_DATA_PATH}/${new Date().getTime()}${
Math.random()
.toString()
.split('.')[1]
}.png`;
fs.writeFile({
filePath: tempFilePath, // 要写入的文件路径 (本地路径)
data: dataURL, // base64图片
encoding: 'base64',
success: res => {
callback.success({
tempFilePath
});
},
fail: err => {
callback.fail(err);
},
complete: () => {
callback.complete();
}
});
// #endif
// #ifdef APP-NVUE
/* 测试过程中,size需要乘以3才能保存完整,3又对应dpr,猜测是与像素比有关,故乘以3。第一次运行无法保存,后续正常,待排查。 */
const dpr = uni.getSystemInfoSync().pixelRatio;
this.canvasContext.toTempFilePath(0, 0, this.size * dpr, this.size * dpr, this.size * dpr, this.size * dpr, '', 1, res => {
callback.success(res);
callback.complete(res);
});
// #endif
},
/**
* 保存
*/
save(callback = {}) {
if (typeof callback.success != 'function') {
callback.success = () => {};
}
if (typeof callback.fail != 'function') {
callback.fail = () => {};
}
if (typeof callback.complete != 'function') {
callback.complete = () => {};
}
this.toTempFilePath({
success: res => {
// #ifndef H5
uni.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: res1 => {
callback.success(res1);
},
fail: err1 => {
callback.fail(err1);
},
complete: () => {
callback.complete();
}
});
// #endif
// #ifdef H5
/* 可以在电脑浏览器下载,移动端iOS不行,安卓微信浏览器不行,安卓外部浏览器可以 */
this.isH5Save = true;
this.tempFilePath = res.tempFilePath;
const aEle = document.createElement('a');
aEle.download = 'uQRCode'; // 设置下载的文件名,默认是'下载'
aEle.href = res.tempFilePath;
document.body.appendChild(aEle);
aEle.click();
aEle.remove(); // 下载之后把创建的元素删除
callback.success({
errMsg: 'ok'
});
callback.complete();
// #endif
},
fail: err => {
callback.fail(err);
callback.complete();
}
});
},
/**
* 注册click事件
*/
onClick(e) {
this.$emit('click', e);
}
}
};
</script>
<style scoped>
.uqrcode {
position: relative;
}
.uqrcode-hide {
position: fixed;
left: 7500rpx;
}
.uqrcode-canvas {
transform-origin: top left;
}
.uqrcode-makeing {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 10;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
align-items: center;
}
.uqrcode-makeing-image {
/* #ifndef APP-NVUE */
display: block;
max-width: 120px;
max-height: 120px;
/* #endif */
}
.uqrcode-error {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
align-items: center;
}
.uqrcode-error-message {
font-size: 12px;
color: #939291;
}
/* #ifdef H5 */
.uqrcode-h5-save {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 100;
background-color: rgba(0, 0, 0, 0.68);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.uqrcode-h5-save-image {
width: 512rpx;
height: 512rpx;
padding: 32rpx;
}
.uqrcode-h5-save-text {
margin-top: 20rpx;
font-size: 32rpx;
font-weight: 700;
color: #ffffff;
}
.uqrcode-h5-save-close {
position: relative;
margin-top: 72rpx;
width: 40rpx;
height: 40rpx;
border: 2rpx solid #ffffff;
border-radius: 40rpx;
padding: 10rpx;
}
.uqrcode-h5-save-close-before {
position: absolute;
top: 50%;
transform: translateY(-50%) rotate(45deg);
width: 40rpx;
height: 4rpx;
background: #ffffff;
}
.uqrcode-h5-save-close-after {
position: absolute;
top: 50%;
transform: translateY(-50%) rotate(-45deg);
width: 40rpx;
height: 4rpx;
background: #ffffff;
}
/* #endif */
</style>
<!-- ---------------------------------------------------------------------
// uQRCode二维码生成插件 v3.5.1
//
// uQRCode是一款基于Javascript环境开发的二维码生成插件,适用所有Javascript运行环境的前端应用和Node.js。
//
// Copyright (c) Sansnn uQRCode All rights reserved.
//
// Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
//
// github地址:
// https://github.com/Sansnn/uQRCode
//
// npm地址:
// https://www.npmjs.com/package/@uqrcode/uni-app
//
// uni-app插件市场地址:
// https://ext.dcloud.net.cn/plugin?id=1287
//
// 复制使用请保留本段注释,感谢支持开源!
//
--------------------------------------------------------------------- -->
<template>
<view class="uqrcode" :class="{ 'uqrcode-hide': hide }" :style="{ width: `${templateOptions.width}px`, height: `${templateOptions.height}px` }">
<!-- 画布 -->
<!-- #ifndef MP-WEIXIN || APP-NVUE -->
<canvas
class="uqrcode-canvas"
:id="canvasId"
:canvas-id="canvasId"
:style="{
width: `${templateOptions.canvasWidth}px`,
height: `${templateOptions.canvasHeight}px`,
transform: `scale(${size / templateOptions.canvasWidth}, ${size / templateOptions.canvasHeight})`
}"
@click="onClick"
v-if="templateOptions.canvasDisplay"
></canvas>
<!-- #endif -->
<!-- 微信小程序非2d模式不支持transform所以使用canvas2d -->
<!-- #ifdef MP-WEIXIN -->
<canvas
class="uqrcode-canvas"
type="2d"
:id="canvasId"
:canvas-id="canvasId"
:style="{
width: `${templateOptions.canvasWidth}px`,
height: `${templateOptions.canvasHeight}px`
}"
@click="onClick"
v-if="templateOptions.canvasDisplay"
></canvas>
<!-- #endif -->
<!-- nvue用gcanvas -->
<!-- #ifdef APP-NVUE -->
<gcanvas
class="uqrcode-canvas"
ref="gcanvas"
:style="{
width: `${templateOptions.canvasWidth}px`,
height: `${templateOptions.canvasHeight}px`
}"
@click="onClick"
v-if="templateOptions.canvasDisplay"
></gcanvas>
<!-- #endif -->
<!-- H5保存提示 -->
<!-- #ifdef H5 -->
<view class="uqrcode-h5-save" v-if="isH5Save">
<image class="uqrcode-h5-save-image" :src="tempFilePath"></image>
<text class="uqrcode-h5-save-text">若保存失败,请长按二维码进行保存</text>
<view class="uqrcode-h5-save-close" @click="isH5Save = false">
<view class="uqrcode-h5-save-close-before"></view>
<view class="uqrcode-h5-save-close-after"></view>
</view>
</view>
<!-- #endif -->
<!-- 加载效果,可在此替换 -->
<view class="uqrcode-makeing" v-if="makeing">
<image
class="uqrcode-makeing-image"
:style="{ width: `${size / 4}px`, height: `${size / 4}px` }"
src="data:image/gif;base64,R0lGODlhAAEAAfIEAOHh4SSsWuDg4N3d3f///wAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/wtYTVAgRGF0YVhNUDw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDYuMC1jMDAyIDc5LjE2NDQ4OCwgMjAyMC8wNy8xMC0yMjowNjo1MyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIDIyLjAgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjAyODhGMzM4RDEwMTExRUM4MDhCRkVBQkE2QUZDQzkwIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjAyODhGMzM5RDEwMTExRUM4MDhCRkVBQkE2QUZDQzkwIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDI4OEYzMzZEMTAxMTFFQzgwOEJGRUFCQTZBRkNDOTAiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDI4OEYzMzdEMTAxMTFFQzgwOEJGRUFCQTZBRkNDOTAiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4B//79/Pv6+fj39vX08/Lx8O/u7ezr6uno5+bl5OPi4eDf3t3c29rZ2NfW1dTT0tHQ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"
></image>
</view>
<!-- 错误处理,可在此替换 -->
<view class="uqrcode-error" v-if="inError"><text class="uqrcode-error-message">Error, see console.</text></view>
</view>
</template>
<script>
// #ifdef VUE3
import { toRaw } from 'vue';
// #endif
/* 引入uQRCode核心js */
import UQRCode from '../../js_sdk/uqrcode';
/* 引入nvue所需模块 */
// #ifdef APP-NVUE
import { enable, WeexBridge } from '../../js_sdk/gcanvas';
const modal = weex.requireModule('modal');
// #endif
export default {
name: 'uqrcode',
props: {
/**
* canvas组件id
*/
canvasId: {
type: String,
required: true // canvasId在微信小程序初始值不能为空,created中赋值也不行,必须给一个值,否则挂载组件后无法绘制
},
/**
* 二维码内容
*/
value: {
type: [String, Number]
},
/**
* 二维码大小
*/
size: {
type: [String, Number],
default: 200
},
/**
* 选项
*/
options: {
type: Object,
default: () => {
return {};
}
},
/**
* 导出的文件类型
*/
fileType: {
type: String,
default: 'png'
},
/**
* 是否初始化组件后就开始生成
*/
start: {
type: Boolean,
default: true
},
/**
* 是否数据发生改变自动重绘
*/
auto: {
type: Boolean,
default: false
},
/**
* 隐藏组件
*/
hide: {
type: Boolean,
default: false
}
},
data() {
return {
canvas: undefined,
canvasContext: undefined,
makeDelegate: undefined,
drawDelegate: undefined,
toTempFilePathDelegate: undefined,
makeing: false,
drawing: false,
inError: false,
isH5Save: false,
tempFilePath: '',
templateOptions: {
width: 0, // 组件宽度
height: 0,
canvasWidth: 0, // canvas宽度
canvasHeight: 0,
canvasDisplay: false
},
uqrcodeOptions: {
data: ''
},
makeingPattern: [
[
[true, true, true, false, false, false, false, true, true, true],
[true, true, true, false, false, false, false, true, true, true],
[true, true, true, false, false, false, false, true, true, true],
[true, true, true, false, false, false, false, true, true, true],
[true, true, true, false, false, false, false, true, true, true],
[true, true, true, false, false, false, false, true, true, true],
[true, true, true, false, false, false, false, true, true, true],
[true, true, true, true, true, true, true, true, true, true],
[true, true, true, true, true, true, true, true, true, true],
[true, true, true, true, true, true, true, true, true, true]
],
[
[true, true, true, true, true, true, true, true, true, true],
[true, true, true, true, true, true, true, true, true, true],
[true, true, true, true, true, true, true, true, true, true],
[true, true, true, false, false, false, false, true, true, true],
[true, true, true, false, false, false, false, true, true, true],
[true, true, true, false, false, false, false, true, true, true],
[true, true, true, false, false, false, false, false, false, false],
[true, true, true, true, true, true, false, true, true, true],
[true, true, true, true, true, true, false, true, true, true],
[true, true, true, true, true, true, false, true, true, true]
],
[
[true, true, true, true, true, true, true, true, true, true],
[true, true, true, true, true, true, true, true, true, true],
[true, true, true, true, true, true, true, true, true, true],
[true, true, true, false, false, false, false, true, true, true],
[true, true, true, false, false, false, false, true, true, true],
[true, true, true, true, true, true, true, false, false, false],
[true, true, true, true, true, true, true, false, false, false],
[true, true, true, true, true, true, true, false, false, false],
[true, true, true, false, false, false, false, true, true, true],
[true, true, true, false, false, false, false, true, true, true]
],
[
[true, true, true, true, true, true, true, true, true, true],
[true, true, true, true, true, true, true, true, true, true],
[true, true, true, true, true, true, true, true, true, true],
[true, true, true, false, false, false, false, false, false, false],
[true, true, true, false, false, false, false, false, false, false],
[true, true, true, false, false, false, false, false, false, false],
[true, true, true, false, false, false, false, false, false, false],
[true, true, true, true, true, true, true, true, true, true],
[true, true, true, true, true, true, true, true, true, true],
[true, true, true, true, true, true, true, true, true, true]
]
]
};
},
watch: {
value: {
handler() {
if (this.auto) {
this.remake();
}
}
},
size: {
handler() {
if (this.auto) {
this.remake();
}
}
},
options: {
handler() {
if (this.auto) {
this.remake();
}
},
deep: true
},
makeing: {
handler(val) {
if (!val) {
if (typeof this.toTempFilePathDelegate === 'function') {
this.toTempFilePathDelegate();
}
}
}
}
},
mounted() {
this.templateOptions.canvasWidth = this.size;
this.templateOptions.canvasHeight = this.size;
if (this.start) {
this.make();
}
},
methods: {
/**
* 获取模板选项
*/
getTemplateOptions() {
return UQRCode.deepReplace(this.templateOptions, {
width: this.size,
height: this.size
});
},
/**
* 获取插件选项
*/
getUqrcodeOptions() {
return UQRCode.deepReplace(this.options, {
data: String(this.value),
size: Number(this.size)
});
},
/**
* 重置画布
*/
resetCanvas(callback) {
this.templateOptions.canvasDisplay = false;
this.$nextTick(() => {
this.templateOptions.canvasDisplay = true;
this.$nextTick(() => {
callback && callback();
});
});
},
/**
* 绘制二维码
*/
async draw(callback = success => {}) {
if (this.drawing) {
this.drawDelegate = () => {
this.draw(callback);
};
}
this.drawing = true;
this.inError = false;
if (!this.canvasId) {
console.error('[uQRCode]: canvasId must be set!');
this.inError = true;
callback(false);
return;
}
if (!this.value) {
console.error('[uQRCode]: value must be set!');
this.inError = true;
callback(false);
return;
}
/* 组件数据 */
this.templateOptions = this.getTemplateOptions();
/* uQRCode选项 */
this.uqrcodeOptions = this.getUqrcodeOptions();
/* 纠错等级兼容字母写法 */
if (typeof this.uqrcodeOptions.errorCorrectLevel === 'string') {
this.uqrcodeOptions.errorCorrectLevel = UQRCode.errorCorrectLevel[this.uqrcodeOptions.errorCorrectLevel];
}
/* nvue不支持动态修改gcanvas尺寸,除nvue外,默认使用useDynamicSize */
// #ifndef APP-NVUE
if (typeof this.options.useDynamicSize === 'undefined') {
this.uqrcodeOptions.useDynamicSize = true;
}
// #endif
// #ifdef APP-NVUE
this.uqrcodeOptions.useDynamicSize = false;
// #endif
/* 获取uQRCode实例 */
const qr = new UQRCode();
/* 设置uQRCode选项 */
qr.setOptions(this.uqrcodeOptions);
/* 调用制作二维码方法 */
qr.make();
/* 获取canvas上下文 */
// #ifndef MP-WEIXIN || APP-NVUE
/* uniapp获取canvas上下文方式 */
const canvasContext = (this.canvasContext = uni.createCanvasContext(this.canvasId, this));
/* 使用dynamicSize,可以解决小块间出现白线问题,再通过scale缩放至size,使其达到所设尺寸 */
this.templateOptions.canvasWidth = qr.dynamicSize;
this.templateOptions.canvasHeight = qr.dynamicSize;
/* uniapp获取图像方式 */
UQRCode.loadImage = function(src) {
return new Promise((resolve, reject) => {
uni.getImageInfo({
src,
success: res => {
resolve(res.path);
},
fail: err => {
reject(err);
}
});
});
};
// #endif
// #ifdef MP-WEIXIN
/* 微信小程序获取canvas上下文方式 */
const canvas = (this.canvas = await new Promise(resolve => {
uni
.createSelectorQuery()
.in(this) // 在组件内使用需要
.select(`#${this.canvasId}`)
.fields({
node: true,
size: true
})
.exec(res => {
resolve(res[0].node);
});
}));
const canvasContext = (this.canvasContext = canvas.getContext('2d'));
/* 2d的组件设置宽高与实际canvas绘制宽高不是一个,打个比方,组件size=200,canvas.width设置为100,那么绘制出来就是100=200,组件size=400,canvas.width设置为800,绘制大小还是800=400,所以无需理会下方返回的dynamicSize是多少,按dpr重新赋值给canvas即可 */
this.templateOptions.canvasWidth = qr.size;
this.templateOptions.canvasHeight = qr.size;
/* 使用dynamicSize+scale,可以解决小块间出现白线问题,dpr可以解决模糊问题 */
const dpr = uni.getSystemInfoSync().pixelRatio;
canvas.width = qr.dynamicSize * dpr;
canvas.height = qr.dynamicSize * dpr;
canvasContext.scale(dpr, dpr);
/* 微信小程序获取图像方式 */
UQRCode.loadImage = function(src) {
/* 小程序下获取网络图片信息需先配置download域名白名单才能生效 */
return new Promise((resolve, reject) => {
const img = canvas.createImage();
img.src = src;
img.onload = () => {
resolve(img);
};
img.onerror = err => {
reject(err);
};
});
};
// #endif
// #ifdef APP-NVUE
/* NVue获取canvas上下文方式 */
const gcanvas = this.$refs['gcanvas'];
const canvas = enable(gcanvas, {
bridge: WeexBridge
});
const canvasContext = (this.canvasContext = canvas.getContext('2d'));
/* NVue获取图像方式 */
UQRCode.loadImage = function(src) {
return new Promise((resolve, reject) => {
/* getImageInfo在nvue的bug:获取同一个路径的图片信息,同一时间第一次获取成功,后续失败,猜测是写入本地时产生文件写入冲突,所以没有返回,特别是对于网络资源 --- js部分已实现队列绘制,已解决此问题 */
uni.getImageInfo({
src,
success: res => {
resolve(res.path);
},
fail: err => {
reject(err);
}
});
});
};
// #endif
/* 设置uQRCode实例的canvas上下文 */
qr.canvasContext = canvasContext;
/* 延时等待页面重新绘制完毕 */
setTimeout(() => {
/* 调用绘制方法将二维码图案绘制到canvas上 */
qr.drawCanvas()
.then(() => {
if (this.drawDelegate) {
/* 高频重绘纠正 */
this.drawDelegate();
this.drawDelegate = undefined;
} else {
this.drawing = false;
callback(true);
}
})
.catch(() => {
if (this.drawDelegate) {
this.drawDelegate();
this.drawDelegate = undefined;
} else {
this.inError = true;
this.drawing = false;
callback(false);
}
});
}, 300);
},
/**
* 生成二维码
*/
make() {
this.makeing = true;
this.resetCanvas(() => {
clearTimeout(this.makeDelegate);
this.makeDelegate = setTimeout(() => {
this.draw(res => {
this.makeing = false;
this.complete(res);
});
}, 300);
});
},
/**
* 重新生成
*/
remake() {
this.make();
},
/**
* 生成完成
*/
complete(success = true) {
setTimeout(() => {
this.$emit('complete', {
success
});
}, 300);
},
/**
* 导出临时路径
*/
toTempFilePath(callback = {}) {
if (typeof callback.success != 'function') {
callback.success = () => {};
}
if (typeof callback.fail != 'function') {
callback.fail = () => {};
}
if (typeof callback.complete != 'function') {
callback.complete = () => {};
}
if (this.makeing) {
/* 如果还在生成状态,那当前操作将托管到委托,监听生成完成后再通过委托复调当前方法 */
this.toTempFilePathDelegate = () => {
this.toTempFilePath(callback);
};
return;
} else {
this.toTempFilePathDelegate = null;
}
// #ifndef MP-WEIXIN || APP-NVUE
uni.canvasToTempFilePath(
{
canvasId: this.canvasId,
fileType: this.fileType,
width: this.templateOptions.canvasWidth,
height: this.templateOptions.canvasHeight,
success: res => {
callback.success(res);
},
fail: err => {
callback.fail(err);
},
complete: () => {
callback.complete();
}
},
this
);
// #endif
// #ifdef MP-WEIXIN
/* 需要将 data:image/png;base64, 这段去除 writeFile 才能正常打开文件,否则是损坏文件,无法打开*/
const reg = new RegExp('^data:image/png;base64,', 'g');
// #ifdef VUE3
const dataURL = toRaw(this.canvas).toDataURL().replace(reg, '');
// #endif
// #ifndef VUE3
const dataURL = this.canvas.toDataURL().replace(reg, '');
// #endif
const fs = wx.getFileSystemManager();
const tempFilePath = `${wx.env.USER_DATA_PATH}/${new Date().getTime()}${
Math.random()
.toString()
.split('.')[1]
}.png`;
fs.writeFile({
filePath: tempFilePath, // 要写入的文件路径 (本地路径)
data: dataURL, // base64图片
encoding: 'base64',
success: res => {
callback.success({
tempFilePath
});
},
fail: err => {
callback.fail(err);
},
complete: () => {
callback.complete();
}
});
// #endif
// #ifdef APP-NVUE
/* 测试过程中,size需要乘以3才能保存完整,3又对应dpr,猜测是与像素比有关,故乘以3。第一次运行无法保存,后续正常,待排查。 */
const dpr = uni.getSystemInfoSync().pixelRatio;
this.canvasContext.toTempFilePath(0, 0, this.size * dpr, this.size * dpr, this.size * dpr, this.size * dpr, '', 1, res => {
callback.success(res);
callback.complete(res);
});
// #endif
},
/**
* 保存
*/
save(callback = {}) {
if (typeof callback.success != 'function') {
callback.success = () => {};
}
if (typeof callback.fail != 'function') {
callback.fail = () => {};
}
if (typeof callback.complete != 'function') {
callback.complete = () => {};
}
this.toTempFilePath({
success: res => {
// #ifndef H5
uni.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: res1 => {
callback.success(res1);
},
fail: err1 => {
callback.fail(err1);
},
complete: () => {
callback.complete();
}
});
// #endif
// #ifdef H5
/* 可以在电脑浏览器下载,移动端iOS不行,安卓微信浏览器不行,安卓外部浏览器可以 */
this.isH5Save = true;
this.tempFilePath = res.tempFilePath;
const aEle = document.createElement('a');
aEle.download = 'uQRCode'; // 设置下载的文件名,默认是'下载'
aEle.href = res.tempFilePath;
document.body.appendChild(aEle);
aEle.click();
aEle.remove(); // 下载之后把创建的元素删除
callback.success({
errMsg: 'ok'
});
callback.complete();
// #endif
},
fail: err => {
callback.fail(err);
callback.complete();
}
});
},
/**
* 注册click事件
*/
onClick(e) {
this.$emit('click', e);
}
}
};
</script>
<style scoped>
.uqrcode {
position: relative;
}
.uqrcode-hide {
position: fixed;
left: 7500rpx;
}
.uqrcode-canvas {
transform-origin: top left;
}
.uqrcode-makeing {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 10;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
align-items: center;
}
.uqrcode-makeing-image {
/* #ifndef APP-NVUE */
display: block;
max-width: 120px;
max-height: 120px;
/* #endif */
}
.uqrcode-error {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
align-items: center;
}
.uqrcode-error-message {
font-size: 12px;
color: #939291;
}
/* #ifdef H5 */
.uqrcode-h5-save {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 100;
background-color: rgba(0, 0, 0, 0.68);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.uqrcode-h5-save-image {
width: 512rpx;
height: 512rpx;
padding: 32rpx;
}
.uqrcode-h5-save-text {
margin-top: 20rpx;
font-size: 32rpx;
font-weight: 700;
color: #ffffff;
}
.uqrcode-h5-save-close {
position: relative;
margin-top: 72rpx;
width: 40rpx;
height: 40rpx;
border: 2rpx solid #ffffff;
border-radius: 40rpx;
padding: 10rpx;
}
.uqrcode-h5-save-close-before {
position: absolute;
top: 50%;
transform: translateY(-50%) rotate(45deg);
width: 40rpx;
height: 4rpx;
background: #ffffff;
}
.uqrcode-h5-save-close-after {
position: absolute;
top: 50%;
transform: translateY(-50%) rotate(-45deg);
width: 40rpx;
height: 4rpx;
background: #ffffff;
}
/* #endif */
</style>
const isWeex = typeof WXEnvironment !== 'undefined';
const isWeexIOS = isWeex && /ios/i.test(WXEnvironment.platform);
const isWeexAndroid = isWeex && !isWeexIOS;
import GLmethod from '../context-webgl/GLmethod';
const GCanvasModule =
(typeof weex !== 'undefined' && weex.requireModule) ? (weex.requireModule('gcanvas')) :
(typeof __weex_require__ !== 'undefined') ? (__weex_require__('@weex-module/gcanvas')) : {};
let isDebugging = false;
let isComboDisabled = false;
const logCommand = (function () {
const methodQuery = [];
Object.keys(GLmethod).forEach(key => {
methodQuery[GLmethod[key]] = key;
})
const queryMethod = (id) => {
return methodQuery[parseInt(id)] || 'NotFoundMethod';
}
const logCommand = (id, cmds) => {
const mId = cmds.split(',')[0];
const mName = queryMethod(mId);
console.log(`=== callNative - componentId:${id}; method: ${mName}; cmds: ${cmds}`);
}
return logCommand;
})();
function joinArray(arr, sep) {
let res = '';
for (let i = 0; i < arr.length; i++) {
if (i !== 0) {
res += sep;
}
res += arr[i];
}
return res;
}
const commandsCache = {}
const GBridge = {
callEnable: (ref, configArray) => {
commandsCache[ref] = [];
return GCanvasModule.enable({
componentId: ref,
config: configArray
});
},
callEnableDebug: () => {
isDebugging = true;
},
callEnableDisableCombo: () => {
isComboDisabled = true;
},
callSetContextType: function (componentId, context_type) {
GCanvasModule.setContextType(context_type, componentId);
},
callReset: function(id){
GCanvasModule.resetComponent && canvasModule.resetComponent(componentId);
},
render: isWeexIOS ? function (componentId) {
return GCanvasModule.extendCallNative({
contextId: componentId,
type: 0x60000001
});
} : function (componentId) {
return callGCanvasLinkNative(componentId, 0x60000001, 'render');
},
render2d: isWeexIOS ? function (componentId, commands, callback) {
if (isDebugging) {
console.log('>>> >>> render2d ===');
console.log('>>> commands: ' + commands);
}
GCanvasModule.render([commands, callback?true:false], componentId, callback);
} : function (componentId, commands,callback) {
if (isDebugging) {
console.log('>>> >>> render2d ===');
console.log('>>> commands: ' + commands);
}
callGCanvasLinkNative(componentId, 0x20000001, commands);
if(callback){
callback();
}
},
callExtendCallNative: isWeexIOS ? function (componentId, cmdArgs) {
throw 'should not be here anymore ' + cmdArgs;
} : function (componentId, cmdArgs) {
throw 'should not be here anymore ' + cmdArgs;
},
flushNative: isWeexIOS ? function (componentId) {
const cmdArgs = joinArray(commandsCache[componentId], ';');
commandsCache[componentId] = [];
if (isDebugging) {
console.log('>>> >>> flush native ===');
console.log('>>> commands: ' + cmdArgs);
}
const result = GCanvasModule.extendCallNative({
"contextId": componentId,
"type": 0x60000000,
"args": cmdArgs
});
const res = result && result.result;
if (isDebugging) {
console.log('>>> result: ' + res);
}
return res;
} : function (componentId) {
const cmdArgs = joinArray(commandsCache[componentId], ';');
commandsCache[componentId] = [];
if (isDebugging) {
console.log('>>> >>> flush native ===');
console.log('>>> commands: ' + cmdArgs);
}
const result = callGCanvasLinkNative(componentId, 0x60000000, cmdArgs);
if (isDebugging) {
console.log('>>> result: ' + result);
}
return result;
},
callNative: function (componentId, cmdArgs, cache) {
if (isDebugging) {
logCommand(componentId, cmdArgs);
}
commandsCache[componentId].push(cmdArgs);
if (!cache || isComboDisabled) {
return GBridge.flushNative(componentId);
} else {
return undefined;
}
},
texImage2D(componentId, ...args) {
if (isWeexIOS) {
if (args.length === 6) {
const [target, level, internalformat, format, type, image] = args;
GBridge.callNative(
componentId,
GLmethod.texImage2D + ',' + 6 + ',' + target + ',' + level + ',' + internalformat + ',' + format + ',' + type + ',' + image.src
)
} else if (args.length === 9) {
const [target, level, internalformat, width, height, border, format, type, image] = args;
GBridge.callNative(
componentId,
GLmethod.texImage2D + ',' + 9 + ',' + target + ',' + level + ',' + internalformat + ',' + width + ',' + height + ',' + border + ',' +
+ format + ',' + type + ',' + (image ? image.src : 0)
)
}
} else if (isWeexAndroid) {
if (args.length === 6) {
const [target, level, internalformat, format, type, image] = args;
GCanvasModule.texImage2D(componentId, target, level, internalformat, format, type, image.src);
} else if (args.length === 9) {
const [target, level, internalformat, width, height, border, format, type, image] = args;
GCanvasModule.texImage2D(componentId, target, level, internalformat, width, height, border, format, type, (image ? image.src : 0));
}
}
},
texSubImage2D(componentId, target, level, xoffset, yoffset, format, type, image) {
if (isWeexIOS) {
if (arguments.length === 8) {
GBridge.callNative(
componentId,
GLmethod.texSubImage2D + ',' + 6 + ',' + target + ',' + level + ',' + xoffset + ',' + yoffset, + ',' + format + ',' + type + ',' + image.src
)
}
} else if (isWeexAndroid) {
GCanvasModule.texSubImage2D(componentId, target, level, xoffset, yoffset, format, type, image.src);
}
},
bindImageTexture(componentId, src, imageId) {
GCanvasModule.bindImageTexture([src, imageId], componentId);
},
perloadImage([url, id], callback) {
GCanvasModule.preLoadImage([url, id], function (image) {
image.url = url;
image.id = id;
callback(image);
});
},
measureText(text, fontStyle, componentId) {
return GCanvasModule.measureText([text, fontStyle], componentId);
},
getImageData (componentId, x, y, w, h, callback) {
GCanvasModule.getImageData([x, y,w,h],componentId,callback);
},
putImageData (componentId, data, x, y, w, h, callback) {
GCanvasModule.putImageData([x, y,w,h,data],componentId,callback);
},
toTempFilePath(componentId, x, y, width, height, destWidth, destHeight, fileType, quality, callback){
GCanvasModule.toTempFilePath([x, y, width,height, destWidth, destHeight, fileType, quality], componentId, callback);
}
}
export default GBridge;
\ No newline at end of file
class FillStyleLinearGradient {
constructor(x0, y0, x1, y1) {
this._start_pos = { _x: x0, _y: y0 };
this._end_pos = { _x: x1, _y: y1 };
this._stop_count = 0;
this._stops = [0, 0, 0, 0, 0];
}
addColorStop = function (pos, color) {
if (this._stop_count < 5 && 0.0 <= pos && pos <= 1.0) {
this._stops[this._stop_count] = { _pos: pos, _color: color };
this._stop_count++;
}
}
}
export default FillStyleLinearGradient;
\ No newline at end of file
class FillStylePattern {
constructor(img, pattern) {
this._style = pattern;
this._img = img;
}
}
export default FillStylePattern;
\ No newline at end of file
class FillStyleRadialGradient {
constructor(x0, y0, r0, x1, y1, r1) {
this._start_pos = { _x: x0, _y: y0, _r: r0 };
this._end_pos = { _x: x1, _y: y1, _r: r1 };
this._stop_count = 0;
this._stops = [0, 0, 0, 0, 0];
}
addColorStop(pos, color) {
if (this._stop_count < 5 && 0.0 <= pos && pos <= 1.0) {
this._stops[this._stop_count] = { _pos: pos, _color: color };
this._stop_count++;
}
}
}
export default FillStyleRadialGradient;
\ No newline at end of file
import FillStylePattern from './FillStylePattern';
import FillStyleLinearGradient from './FillStyleLinearGradient';
import FillStyleRadialGradient from './FillStyleRadialGradient';
import GImage from '../env/image.js';
import {
ArrayBufferToBase64,
Base64ToUint8ClampedArray
} from '../env/tool.js';
export default class CanvasRenderingContext2D {
_drawCommands = '';
_globalAlpha = 1.0;
_fillStyle = 'rgb(0,0,0)';
_strokeStyle = 'rgb(0,0,0)';
_lineWidth = 1;
_lineCap = 'butt';
_lineJoin = 'miter';
_miterLimit = 10;
_globalCompositeOperation = 'source-over';
_textAlign = 'start';
_textBaseline = 'alphabetic';
_font = '10px sans-serif';
_savedGlobalAlpha = [];
timer = null;
componentId = null;
_notCommitDrawImageCache = [];
_needRedrawImageCache = [];
_redrawCommands = '';
_autoSaveContext = true;
// _imageMap = new GHashMap();
// _textureMap = new GHashMap();
constructor() {
this.className = 'CanvasRenderingContext2D';
//this.save()
}
setFillStyle(value) {
this.fillStyle = value;
}
set fillStyle(value) {
this._fillStyle = value;
if (typeof(value) == 'string') {
this._drawCommands = this._drawCommands.concat("F" + value + ";");
} else if (value instanceof FillStylePattern) {
const image = value._img;
if (!image.complete) {
image.onload = () => {
var index = this._needRedrawImageCache.indexOf(image);
if (index > -1) {
this._needRedrawImageCache.splice(index, 1);
CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
this._redrawflush(true);
}
}
this._notCommitDrawImageCache.push(image);
} else {
CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
}
//CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
this._drawCommands = this._drawCommands.concat("G" + image._id + "," + value._style + ";");
} else if (value instanceof FillStyleLinearGradient) {
var command = "D" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," +
value._end_pos._x.toFixed(2) + "," + value._end_pos._y.toFixed(2) + "," +
value._stop_count;
for (var i = 0; i < value._stop_count; ++i) {
command += ("," + value._stops[i]._pos + "," + value._stops[i]._color);
}
this._drawCommands = this._drawCommands.concat(command + ";");
} else if (value instanceof FillStyleRadialGradient) {
var command = "H" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," + value._start_pos._r
.toFixed(2) + "," +
value._end_pos._x.toFixed(2) + "," + value._end_pos._y.toFixed(2) + "," + value._end_pos._r.toFixed(2) + "," +
value._stop_count;
for (var i = 0; i < value._stop_count; ++i) {
command += ("," + value._stops[i]._pos + "," + value._stops[i]._color);
}
this._drawCommands = this._drawCommands.concat(command + ";");
}
}
get fillStyle() {
return this._fillStyle;
}
get globalAlpha() {
return this._globalAlpha;
}
setGlobalAlpha(value) {
this.globalAlpha = value;
}
set globalAlpha(value) {
this._globalAlpha = value;
this._drawCommands = this._drawCommands.concat("a" + value.toFixed(2) + ";");
}
get strokeStyle() {
return this._strokeStyle;
}
setStrokeStyle(value) {
this.strokeStyle = value;
}
set strokeStyle(value) {
this._strokeStyle = value;
if (typeof(value) == 'string') {
this._drawCommands = this._drawCommands.concat("S" + value + ";");
} else if (value instanceof FillStylePattern) {
CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
this._drawCommands = this._drawCommands.concat("G" + image._id + "," + value._style + ";");
} else if (value instanceof FillStyleLinearGradient) {
var command = "D" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," +
value._end_pos._x.toFixed(2) + "," + value._end_pos._y.toFixed(2) + "," +
value._stop_count;
for (var i = 0; i < value._stop_count; ++i) {
command += ("," + value._stops[i]._pos + "," + value._stops[i]._color);
}
this._drawCommands = this._drawCommands.concat(command + ";");
} else if (value instanceof FillStyleRadialGradient) {
var command = "H" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," + value._start_pos._r
.toFixed(2) + "," +
value._end_pos._x.toFixed(2) + "," + value._end_pos._y + ",".toFixed(2) + value._end_pos._r.toFixed(2) + "," +
value._stop_count;
for (var i = 0; i < value._stop_count; ++i) {
command += ("," + value._stops[i]._pos + "," + value._stops[i]._color);
}
this._drawCommands = this._drawCommands.concat(command + ";");
}
}
get lineWidth() {
return this._lineWidth;
}
setLineWidth(value) {
this.lineWidth = value;
}
set lineWidth(value) {
this._lineWidth = value;
this._drawCommands = this._drawCommands.concat("W" + value + ";");
}
get lineCap() {
return this._lineCap;
}
setLineCap(value) {
this.lineCap = value;
}
set lineCap(value) {
this._lineCap = value;
this._drawCommands = this._drawCommands.concat("C" + value + ";");
}
get lineJoin() {
return this._lineJoin;
}
setLineJoin(value) {
this.lineJoin = value
}
set lineJoin(value) {
this._lineJoin = value;
this._drawCommands = this._drawCommands.concat("J" + value + ";");
}
get miterLimit() {
return this._miterLimit;
}
setMiterLimit(value) {
this.miterLimit = value
}
set miterLimit(value) {
this._miterLimit = value;
this._drawCommands = this._drawCommands.concat("M" + value + ";");
}
get globalCompositeOperation() {
return this._globalCompositeOperation;
}
set globalCompositeOperation(value) {
this._globalCompositeOperation = value;
let mode = 0;
switch (value) {
case "source-over":
mode = 0;
break;
case "source-atop":
mode = 5;
break;
case "source-in":
mode = 0;
break;
case "source-out":
mode = 2;
break;
case "destination-over":
mode = 4;
break;
case "destination-atop":
mode = 4;
break;
case "destination-in":
mode = 4;
break;
case "destination-out":
mode = 3;
break;
case "lighter":
mode = 1;
break;
case "copy":
mode = 2;
break;
case "xor":
mode = 6;
break;
default:
mode = 0;
}
this._drawCommands = this._drawCommands.concat("B" + mode + ";");
}
get textAlign() {
return this._textAlign;
}
setTextAlign(value) {
this.textAlign = value
}
set textAlign(value) {
this._textAlign = value;
let Align = 0;
switch (value) {
case "start":
Align = 0;
break;
case "end":
Align = 1;
break;
case "left":
Align = 2;
break;
case "center":
Align = 3;
break;
case "right":
Align = 4;
break;
default:
Align = 0;
}
this._drawCommands = this._drawCommands.concat("A" + Align + ";");
}
get textBaseline() {
return this._textBaseline;
}
setTextBaseline(value) {
this.textBaseline = value
}
set textBaseline(value) {
this._textBaseline = value;
let baseline = 0;
switch (value) {
case "alphabetic":
baseline = 0;
break;
case "middle":
baseline = 1;
break;
case "top":
baseline = 2;
break;
case "hanging":
baseline = 3;
break;
case "bottom":
baseline = 4;
break;
case "ideographic":
baseline = 5;
break;
default:
baseline = 0;
break;
}
this._drawCommands = this._drawCommands.concat("E" + baseline + ";");
}
get font() {
return this._font;
}
setFontSize(size) {
var str = this._font;
var strs = str.trim().split(/\s+/);
for (var i = 0; i < strs.length; i++) {
var values = ["normal", "italic", "oblique", "normal", "small-caps", "normal", "bold",
"bolder", "lighter", "100", "200", "300", "400", "500", "600", "700", "800", "900",
"normal", "ultra-condensed", "extra-condensed", "condensed", "semi-condensed",
"semi-expanded", "expanded", "extra-expanded", "ultra-expanded"
];
if (-1 == values.indexOf(strs[i].trim())) {
if (typeof size === 'string') {
strs[i] = size;
} else if (typeof size === 'number') {
strs[i] = String(size) + 'px';
}
break;
}
}
this.font = strs.join(" ");
}
set font(value) {
this._font = value;
this._drawCommands = this._drawCommands.concat("j" + value + ";");
}
setTransform(a, b, c, d, tx, ty) {
this._drawCommands = this._drawCommands.concat("t" +
(a === 1 ? "1" : a.toFixed(2)) + "," +
(b === 0 ? "0" : b.toFixed(2)) + "," +
(c === 0 ? "0" : c.toFixed(2)) + "," +
(d === 1 ? "1" : d.toFixed(2)) + "," + tx.toFixed(2) + "," + ty.toFixed(2) + ";");
}
transform(a, b, c, d, tx, ty) {
this._drawCommands = this._drawCommands.concat("f" +
(a === 1 ? "1" : a.toFixed(2)) + "," +
(b === 0 ? "0" : b.toFixed(2)) + "," +
(c === 0 ? "0" : c.toFixed(2)) + "," +
(d === 1 ? "1" : d.toFixed(2)) + "," + tx + "," + ty + ";");
}
resetTransform() {
this._drawCommands = this._drawCommands.concat("m;");
}
scale(a, d) {
this._drawCommands = this._drawCommands.concat("k" + a.toFixed(2) + "," +
d.toFixed(2) + ";");
}
rotate(angle) {
this._drawCommands = this._drawCommands
.concat("r" + angle.toFixed(6) + ";");
}
translate(tx, ty) {
this._drawCommands = this._drawCommands.concat("l" + tx.toFixed(2) + "," + ty.toFixed(2) + ";");
}
save() {
this._savedGlobalAlpha.push(this._globalAlpha);
this._drawCommands = this._drawCommands.concat("v;");
}
restore() {
this._drawCommands = this._drawCommands.concat("e;");
this._globalAlpha = this._savedGlobalAlpha.pop();
}
createPattern(img, pattern) {
if (typeof img === 'string') {
var imgObj = new GImage();
imgObj.src = img;
img = imgObj;
}
return new FillStylePattern(img, pattern);
}
createLinearGradient(x0, y0, x1, y1) {
return new FillStyleLinearGradient(x0, y0, x1, y1);
}
createRadialGradient = function(x0, y0, r0, x1, y1, r1) {
return new FillStyleRadialGradient(x0, y0, r0, x1, y1, r1);
};
createCircularGradient = function(x0, y0, r0) {
return new FillStyleRadialGradient(x0, y0, 0, x0, y0, r0);
};
strokeRect(x, y, w, h) {
this._drawCommands = this._drawCommands.concat("s" + x + "," + y + "," + w + "," + h + ";");
}
clearRect(x, y, w, h) {
this._drawCommands = this._drawCommands.concat("c" + x + "," + y + "," + w +
"," + h + ";");
}
clip() {
this._drawCommands = this._drawCommands.concat("p;");
}
resetClip() {
this._drawCommands = this._drawCommands.concat("q;");
}
closePath() {
this._drawCommands = this._drawCommands.concat("o;");
}
moveTo(x, y) {
this._drawCommands = this._drawCommands.concat("g" + x.toFixed(2) + "," + y.toFixed(2) + ";");
}
lineTo(x, y) {
this._drawCommands = this._drawCommands.concat("i" + x.toFixed(2) + "," + y.toFixed(2) + ";");
}
quadraticCurveTo = function(cpx, cpy, x, y) {
this._drawCommands = this._drawCommands.concat("u" + cpx + "," + cpy + "," + x + "," + y + ";");
}
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y, ) {
this._drawCommands = this._drawCommands.concat(
"z" + cp1x.toFixed(2) + "," + cp1y.toFixed(2) + "," + cp2x.toFixed(2) + "," + cp2y.toFixed(2) + "," +
x.toFixed(2) + "," + y.toFixed(2) + ";");
}
arcTo(x1, y1, x2, y2, radius) {
this._drawCommands = this._drawCommands.concat("h" + x1 + "," + y1 + "," + x2 + "," + y2 + "," + radius + ";");
}
beginPath() {
this._drawCommands = this._drawCommands.concat("b;");
}
fillRect(x, y, w, h) {
this._drawCommands = this._drawCommands.concat("n" + x + "," + y + "," + w +
"," + h + ";");
}
rect(x, y, w, h) {
this._drawCommands = this._drawCommands.concat("w" + x + "," + y + "," + w + "," + h + ";");
}
fill() {
this._drawCommands = this._drawCommands.concat("L;");
}
stroke(path) {
this._drawCommands = this._drawCommands.concat("x;");
}
arc(x, y, radius, startAngle, endAngle, anticlockwise) {
let ianticlockwise = 0;
if (anticlockwise) {
ianticlockwise = 1;
}
this._drawCommands = this._drawCommands.concat(
"y" + x.toFixed(2) + "," + y.toFixed(2) + "," +
radius.toFixed(2) + "," + startAngle + "," + endAngle + "," + ianticlockwise +
";"
);
}
fillText(text, x, y) {
let tmptext = text.replace(/!/g, "!!");
tmptext = tmptext.replace(/,/g, "!,");
tmptext = tmptext.replace(/;/g, "!;");
this._drawCommands = this._drawCommands.concat("T" + tmptext + "," + x + "," + y + ",0.0;");
}
strokeText = function(text, x, y) {
let tmptext = text.replace(/!/g, "!!");
tmptext = tmptext.replace(/,/g, "!,");
tmptext = tmptext.replace(/;/g, "!;");
this._drawCommands = this._drawCommands.concat("U" + tmptext + "," + x + "," + y + ",0.0;");
}
measureText(text) {
return CanvasRenderingContext2D.GBridge.measureText(text, this.font, this.componentId);
}
isPointInPath = function(x, y) {
throw new Error('GCanvas not supported yet');
}
drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh) {
if (typeof image === 'string') {
var imgObj = new GImage();
imgObj.src = image;
image = imgObj;
}
if (image instanceof GImage) {
if (!image.complete) {
imgObj.onload = () => {
var index = this._needRedrawImageCache.indexOf(image);
if (index > -1) {
this._needRedrawImageCache.splice(index, 1);
CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
this._redrawflush(true);
}
}
this._notCommitDrawImageCache.push(image);
} else {
CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
}
var srcArgs = [image, sx, sy, sw, sh, dx, dy, dw, dh];
var args = [];
for (var arg in srcArgs) {
if (typeof(srcArgs[arg]) != 'undefined') {
args.push(srcArgs[arg]);
}
}
this.__drawImage.apply(this, args);
//this.__drawImage(image,sx, sy, sw, sh, dx, dy, dw, dh);
}
}
__drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh) {
const numArgs = arguments.length;
function drawImageCommands() {
if (numArgs === 3) {
const x = parseFloat(sx) || 0.0;
const y = parseFloat(sy) || 0.0;
return ("d" + image._id + ",0,0," +
image.width + "," + image.height + "," +
x + "," + y + "," + image.width + "," + image.height + ";");
} else if (numArgs === 5) {
const x = parseFloat(sx) || 0.0;
const y = parseFloat(sy) || 0.0;
const width = parseInt(sw) || image.width;
const height = parseInt(sh) || image.height;
return ("d" + image._id + ",0,0," +
image.width + "," + image.height + "," +
x + "," + y + "," + width + "," + height + ";");
} else if (numArgs === 9) {
sx = parseFloat(sx) || 0.0;
sy = parseFloat(sy) || 0.0;
sw = parseInt(sw) || image.width;
sh = parseInt(sh) || image.height;
dx = parseFloat(dx) || 0.0;
dy = parseFloat(dy) || 0.0;
dw = parseInt(dw) || image.width;
dh = parseInt(dh) || image.height;
return ("d" + image._id + "," +
sx + "," + sy + "," + sw + "," + sh + "," +
dx + "," + dy + "," + dw + "," + dh + ";");
}
}
this._drawCommands += drawImageCommands();
}
_flush(reserve, callback) {
const commands = this._drawCommands;
this._drawCommands = '';
CanvasRenderingContext2D.GBridge.render2d(this.componentId, commands, callback);
this._needRender = false;
}
_redrawflush(reserve, callback) {
const commands = this._redrawCommands;
CanvasRenderingContext2D.GBridge.render2d(this.componentId, commands, callback);
if (this._needRedrawImageCache.length == 0) {
this._redrawCommands = '';
}
}
draw(reserve, callback) {
if (!reserve) {
this._globalAlpha = this._savedGlobalAlpha.pop();
this._savedGlobalAlpha.push(this._globalAlpha);
this._redrawCommands = this._drawCommands;
this._needRedrawImageCache = this._notCommitDrawImageCache;
if (this._autoSaveContext) {
this._drawCommands = ("v;" + this._drawCommands);
this._autoSaveContext = false;
} else {
this._drawCommands = ("e;X;v;" + this._drawCommands);
}
} else {
this._needRedrawImageCache = this._needRedrawImageCache.concat(this._notCommitDrawImageCache);
this._redrawCommands += this._drawCommands;
if (this._autoSaveContext) {
this._drawCommands = ("v;" + this._drawCommands);
this._autoSaveContext = false;
}
}
this._notCommitDrawImageCache = [];
if (this._flush) {
this._flush(reserve, callback);
}
}
getImageData(x, y, w, h, callback) {
CanvasRenderingContext2D.GBridge.getImageData(this.componentId, x, y, w, h, function(res) {
res.data = Base64ToUint8ClampedArray(res.data);
if (typeof(callback) == 'function') {
callback(res);
}
});
}
putImageData(data, x, y, w, h, callback) {
if (data instanceof Uint8ClampedArray) {
data = ArrayBufferToBase64(data);
CanvasRenderingContext2D.GBridge.putImageData(this.componentId, data, x, y, w, h, function(res) {
if (typeof(callback) == 'function') {
callback(res);
}
});
}
}
toTempFilePath(x, y, width, height, destWidth, destHeight, fileType, quality, callback) {
CanvasRenderingContext2D.GBridge.toTempFilePath(this.componentId, x, y, width, height, destWidth, destHeight,
fileType, quality,
function(res) {
if (typeof(callback) == 'function') {
callback(res);
}
});
}
}
export default class WebGLActiveInfo {
className = 'WebGLActiveInfo';
constructor({
type, name, size
}) {
this.type = type;
this.name = name;
this.size = size;
}
}
\ No newline at end of file
import {getTransferedObjectUUID} from './classUtils';
const name = 'WebGLBuffer';
function uuid(id) {
return getTransferedObjectUUID(name, id);
}
export default class WebGLBuffer {
className = name;
constructor(id) {
this.id = id;
}
static uuid = uuid;
uuid() {
return uuid(this.id);
}
}
\ No newline at end of file
import {getTransferedObjectUUID} from './classUtils';
const name = 'WebGLFrameBuffer';
function uuid(id) {
return getTransferedObjectUUID(name, id);
}
export default class WebGLFramebuffer {
className = name;
constructor(id) {
this.id = id;
}
static uuid = uuid;
uuid() {
return uuid(this.id);
}
}
\ No newline at end of file
export default {
"DEPTH_BUFFER_BIT": 256,
"STENCIL_BUFFER_BIT": 1024,
"COLOR_BUFFER_BIT": 16384,
"POINTS": 0,
"LINES": 1,
"LINE_LOOP": 2,
"LINE_STRIP": 3,
"TRIANGLES": 4,
"TRIANGLE_STRIP": 5,
"TRIANGLE_FAN": 6,
"ZERO": 0,
"ONE": 1,
"SRC_COLOR": 768,
"ONE_MINUS_SRC_COLOR": 769,
"SRC_ALPHA": 770,
"ONE_MINUS_SRC_ALPHA": 771,
"DST_ALPHA": 772,
"ONE_MINUS_DST_ALPHA": 773,
"DST_COLOR": 774,
"ONE_MINUS_DST_COLOR": 775,
"SRC_ALPHA_SATURATE": 776,
"FUNC_ADD": 32774,
"BLEND_EQUATION": 32777,
"BLEND_EQUATION_RGB": 32777,
"BLEND_EQUATION_ALPHA": 34877,
"FUNC_SUBTRACT": 32778,
"FUNC_REVERSE_SUBTRACT": 32779,
"BLEND_DST_RGB": 32968,
"BLEND_SRC_RGB": 32969,
"BLEND_DST_ALPHA": 32970,
"BLEND_SRC_ALPHA": 32971,
"CONSTANT_COLOR": 32769,
"ONE_MINUS_CONSTANT_COLOR": 32770,
"CONSTANT_ALPHA": 32771,
"ONE_MINUS_CONSTANT_ALPHA": 32772,
"BLEND_COLOR": 32773,
"ARRAY_BUFFER": 34962,
"ELEMENT_ARRAY_BUFFER": 34963,
"ARRAY_BUFFER_BINDING": 34964,
"ELEMENT_ARRAY_BUFFER_BINDING": 34965,
"STREAM_DRAW": 35040,
"STATIC_DRAW": 35044,
"DYNAMIC_DRAW": 35048,
"BUFFER_SIZE": 34660,
"BUFFER_USAGE": 34661,
"CURRENT_VERTEX_ATTRIB": 34342,
"FRONT": 1028,
"BACK": 1029,
"FRONT_AND_BACK": 1032,
"TEXTURE_2D": 3553,
"CULL_FACE": 2884,
"BLEND": 3042,
"DITHER": 3024,
"STENCIL_TEST": 2960,
"DEPTH_TEST": 2929,
"SCISSOR_TEST": 3089,
"POLYGON_OFFSET_FILL": 32823,
"SAMPLE_ALPHA_TO_COVERAGE": 32926,
"SAMPLE_COVERAGE": 32928,
"NO_ERROR": 0,
"INVALID_ENUM": 1280,
"INVALID_VALUE": 1281,
"INVALID_OPERATION": 1282,
"OUT_OF_MEMORY": 1285,
"CW": 2304,
"CCW": 2305,
"LINE_WIDTH": 2849,
"ALIASED_POINT_SIZE_RANGE": 33901,
"ALIASED_LINE_WIDTH_RANGE": 33902,
"CULL_FACE_MODE": 2885,
"FRONT_FACE": 2886,
"DEPTH_RANGE": 2928,
"DEPTH_WRITEMASK": 2930,
"DEPTH_CLEAR_VALUE": 2931,
"DEPTH_FUNC": 2932,
"STENCIL_CLEAR_VALUE": 2961,
"STENCIL_FUNC": 2962,
"STENCIL_FAIL": 2964,
"STENCIL_PASS_DEPTH_FAIL": 2965,
"STENCIL_PASS_DEPTH_PASS": 2966,
"STENCIL_REF": 2967,
"STENCIL_VALUE_MASK": 2963,
"STENCIL_WRITEMASK": 2968,
"STENCIL_BACK_FUNC": 34816,
"STENCIL_BACK_FAIL": 34817,
"STENCIL_BACK_PASS_DEPTH_FAIL": 34818,
"STENCIL_BACK_PASS_DEPTH_PASS": 34819,
"STENCIL_BACK_REF": 36003,
"STENCIL_BACK_VALUE_MASK": 36004,
"STENCIL_BACK_WRITEMASK": 36005,
"VIEWPORT": 2978,
"SCISSOR_BOX": 3088,
"COLOR_CLEAR_VALUE": 3106,
"COLOR_WRITEMASK": 3107,
"UNPACK_ALIGNMENT": 3317,
"PACK_ALIGNMENT": 3333,
"MAX_TEXTURE_SIZE": 3379,
"MAX_VIEWPORT_DIMS": 3386,
"SUBPIXEL_BITS": 3408,
"RED_BITS": 3410,
"GREEN_BITS": 3411,
"BLUE_BITS": 3412,
"ALPHA_BITS": 3413,
"DEPTH_BITS": 3414,
"STENCIL_BITS": 3415,
"POLYGON_OFFSET_UNITS": 10752,
"POLYGON_OFFSET_FACTOR": 32824,
"TEXTURE_BINDING_2D": 32873,
"SAMPLE_BUFFERS": 32936,
"SAMPLES": 32937,
"SAMPLE_COVERAGE_VALUE": 32938,
"SAMPLE_COVERAGE_INVERT": 32939,
"COMPRESSED_TEXTURE_FORMATS": 34467,
"DONT_CARE": 4352,
"FASTEST": 4353,
"NICEST": 4354,
"GENERATE_MIPMAP_HINT": 33170,
"BYTE": 5120,
"UNSIGNED_BYTE": 5121,
"SHORT": 5122,
"UNSIGNED_SHORT": 5123,
"INT": 5124,
"UNSIGNED_INT": 5125,
"FLOAT": 5126,
"DEPTH_COMPONENT": 6402,
"ALPHA": 6406,
"RGB": 6407,
"RGBA": 6408,
"LUMINANCE": 6409,
"LUMINANCE_ALPHA": 6410,
"UNSIGNED_SHORT_4_4_4_4": 32819,
"UNSIGNED_SHORT_5_5_5_1": 32820,
"UNSIGNED_SHORT_5_6_5": 33635,
"FRAGMENT_SHADER": 35632,
"VERTEX_SHADER": 35633,
"MAX_VERTEX_ATTRIBS": 34921,
"MAX_VERTEX_UNIFORM_VECTORS": 36347,
"MAX_VARYING_VECTORS": 36348,
"MAX_COMBINED_TEXTURE_IMAGE_UNITS": 35661,
"MAX_VERTEX_TEXTURE_IMAGE_UNITS": 35660,
"MAX_TEXTURE_IMAGE_UNITS": 34930,
"MAX_FRAGMENT_UNIFORM_VECTORS": 36349,
"SHADER_TYPE": 35663,
"DELETE_STATUS": 35712,
"LINK_STATUS": 35714,
"VALIDATE_STATUS": 35715,
"ATTACHED_SHADERS": 35717,
"ACTIVE_UNIFORMS": 35718,
"ACTIVE_ATTRIBUTES": 35721,
"SHADING_LANGUAGE_VERSION": 35724,
"CURRENT_PROGRAM": 35725,
"NEVER": 512,
"LESS": 513,
"EQUAL": 514,
"LEQUAL": 515,
"GREATER": 516,
"NOTEQUAL": 517,
"GEQUAL": 518,
"ALWAYS": 519,
"KEEP": 7680,
"REPLACE": 7681,
"INCR": 7682,
"DECR": 7683,
"INVERT": 5386,
"INCR_WRAP": 34055,
"DECR_WRAP": 34056,
"VENDOR": 7936,
"RENDERER": 7937,
"VERSION": 7938,
"NEAREST": 9728,
"LINEAR": 9729,
"NEAREST_MIPMAP_NEAREST": 9984,
"LINEAR_MIPMAP_NEAREST": 9985,
"NEAREST_MIPMAP_LINEAR": 9986,
"LINEAR_MIPMAP_LINEAR": 9987,
"TEXTURE_MAG_FILTER": 10240,
"TEXTURE_MIN_FILTER": 10241,
"TEXTURE_WRAP_S": 10242,
"TEXTURE_WRAP_T": 10243,
"TEXTURE": 5890,
"TEXTURE_CUBE_MAP": 34067,
"TEXTURE_BINDING_CUBE_MAP": 34068,
"TEXTURE_CUBE_MAP_POSITIVE_X": 34069,
"TEXTURE_CUBE_MAP_NEGATIVE_X": 34070,
"TEXTURE_CUBE_MAP_POSITIVE_Y": 34071,
"TEXTURE_CUBE_MAP_NEGATIVE_Y": 34072,
"TEXTURE_CUBE_MAP_POSITIVE_Z": 34073,
"TEXTURE_CUBE_MAP_NEGATIVE_Z": 34074,
"MAX_CUBE_MAP_TEXTURE_SIZE": 34076,
"TEXTURE0": 33984,
"TEXTURE1": 33985,
"TEXTURE2": 33986,
"TEXTURE3": 33987,
"TEXTURE4": 33988,
"TEXTURE5": 33989,
"TEXTURE6": 33990,
"TEXTURE7": 33991,
"TEXTURE8": 33992,
"TEXTURE9": 33993,
"TEXTURE10": 33994,
"TEXTURE11": 33995,
"TEXTURE12": 33996,
"TEXTURE13": 33997,
"TEXTURE14": 33998,
"TEXTURE15": 33999,
"TEXTURE16": 34000,
"TEXTURE17": 34001,
"TEXTURE18": 34002,
"TEXTURE19": 34003,
"TEXTURE20": 34004,
"TEXTURE21": 34005,
"TEXTURE22": 34006,
"TEXTURE23": 34007,
"TEXTURE24": 34008,
"TEXTURE25": 34009,
"TEXTURE26": 34010,
"TEXTURE27": 34011,
"TEXTURE28": 34012,
"TEXTURE29": 34013,
"TEXTURE30": 34014,
"TEXTURE31": 34015,
"ACTIVE_TEXTURE": 34016,
"REPEAT": 10497,
"CLAMP_TO_EDGE": 33071,
"MIRRORED_REPEAT": 33648,
"FLOAT_VEC2": 35664,
"FLOAT_VEC3": 35665,
"FLOAT_VEC4": 35666,
"INT_VEC2": 35667,
"INT_VEC3": 35668,
"INT_VEC4": 35669,
"BOOL": 35670,
"BOOL_VEC2": 35671,
"BOOL_VEC3": 35672,
"BOOL_VEC4": 35673,
"FLOAT_MAT2": 35674,
"FLOAT_MAT3": 35675,
"FLOAT_MAT4": 35676,
"SAMPLER_2D": 35678,
"SAMPLER_CUBE": 35680,
"VERTEX_ATTRIB_ARRAY_ENABLED": 34338,
"VERTEX_ATTRIB_ARRAY_SIZE": 34339,
"VERTEX_ATTRIB_ARRAY_STRIDE": 34340,
"VERTEX_ATTRIB_ARRAY_TYPE": 34341,
"VERTEX_ATTRIB_ARRAY_NORMALIZED": 34922,
"VERTEX_ATTRIB_ARRAY_POINTER": 34373,
"VERTEX_ATTRIB_ARRAY_BUFFER_BINDING": 34975,
"IMPLEMENTATION_COLOR_READ_TYPE": 35738,
"IMPLEMENTATION_COLOR_READ_FORMAT": 35739,
"COMPILE_STATUS": 35713,
"LOW_FLOAT": 36336,
"MEDIUM_FLOAT": 36337,
"HIGH_FLOAT": 36338,
"LOW_INT": 36339,
"MEDIUM_INT": 36340,
"HIGH_INT": 36341,
"FRAMEBUFFER": 36160,
"RENDERBUFFER": 36161,
"RGBA4": 32854,
"RGB5_A1": 32855,
"RGB565": 36194,
"DEPTH_COMPONENT16": 33189,
"STENCIL_INDEX8": 36168,
"DEPTH_STENCIL": 34041,
"RENDERBUFFER_WIDTH": 36162,
"RENDERBUFFER_HEIGHT": 36163,
"RENDERBUFFER_INTERNAL_FORMAT": 36164,
"RENDERBUFFER_RED_SIZE": 36176,
"RENDERBUFFER_GREEN_SIZE": 36177,
"RENDERBUFFER_BLUE_SIZE": 36178,
"RENDERBUFFER_ALPHA_SIZE": 36179,
"RENDERBUFFER_DEPTH_SIZE": 36180,
"RENDERBUFFER_STENCIL_SIZE": 36181,
"FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE": 36048,
"FRAMEBUFFER_ATTACHMENT_OBJECT_NAME": 36049,
"FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL": 36050,
"FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE": 36051,
"COLOR_ATTACHMENT0": 36064,
"DEPTH_ATTACHMENT": 36096,
"STENCIL_ATTACHMENT": 36128,
"DEPTH_STENCIL_ATTACHMENT": 33306,
"NONE": 0,
"FRAMEBUFFER_COMPLETE": 36053,
"FRAMEBUFFER_INCOMPLETE_ATTACHMENT": 36054,
"FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT": 36055,
"FRAMEBUFFER_INCOMPLETE_DIMENSIONS": 36057,
"FRAMEBUFFER_UNSUPPORTED": 36061,
"FRAMEBUFFER_BINDING": 36006,
"RENDERBUFFER_BINDING": 36007,
"MAX_RENDERBUFFER_SIZE": 34024,
"INVALID_FRAMEBUFFER_OPERATION": 1286,
"UNPACK_FLIP_Y_WEBGL": 37440,
"UNPACK_PREMULTIPLY_ALPHA_WEBGL": 37441,
"CONTEXT_LOST_WEBGL": 37442,
"UNPACK_COLORSPACE_CONVERSION_WEBGL": 37443,
"BROWSER_DEFAULT_WEBGL": 37444
};
\ No newline at end of file
let i = 1;
const GLmethod = {};
GLmethod.activeTexture = i++; //1
GLmethod.attachShader = i++;
GLmethod.bindAttribLocation = i++;
GLmethod.bindBuffer = i++;
GLmethod.bindFramebuffer = i++;
GLmethod.bindRenderbuffer = i++;
GLmethod.bindTexture = i++;
GLmethod.blendColor = i++;
GLmethod.blendEquation = i++;
GLmethod.blendEquationSeparate = i++; //10
GLmethod.blendFunc = i++;
GLmethod.blendFuncSeparate = i++;
GLmethod.bufferData = i++;
GLmethod.bufferSubData = i++;
GLmethod.checkFramebufferStatus = i++;
GLmethod.clear = i++;
GLmethod.clearColor = i++;
GLmethod.clearDepth = i++;
GLmethod.clearStencil = i++;
GLmethod.colorMask = i++; //20
GLmethod.compileShader = i++;
GLmethod.compressedTexImage2D = i++;
GLmethod.compressedTexSubImage2D = i++;
GLmethod.copyTexImage2D = i++;
GLmethod.copyTexSubImage2D = i++;
GLmethod.createBuffer = i++;
GLmethod.createFramebuffer = i++;
GLmethod.createProgram = i++;
GLmethod.createRenderbuffer = i++;
GLmethod.createShader = i++; //30
GLmethod.createTexture = i++;
GLmethod.cullFace = i++;
GLmethod.deleteBuffer = i++;
GLmethod.deleteFramebuffer = i++;
GLmethod.deleteProgram = i++;
GLmethod.deleteRenderbuffer = i++;
GLmethod.deleteShader = i++;
GLmethod.deleteTexture = i++;
GLmethod.depthFunc = i++;
GLmethod.depthMask = i++; //40
GLmethod.depthRange = i++;
GLmethod.detachShader = i++;
GLmethod.disable = i++;
GLmethod.disableVertexAttribArray = i++;
GLmethod.drawArrays = i++;
GLmethod.drawArraysInstancedANGLE = i++;
GLmethod.drawElements = i++;
GLmethod.drawElementsInstancedANGLE = i++;
GLmethod.enable = i++;
GLmethod.enableVertexAttribArray = i++; //50
GLmethod.flush = i++;
GLmethod.framebufferRenderbuffer = i++;
GLmethod.framebufferTexture2D = i++;
GLmethod.frontFace = i++;
GLmethod.generateMipmap = i++;
GLmethod.getActiveAttrib = i++;
GLmethod.getActiveUniform = i++;
GLmethod.getAttachedShaders = i++;
GLmethod.getAttribLocation = i++;
GLmethod.getBufferParameter = i++; //60
GLmethod.getContextAttributes = i++;
GLmethod.getError = i++;
GLmethod.getExtension = i++;
GLmethod.getFramebufferAttachmentParameter = i++;
GLmethod.getParameter = i++;
GLmethod.getProgramInfoLog = i++;
GLmethod.getProgramParameter = i++;
GLmethod.getRenderbufferParameter = i++;
GLmethod.getShaderInfoLog = i++;
GLmethod.getShaderParameter = i++; //70
GLmethod.getShaderPrecisionFormat = i++;
GLmethod.getShaderSource = i++;
GLmethod.getSupportedExtensions = i++;
GLmethod.getTexParameter = i++;
GLmethod.getUniform = i++;
GLmethod.getUniformLocation = i++;
GLmethod.getVertexAttrib = i++;
GLmethod.getVertexAttribOffset = i++;
GLmethod.isBuffer = i++;
GLmethod.isContextLost = i++; //80
GLmethod.isEnabled = i++;
GLmethod.isFramebuffer = i++;
GLmethod.isProgram = i++;
GLmethod.isRenderbuffer = i++;
GLmethod.isShader = i++;
GLmethod.isTexture = i++;
GLmethod.lineWidth = i++;
GLmethod.linkProgram = i++;
GLmethod.pixelStorei = i++;
GLmethod.polygonOffset = i++; //90
GLmethod.readPixels = i++;
GLmethod.renderbufferStorage = i++;
GLmethod.sampleCoverage = i++;
GLmethod.scissor = i++;
GLmethod.shaderSource = i++;
GLmethod.stencilFunc = i++;
GLmethod.stencilFuncSeparate = i++;
GLmethod.stencilMask = i++;
GLmethod.stencilMaskSeparate = i++;
GLmethod.stencilOp = i++; //100
GLmethod.stencilOpSeparate = i++;
GLmethod.texImage2D = i++;
GLmethod.texParameterf = i++;
GLmethod.texParameteri = i++;
GLmethod.texSubImage2D = i++;
GLmethod.uniform1f = i++;
GLmethod.uniform1fv = i++;
GLmethod.uniform1i = i++;
GLmethod.uniform1iv = i++;
GLmethod.uniform2f = i++; //110
GLmethod.uniform2fv = i++;
GLmethod.uniform2i = i++;
GLmethod.uniform2iv = i++;
GLmethod.uniform3f = i++;
GLmethod.uniform3fv = i++;
GLmethod.uniform3i = i++;
GLmethod.uniform3iv = i++;
GLmethod.uniform4f = i++;
GLmethod.uniform4fv = i++;
GLmethod.uniform4i = i++; //120
GLmethod.uniform4iv = i++;
GLmethod.uniformMatrix2fv = i++;
GLmethod.uniformMatrix3fv = i++;
GLmethod.uniformMatrix4fv = i++;
GLmethod.useProgram = i++;
GLmethod.validateProgram = i++;
GLmethod.vertexAttrib1f = i++; //new
GLmethod.vertexAttrib2f = i++; //new
GLmethod.vertexAttrib3f = i++; //new
GLmethod.vertexAttrib4f = i++; //new //130
GLmethod.vertexAttrib1fv = i++; //new
GLmethod.vertexAttrib2fv = i++; //new
GLmethod.vertexAttrib3fv = i++; //new
GLmethod.vertexAttrib4fv = i++; //new
GLmethod.vertexAttribPointer = i++;
GLmethod.viewport = i++;
export default GLmethod;
\ No newline at end of file
const GLtype = {};
[
"GLbitfield",
"GLboolean",
"GLbyte",
"GLclampf",
"GLenum",
"GLfloat",
"GLint",
"GLintptr",
"GLsizei",
"GLsizeiptr",
"GLshort",
"GLubyte",
"GLuint",
"GLushort"
].sort().map((typeName, i) => GLtype[typeName] = 1 >> (i + 1));
export default GLtype;
import {getTransferedObjectUUID} from './classUtils';
const name = 'WebGLProgram';
function uuid(id) {
return getTransferedObjectUUID(name, id);
}
export default class WebGLProgram {
className = name;
constructor(id) {
this.id = id;
}
static uuid = uuid;
uuid() {
return uuid(this.id);
}
}
\ No newline at end of file
import {getTransferedObjectUUID} from './classUtils';
const name = 'WebGLRenderBuffer';
function uuid(id) {
return getTransferedObjectUUID(name, id);
}
export default class WebGLRenderbuffer {
className = name;
constructor(id) {
this.id = id;
}
static uuid = uuid;
uuid() {
return uuid(this.id);
}
}
\ No newline at end of file
import GLenum from './GLenum';
import ActiveInfo from './ActiveInfo';
import Buffer from './Buffer';
import Framebuffer from './Framebuffer';
import Renderbuffer from './Renderbuffer';
import Texture from './Texture';
import Program from './Program';
import Shader from './Shader';
import ShaderPrecisionFormat from './ShaderPrecisionFormat';
import UniformLocation from './UniformLocation';
import GLmethod from './GLmethod';
const processArray = (array, checkArrayType = false) => {
function joinArray(arr, sep) {
let res = '';
for (let i = 0; i < arr.length; i++) {
if (i !== 0) {
res += sep;
}
res += arr[i];
}
return res;
}
let type = 'Float32Array';
if (checkArrayType) {
if (array instanceof Uint8Array) {
type = 'Uint8Array'
} else if (array instanceof Uint16Array) {
type = 'Uint16Array';
} else if (array instanceof Uint32Array) {
type = 'Uint32Array';
} else if (array instanceof Float32Array) {
type = 'Float32Array';
} else {
throw new Error('Check array type failed. Array type is ' + typeof array);
}
}
const ArrayTypes = {
Uint8Array: 1,
Uint16Array: 2,
Uint32Array: 4,
Float32Array: 14
};
return ArrayTypes[type] + ',' + btoa(joinArray(array, ','))
}
export default class WebGLRenderingContext {
// static GBridge = null;
className = 'WebGLRenderingContext';
constructor(canvas, type, attrs) {
this._canvas = canvas;
this._type = type;
this._version = 'WebGL 1.0';
this._attrs = attrs;
this._map = new Map();
Object.keys(GLenum)
.forEach(name => Object.defineProperty(this, name, {
value: GLenum[name]
}));
}
get canvas() {
return this._canvas;
}
activeTexture = function (textureUnit) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.activeTexture + ',' + textureUnit,
true
);
}
attachShader = function (progarm, shader) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.attachShader + ',' + progarm.id + ',' + shader.id,
true
);
}
bindAttribLocation = function (program, index, name) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.bindAttribLocation + ',' + program.id + ',' + index + ',' + name,
true
)
}
bindBuffer = function (target, buffer) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.bindBuffer + ',' + target + ',' + (buffer ? buffer.id : 0),
true
);
}
bindFramebuffer = function (target, framebuffer) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.bindFramebuffer + ',' + target + ',' + (framebuffer ? framebuffer.id : 0),
true
)
}
bindRenderbuffer = function (target, renderBuffer) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.bindRenderbuffer + ',' + target + ',' + (renderBuffer ? renderBuffer.id : 0),
true
)
}
bindTexture = function (target, texture) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.bindTexture + ',' + target + ',' + (texture ? texture.id : 0),
true
)
}
blendColor = function (r, g, b, a) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.blendColor + ',' + target + ',' + r + ',' + g + ',' + b + ',' + a,
true
)
}
blendEquation = function (mode) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.blendEquation + ',' + mode,
true
)
}
blendEquationSeparate = function (modeRGB, modeAlpha) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.blendEquationSeparate + ',' + modeRGB + ',' + modeAlpha,
true
)
}
blendFunc = function (sfactor, dfactor) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.blendFunc + ',' + sfactor + ',' + dfactor,
true
);
}
blendFuncSeparate = function (srcRGB, dstRGB, srcAlpha, dstAlpha) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.blendFuncSeparate + ',' + srcRGB + ',' + dstRGB + ',' + srcAlpha + ',' + dstAlpha,
true
);
}
bufferData = function (target, data, usage) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.bufferData + ',' + target + ',' + processArray(data, true) + ',' + usage,
true
)
}
bufferSubData = function (target, offset, data) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.bufferSubData + ',' + target + ',' + offset + ',' + processArray(data, true),
true
)
}
checkFramebufferStatus = function (target) {
const result = WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.checkFramebufferStatus + ',' + target
);
return Number(result);
}
clear = function (mask) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.clear + ',' + mask
);
this._canvas._needRender = true;
}
clearColor = function (r, g, b, a) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.clearColor + ',' + r + ',' + g + ',' + b,
true
)
}
clearDepth = function (depth) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.clearDepth + ',' + depth,
true
)
}
clearStencil = function (s) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.clearStencil + ',' + s
);
}
colorMask = function (r, g, b, a) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.colorMask + ',' + r + ',' + g + ',' + b + ',' + a
)
}
compileShader = function (shader) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.compileShader + ',' + shader.id,
true
)
}
compressedTexImage2D = function (target, level, internalformat, width, height, border, pixels) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.compressedTexImage2D + ',' + target + ',' + level + ',' + internalformat + ',' +
width + ',' + height + ',' + border + ',' + processArray(pixels),
true
)
}
compressedTexSubImage2D = function (target, level, xoffset, yoffset, width, height, format, pixels) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.compressedTexSubImage2D + ',' + target + ',' + level + ',' + xoffset + ',' + yoffset + ',' +
width + ',' + height + ',' + format + ',' + processArray(pixels),
true
)
}
copyTexImage2D = function (target, level, internalformat, x, y, width, height, border) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.copyTexImage2D + ',' + target + ',' + level + ',' + internalformat + ',' + x + ',' + y + ',' +
width + ',' + height + ',' + border,
true
);
}
copyTexSubImage2D = function (target, level, xoffset, yoffset, x, y, width, height) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.copyTexSubImage2D + ',' + target + ',' + level + ',' + xoffset + ',' + yoffset + ',' + x + ',' + y + ',' +
width + ',' + height
);
}
createBuffer = function () {
const result = WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.createBuffer + ''
);
const buffer = new Buffer(result);
this._map.set(buffer.uuid(), buffer);
return buffer;
}
createFramebuffer = function () {
const result = WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.createFramebuffer + ''
);
const framebuffer = new Framebuffer(result);
this._map.set(framebuffer.uuid(), framebuffer);
return framebuffer;
}
createProgram = function () {
const id = WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.createProgram + ''
);
const program = new Program(id);
this._map.set(program.uuid(), program);
return program;
}
createRenderbuffer = function () {
const id = WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.createRenderbuffer + ''
)
const renderBuffer = new Renderbuffer(id);
this._map.set(renderBuffer.uuid(), renderBuffer);
return renderBuffer;
}
createShader = function (type) {
const id = WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.createShader + ',' + type
)
const shader = new Shader(id, type);
this._map.set(shader.uuid(), shader);
return shader;
}
createTexture = function () {
const id = WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.createTexture + ''
);
const texture = new Texture(id);
this._map.set(texture.uuid(), texture);
return texture;
}
cullFace = function (mode) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.cullFace + ',' + mode,
true
)
}
deleteBuffer = function (buffer) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.deleteBuffer + ',' + buffer.id,
true
)
}
deleteFramebuffer = function (framebuffer) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.deleteFramebuffer + ',' + framebuffer.id,
true
)
}
deleteProgram = function (program) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.deleteProgram + ',' + program.id,
true
)
}
deleteRenderbuffer = function (renderbuffer) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.deleteRenderbuffer + ',' + renderbuffer.id,
true
)
}
deleteShader = function (shader) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.deleteShader + ',' + shader.id,
true
)
}
deleteTexture = function (texture) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.deleteTexture + ',' + texture.id,
true
)
}
depthFunc = function (func) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.depthFunc + ',' + func
)
}
depthMask = function (flag) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.depthMask + ',' + Number(flag),
true
)
}
depthRange = function (zNear, zFar) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.depthRange + ',' + zNear + ',' + zFar,
true
)
}
detachShader = function (program, shader) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.detachShader + ',' + program.id + ',' + shader.id,
true
)
}
disable = function (cap) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.disable + ',' + cap,
true
)
}
disableVertexAttribArray = function (index) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.disableVertexAttribArray + ',' + index,
true
);
}
drawArrays = function (mode, first, count) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.drawArrays + ',' + mode + ',' + first + ',' + count
)
this._canvas._needRender = true;
}
drawElements = function (mode, count, type, offset) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.drawElements + ',' + mode + ',' + count + ',' + type + ',' + offset + ';'
);
this._canvas._needRender = true;
}
enable = function (cap) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.enable + ',' + cap,
true
);
}
enableVertexAttribArray = function (index) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.enableVertexAttribArray + ',' + index,
true
)
}
flush = function () {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.flush + ''
)
}
framebufferRenderbuffer = function (target, attachment, textarget, texture, level) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.framebufferRenderbuffer + ',' + target + ',' + attachment + ',' + textarget + ',' + (texture ? texture.id : 0) + ',' + level,
true
)
}
framebufferTexture2D = function (target, attachment, textarget, texture, level) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.framebufferTexture2D + ',' + target + ',' + attachment + ',' + textarget + ',' + (texture ? texture.id : 0) + ',' + level,
true
)
}
frontFace = function (mode) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.frontFace + ',' + mode,
true
)
}
generateMipmap = function (target) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.generateMipmap + ',' + target,
true
)
}
getActiveAttrib = function (progarm, index) {
const resultString = WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.getActiveAttrib + ',' + progarm.id + ',' + index
)
const [type, size, name] = resultString.split(',');
return new ActiveInfo({
type: Number(type),
size: Number(size),
name
});
}
getActiveUniform = function (progarm, index) {
const resultString = WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.getActiveUniform + ',' + progarm.id + ',' + index
);
const [type, size, name] = resultString.split(',');
return new ActiveInfo({
type: Number(type),
size: Number(size),
name
})
}
getAttachedShaders = function (progarm) {
const result = WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.getAttachedShaders + ',' + progarm.id
);
const [type, ...ids] = result;
return ids.map(id => this._map.get(Shader.uuid(id)));
}
getAttribLocation = function (progarm, name) {
return WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.getAttribLocation + ',' + progarm.id + ',' + name
)
}
getBufferParameter = function (target, pname) {
const result = WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.getBufferParameter + ',' + target + ',' + pname
);
const [type, res] = getBufferParameter;
return res;
}
getError = function () {
const result = WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.getError + ''
)
return result;
}
getExtension = function (name) {
return null;
}
getFramebufferAttachmentParameter = function (target, attachment, pname) {
const result = WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.getFramebufferAttachmentParameter + ',' + target + ',' + attachment + ',' + pname
)
switch (pname) {
case GLenum.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
return this._map.get(Renderbuffer.uuid(result)) || this._map.get(Texture.uuid(result)) || null;
default:
return result;
}
}
getParameter = function (pname) {
const result = WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.getParameter + ',' + pname
)
switch (pname) {
case GLenum.VERSION:
return this._version;
case GLenum.ARRAY_BUFFER_BINDING: // buffer
case GLenum.ELEMENT_ARRAY_BUFFER_BINDING: // buffer
return this._map.get(Buffer.uuid(result)) || null;
case GLenum.CURRENT_PROGRAM: // program
return this._map.get(Program.uuid(result)) || null;
case GLenum.FRAMEBUFFER_BINDING: // framebuffer
return this._map.get(Framebuffer.uuid(result)) || null;
case GLenum.RENDERBUFFER_BINDING: // renderbuffer
return this._map.get(Renderbuffer.uuid(result)) || null;
case GLenum.TEXTURE_BINDING_2D: // texture
case GLenum.TEXTURE_BINDING_CUBE_MAP: // texture
return this._map.get(Texture.uuid(result)) || null;
case GLenum.ALIASED_LINE_WIDTH_RANGE: // Float32Array
case GLenum.ALIASED_POINT_SIZE_RANGE: // Float32Array
case GLenum.BLEND_COLOR: // Float32Array
case GLenum.COLOR_CLEAR_VALUE: // Float32Array
case GLenum.DEPTH_RANGE: // Float32Array
case GLenum.MAX_VIEWPORT_DIMS: // Int32Array
case GLenum.SCISSOR_BOX: // Int32Array
case GLenum.VIEWPORT: // Int32Array
case GLenum.COMPRESSED_TEXTURE_FORMATS: // Uint32Array
default:
const [type, ...res] = result.split(',');
if (res.length === 1) {
return Number(res[0]);
} else {
return res.map(Number);
}
}
}
getProgramInfoLog = function (progarm) {
return WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.getProgramInfoLog + ',' + progarm.id
)
}
getProgramParameter = function (program, pname) {
const res = WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.getProgramParameter + ',' + program.id + ',' + pname
);
const [type, result] = res.split(',').map(i => parseInt(i));
if (type === 1) {
return Boolean(result);
} else if (type === 2) {
return result;
} else {
throw new Error('Unrecongized program paramater ' + res + ', type: ' + typeof res);
}
}
getRenderbufferParameter = function (target, pname) {
const result = WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.getRenderbufferParameter + ',' + target + ',' + pname
)
return result;
}
getShaderInfoLog = function (shader) {
return WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.getShaderInfoLog + ',' + shader.id
);
}
getShaderParameter = function (shader, pname) {
return WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.getShaderParameter + ',' + shader.id + ',' + pname
)
}
getShaderPrecisionFormat = function (shaderType, precisionType) {
const [rangeMin, rangeMax, precision] = WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.getShaderPrecisionFormat + ',' + shaderType + ',' + precisionType
);
const shaderPrecisionFormat = new ShaderPrecisionFormat({
rangeMin: Number(rangeMin),
rangeMax: Number(rangeMax),
precision: Number(precision)
});
return shaderPrecisionFormat;
}
getShaderSource = function (shader) {
const result = WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.getShaderSource + ',' + shader.id
);
return result;
}
getSupportedExtensions = function () {
return Object.keys({});
}
getTexParameter = function (target, pname) {
const result = WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.getTexParameter + ',' + target + ',' + pname
)
return result;
}
getUniformLocation = function (program, name) {
const id = WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.getUniformLocation + ',' + program.id + ',' + name
);
if (id === -1) {
return null;
} else {
return new UniformLocation(Number(id));
}
}
getVertexAttrib = function (index, pname) {
const result = WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.getVertexAttrib + ',' + index + ',' + pname
);
switch (pname) {
case GLenum.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
return this._map.get(Buffer.uuid(result)) || null;
case GLenum.CURRENT_VERTEX_ATTRIB: // Float32Array
default:
return result;
}
}
getVertexAttribOffset = function (index, pname) {
const result = WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.getVertexAttribOffset + ',' + index + ',' + pname
)
return Number(result);
}
isBuffer = function (buffer) {
const result = WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.isBuffer + ',' + buffer.id
)
return Boolean(result);
}
isContextLost = function () {
return false;
}
isEnabled = function (cap) {
const result = WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.isEnabled + ',' + cap
)
return Boolean(result);
}
isFramebuffer = function (framebuffer) {
const result = WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.isFramebuffer + ',' + framebuffer.id
)
return Boolean(result);
}
isProgram = function (program) {
const result = WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.isProgram + ',' + program.id
)
return Boolean(result);
}
isRenderbuffer = function (renderBuffer) {
const result = WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.isRenderbuffer + ',' + renderbuffer.id
)
return Boolean(result);
}
isShader = function (shader) {
const result = WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.isShader + ',' + shader.id
)
return Boolean(result);
}
isTexture = function (texture) {
const result = WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.isTexture + ',' + texture.id
);
return Boolean(result);
}
lineWidth = function (width) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.lineWidth + ',' + width,
true
)
}
linkProgram = function (program) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.linkProgram + ',' + program.id,
true
);
}
pixelStorei = function (pname, param) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.pixelStorei + ',' + pname + ',' + Number(param)
)
}
polygonOffset = function (factor, units) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.polygonOffset + ',' + factor + ',' + units
)
}
readPixels = function (x, y, width, height, format, type, pixels) {
const result = WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.readPixels + ',' + x + ',' + y + ',' + width + ',' + height + ',' + format + ',' + type
)
return result;
}
renderbufferStorage = function (target, internalFormat, width, height) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.renderbufferStorage + ',' + target + ',' + internalFormat + ',' + width + ',' + height,
true
)
}
sampleCoverage = function (value, invert) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.sampleCoverage + ',' + value + ',' + Number(invert),
true
)
}
scissor = function (x, y, width, height) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.scissor + ',' + x + ',' + y + ',' + width + ',' + height,
true
)
}
shaderSource = function (shader, source) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.shaderSource + ',' + shader.id + ',' + source
)
}
stencilFunc = function (func, ref, mask) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.stencilFunc + ',' + func + ',' + ref + ',' + mask,
true
)
}
stencilFuncSeparate = function (face, func, ref, mask) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.stencilFuncSeparate + ',' + face + ',' + func + ',' + ref + ',' + mask,
true
)
}
stencilMask = function (mask) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.stencilMask + ',' + mask,
true
)
}
stencilMaskSeparate = function (face, mask) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.stencilMaskSeparate + ',' + face + ',' + mask,
true
)
}
stencilOp = function (fail, zfail, zpass) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.stencilOp + ',' + fail + ',' + zfail + ',' + zpass
)
}
stencilOpSeparate = function (face, fail, zfail, zpass) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.stencilOp + ',' + face + ',' + fail + ',' + zfail + ',' + zpass,
true
)
}
texImage2D = function (...args) {
WebGLRenderingContext.GBridge.texImage2D(this._canvas.id, ...args);
}
texParameterf = function (target, pname, param) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.texParameterf + ',' + target + ',' + pname + ',' + param,
true
)
}
texParameteri = function (target, pname, param) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.texParameteri + ',' + target + ',' + pname + ',' + param
)
}
texSubImage2D = function (...args) {
WebGLRenderingContext.GBridge.texSubImage2D(this._canvas.id, ...args);
}
uniform1f = function (location, v0) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.uniform1f + ',' + location.id + ',' + v0
)
}
uniform1fv = function (location, value) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.uniform1fv + ',' + location.id + ',' + processArray(value),
true
)
}
uniform1i = function (location, v0) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.uniform1i + ',' + location.id + ',' + v0,
// true
)
}
uniform1iv = function (location, value) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.uniform1iv + ',' + location.id + ',' + processArray(value),
true
)
}
uniform2f = function (location, v0, v1) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.uniform2f + ',' + location.id + ',' + v0 + ',' + v1,
true
)
}
uniform2fv = function (location, value) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.uniform2fv + ',' + location.id + ',' + processArray(value),
true
)
}
uniform2i = function (location, v0, v1) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.uniform2i + ',' + location.id + ',' + v0 + ',' + v1,
true
)
}
uniform2iv = function (location, value) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.uniform2iv + ',' + location.id + ',' + processArray(value),
true
)
}
uniform3f = function (location, v0, v1, v2) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.uniform3f + ',' + location.id + ',' + v0 + ',' + v1 + ',' + v2,
true
)
}
uniform3fv = function (location, value) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.uniform3fv + ',' + location.id + ',' + processArray(value),
true
)
}
uniform3i = function (location, v0, v1, v2) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.uniform3i + ',' + location.id + ',' + v0 + ',' + v1 + ',' + v2,
true
)
}
uniform3iv = function (location, value) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.uniform3iv + ',' + location.id + ',' + processArray(value),
true
)
}
uniform4f = function (location, v0, v1, v2, v3) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.uniform4f + ',' + location.id + ',' + v0 + ',' + v1 + ',' + v2 + ',' + v3,
true
)
}
uniform4fv = function (location, value) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.uniform4fv + ',' + location.id + ',' + processArray(value),
true
)
}
uniform4i = function (location, v0, v1, v2, v3) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.uniform4i + ',' + location.id + ',' + v0 + ',' + v1 + ',' + v2 + ',' + v3,
true
)
}
uniform4iv = function (location, value) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.uniform4iv + ',' + location.id + ',' + processArray(value, true),
true
)
}
uniformMatrix2fv = function (location, transpose, value) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.uniformMatrix2fv + ',' + location.id + ',' + Number(transpose) + ',' + processArray(value),
true
)
}
uniformMatrix3fv = function (location, transpose, value) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.uniformMatrix3fv + ',' + location.id + ',' + Number(transpose) + ',' + processArray(value),
true
)
}
uniformMatrix4fv = function (location, transpose, value) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.uniformMatrix4fv + ',' + location.id + ',' + Number(transpose) + ',' + processArray(value),
true
);
}
useProgram = function (progarm) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.useProgram + ',' + progarm.id + '',
true
)
}
validateProgram = function (program) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.validateProgram + ',' + program.id,
true
)
}
vertexAttrib1f = function (index, v0) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.vertexAttrib1f + ',' + index + ',' + v0,
true
)
}
vertexAttrib2f = function (index, v0, v1) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.vertexAttrib2f + ',' + index + ',' + v0 + ',' + v1,
true
)
}
vertexAttrib3f = function (index, v0, v1, v2) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.vertexAttrib3f + ',' + index + ',' + v0 + ',' + v1 + ',' + v2,
true
)
}
vertexAttrib4f = function (index, v0, v1, v2, v3) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.vertexAttrib4f + ',' + index + ',' + v0 + ',' + v1 + ',' + v2 + ',' + v3,
true
)
}
vertexAttrib1fv = function (index, value) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.vertexAttrib1fv + ',' + index + ',' + processArray(value),
true
)
}
vertexAttrib2fv = function (index, value) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.vertexAttrib2fv + ',' + index + ',' + processArray(value),
true
)
}
vertexAttrib3fv = function (index, value) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.vertexAttrib3fv + ',' + index + ',' + processArray(value),
true
)
}
vertexAttrib4fv = function (index, value) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.vertexAttrib4fv + ',' + index + ',' + processArray(value),
true
)
}
vertexAttribPointer = function (index, size, type, normalized, stride, offset) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.vertexAttribPointer + ',' + index + ',' + size + ',' + type + ',' + Number(normalized) + ',' + stride + ',' + offset,
true
)
}
viewport = function (x, y, width, height) {
WebGLRenderingContext.GBridge.callNative(
this._canvas.id,
GLmethod.viewport + ',' + x + ',' + y + ',' + width + ',' + height,
true
)
}
}
\ No newline at end of file
import {getTransferedObjectUUID} from './classUtils';
const name = 'WebGLShader';
function uuid(id) {
return getTransferedObjectUUID(name, id);
}
export default class WebGLShader {
className = name;
constructor(id, type) {
this.id = id;
this.type = type;
}
static uuid = uuid;
uuid() {
return uuid(this.id);
}
}
\ No newline at end of file
export default class WebGLShaderPrecisionFormat {
className = 'WebGLShaderPrecisionFormat';
constructor({
rangeMin, rangeMax, precision
}) {
this.rangeMin = rangeMin;
this.rangeMax = rangeMax;
this.precision = precision;
}
}
\ No newline at end of file
import {getTransferedObjectUUID} from './classUtils';
const name = 'WebGLTexture';
function uuid(id) {
return getTransferedObjectUUID(name, id);
}
export default class WebGLTexture {
className = name;
constructor(id, type) {
this.id = id;
this.type = type;
}
static uuid = uuid;
uuid() {
return uuid(this.id);
}
}
\ No newline at end of file
import {getTransferedObjectUUID} from './classUtils';
const name = 'WebGLUniformLocation';
function uuid(id) {
return getTransferedObjectUUID(name, id);
}
export default class WebGLUniformLocation {
className = name;
constructor(id, type) {
this.id = id;
this.type = type;
}
static uuid = uuid;
uuid() {
return uuid(this.id);
}
}
\ No newline at end of file
export function getTransferedObjectUUID(name, id) {
return `${name.toLowerCase()}-${id}`;
}
\ No newline at end of file
import GContext2D from '../context-2d/RenderingContext';
import GContextWebGL from '../context-webgl/RenderingContext';
export default class GCanvas {
// static GBridge = null;
id = null;
_needRender = true;
constructor(id, { disableAutoSwap }) {
this.id = id;
this._disableAutoSwap = disableAutoSwap;
if (disableAutoSwap) {
this._swapBuffers = () => {
GCanvas.GBridge.render(this.id);
}
}
}
getContext(type) {
let context = null;
if (type.match(/webgl/i)) {
context = new GContextWebGL(this);
context.componentId = this.id;
if (!this._disableAutoSwap) {
const render = () => {
if (this._needRender) {
GCanvas.GBridge.render(this.id);
this._needRender = false;
}
}
setInterval(render, 16);
}
GCanvas.GBridge.callSetContextType(this.id, 1); // 0 for 2d; 1 for webgl
} else if (type.match(/2d/i)) {
context = new GContext2D(this);
context.componentId = this.id;
// const render = ( callback ) => {
//
// const commands = context._drawCommands;
// context._drawCommands = '';
//
// GCanvas.GBridge.render2d(this.id, commands, callback);
// this._needRender = false;
// }
// //draw方法触发
// context._flush = render;
// //setInterval(render, 16);
GCanvas.GBridge.callSetContextType(this.id, 0);
} else {
throw new Error('not supported context ' + type);
}
return context;
}
reset() {
GCanvas.GBridge.callReset(this.id);
}
}
\ No newline at end of file
let incId = 1;
const noop = function () { };
class GImage {
static GBridge = null;
constructor() {
this._id = incId++;
this._width = 0;
this._height = 0;
this._src = undefined;
this._onload = noop;
this._onerror = noop;
this.complete = false;
}
get width() {
return this._width;
}
set width(v) {
this._width = v;
}
get height() {
return this._height;
}
set height(v) {
this._height = v;
}
get src() {
return this._src;
}
set src(v) {
if (v.startsWith('//')) {
v = 'http:' + v;
}
this._src = v;
GImage.GBridge.perloadImage([this._src, this._id], (data) => {
if (typeof data === 'string') {
data = JSON.parse(data);
}
if (data.error) {
var evt = { type: 'error', target: this };
this.onerror(evt);
} else {
this.complete = true;
this.width = typeof data.width === 'number' ? data.width : 0;
this.height = typeof data.height === 'number' ? data.height : 0;
var evt = { type: 'load', target: this };
this.onload(evt);
}
});
}
addEventListener(name, listener) {
if (name === 'load') {
this.onload = listener;
} else if (name === 'error') {
this.onerror = listener;
}
}
removeEventListener(name, listener) {
if (name === 'load') {
this.onload = noop;
} else if (name === 'error') {
this.onerror = noop;
}
}
get onload() {
return this._onload;
}
set onload(v) {
this._onload = v;
}
get onerror() {
return this._onerror;
}
set onerror(v) {
this._onerror = v;
}
}
export default GImage;
\ No newline at end of file
export function ArrayBufferToBase64 (buffer) {
var binary = '';
var bytes = new Uint8ClampedArray(buffer);
for (var len = bytes.byteLength, i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return btoa(binary);
}
export function Base64ToUint8ClampedArray(base64String) {
const padding = '='.repeat((4 - base64String.length % 4) % 4);
const base64 = (base64String + padding)
.replace(/\-/g, '+')
.replace(/_/g, '/');
const rawData = atob(base64);
const outputArray = new Uint8ClampedArray(rawData.length);
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}
\ No newline at end of file
import GCanvas from './env/canvas';
import GImage from './env/image';
import GWebGLRenderingContext from './context-webgl/RenderingContext';
import GContext2D from './context-2d/RenderingContext';
import GBridgeWeex from './bridge/bridge-weex';
export let Image = GImage;
export let WeexBridge = GBridgeWeex;
export function enable(el, { bridge, debug, disableAutoSwap, disableComboCommands } = {}) {
const GBridge = GImage.GBridge = GCanvas.GBridge = GWebGLRenderingContext.GBridge = GContext2D.GBridge = bridge;
GBridge.callEnable(el.ref, [
0, // renderMode: 0--RENDERMODE_WHEN_DIRTY, 1--RENDERMODE_CONTINUOUSLY
-1, // hybridLayerType: 0--LAYER_TYPE_NONE 1--LAYER_TYPE_SOFTWARE 2--LAYER_TYPE_HARDWARE
false, // supportScroll
false, // newCanvasMode
1, // compatible
'white',// clearColor
false // sameLevel: newCanvasMode = true && true => GCanvasView and Webview is same level
]);
if (debug === true) {
GBridge.callEnableDebug();
}
if (disableComboCommands) {
GBridge.callEnableDisableCombo();
}
var canvas = new GCanvas(el.ref, { disableAutoSwap });
canvas.width = el.style.width;
canvas.height = el.style.height;
return canvas;
};
\ No newline at end of file
{
"name": "uqrcode",
"version": "3.5.1",
"description": "",
"main": "uqrcode.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
//---------------------------------------------------------------------
// uQRCode二维码生成插件 v3.5.1
//
// uQRCode是一款基于Javascript环境开发的二维码生成插件,适用所有Javascript运行环境的前端应用和Node.js。
//
// Copyright (c) Sansnn uQRCode All rights reserved.
//
// Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
//
// github地址:
// https://github.com/Sansnn/uQRCode
//
// npm地址:
// https://www.npmjs.com/package/uqrcodejs
//
// uni-app插件市场地址:
// https://ext.dcloud.net.cn/plugin?id=1287
//
// 复制使用请保留本段注释,感谢支持开源!
//
//---------------------------------------------------------------------
//---------------------------------------------------------------------
// QRCode for JavaScript
//
// Copyright (c) 2009 Kazuhiko Arase
//
// URL: http://www.d-project.com/
//
// Licensed under the MIT license:
// http://www.opensource.org/licenses/mit-license.php
//
// The word "QR Code" is registered trademark of
// DENSO WAVE INCORPORATED
// http://www.denso-wave.com/qrcode/faqpatent-e.html
//
//---------------------------------------------------------------------
"use strict";let uQRCode;!function(){function o(o){this.mode=u.MODE_8BIT_BYTE,this.data=o}function e(o,e){this.typeNumber=o,this.errorCorrectLevel=e,this.modules=null,this.moduleCount=0,this.dataCache=null,this.dataList=new Array}function r(o,e){if(null==o.length)throw new Error(o.length+"/"+e);for(var r=0;r<o.length&&0==o[r];)r++;this.num=new Array(o.length-r+e);for(var t=0;t<o.length-r;t++)this.num[t]=o[t+r]}function t(o,e){this.totalCount=o,this.dataCount=e}function i(){this.buffer=new Array,this.length=0}function n(){function o(t,i,n){t().then(o=>{i(o)}).catch(o=>{n(o)}).finally(()=>{if(e.length){const r=e.shift();o(r.task,r.resolve,r.reject)}else r=!1})}let e=this.waitingQueue=[],r=this.isRunning=!1;this.exec=function(t){return new Promise((i,n)=>{r?e.push({task:t,resolve:i,reject:n}):(r=!0,o(t,i,n))})}}function a(o,e){var r=this.data="",t=this.size=200,i=this.typeNumber=-1,n=(this.errorCorrectLevel=d.H,this.useDynamicSize=!1,this.dynamicSize=void 0,this.margin=0),u=(this.backgroundColor="#FFFFFF",this.backgroundImageSrc=void 0,this.backgroundImageWidth=void 0),s=this.backgroundImageHeight=void 0,g=this.backgroundImageX=void 0,l=this.backgroundImageY=void 0,h=(this.backgroundImageAlpha=1,this.backgroundImageBorderRadius=0,this.foregroundColor="#000000",this.foregroundImageSrc=void 0,this.foregroundImageWidth=void 0),m=this.foregroundImageHeight=void 0,c=this.foregroundImageX=void 0,f=this.foregroundImageY=void 0,v=this.foregroundImagePadding=0,p=(this.foregroundImageBackgroundColor="#FFFFFF",this.foregroundImageBorderRadius=0),C=this.foregroundImageShadowOffsetX=0,b=this.foregroundImageShadowOffsetY=0,y=this.foregroundImageShadowBlur=0,I=(this.foregroundImageShadowColor="#808080",this.positionProbeBackgroundColor=void 0),k=this.positionProbeForegroundColor=void 0,w=(this.positionProbeImageSrc=void 0,this.positionProbeLeftUpperImageSrc=void 0),S=this.positionProbeRightUpperImageSrc=void 0,P=this.positionProbeLeftLowerImageSrc=void 0,B=this.separatorColor=void 0,T=this.positionAdjustBackgroundColor=void 0,L=this.positionAdjustForegroundColor=void 0,A=(this.positionAdjustImageSrc=void 0,this.timingBackgroundColor=void 0),D=this.timingForegroundColor=void 0,E=this.typeNumberBackgroundColor=void 0,N=this.typeNumberForegroundColor=void 0,x=this.darkBlockColor=void 0,R=(this.patterns=[],this.canvasContext=void 0);this.queue=!1,this.modules=[],this.moduleCount=0,this.drawModules=[];Object.defineProperties(this,{data:{get:()=>(""!==r&&void 0!==r||console.error("[uQRCode]: data must be set!"),r),set(o){r=o}},size:{get:()=>t,set(o){t=Number(o)}},typeNumber:{get:()=>i,set(o){i=Number(o)}},margin:{get:()=>n,set(o){n=Number(o)}},backgroundImageWidth:{get(){return void 0===u?this.dynamicSize:this.useDynamicSize?this.dynamicSize/this.size*u:u},set(o){u=Number(o)}},backgroundImageHeight:{get(){return void 0===s?this.dynamicSize:this.useDynamicSize?this.dynamicSize/this.size*s:s},set(o){s=Number(o)}},backgroundImageX:{get(){return void 0===g?0:this.useDynamicSize?this.dynamicSize/this.size*g:g},set(o){g=Number(o)}},backgroundImageY:{get(){return void 0===l?0:this.useDynamicSize?this.dynamicSize/this.size*l:l},set(o){l=Number(o)}},foregroundImageWidth:{get(){return void 0===h?(this.dynamicSize-2*this.margin)/4:this.useDynamicSize?this.dynamicSize/this.size*h:h},set(o){h=Number(o)}},foregroundImageHeight:{get(){return void 0===m?(this.dynamicSize-2*this.margin)/4:this.useDynamicSize?this.dynamicSize/this.size*m:m},set(o){m=Number(o)}},foregroundImageX:{get(){return void 0===c?this.dynamicSize/2-this.foregroundImageWidth/2:this.useDynamicSize?this.dynamicSize/this.size*c:c},set(o){c=Number(o)}},foregroundImageY:{get(){return void 0===f?this.dynamicSize/2-this.foregroundImageHeight/2:this.useDynamicSize?this.dynamicSize/this.size*f:f},set(o){f=Number(o)}},foregroundImagePadding:{get(){return this.useDynamicSize?this.dynamicSize/this.size*v:v},set(o){v=Number(o)}},foregroundImageBorderRadius:{get(){return this.useDynamicSize?this.dynamicSize/this.size*p:p},set(o){p=Number(o)}},foregroundImageShadowOffsetX:{get(){return this.useDynamicSize?this.dynamicSize/this.size*C:C},set(o){C=Number(o)}},foregroundImageShadowOffsetY:{get(){return this.useDynamicSize?this.dynamicSize/this.size*b:b},set(o){b=Number(o)}},foregroundImageShadowBlur:{get(){return this.useDynamicSize?this.dynamicSize/this.size*y:y},set(o){y=Number(o)}},positionProbeBackgroundColor:{get(){return I||this.backgroundColor},set(o){I=o}},positionProbeForegroundColor:{get(){return k||this.foregroundColor},set(o){k=o}},positionProbeLeftUpperImageSrc:{get(){return w||this.positionProbeImageSrc},set(o){w=o}},positionProbeRightUpperImageSrc:{get(){return S||this.positionProbeImageSrc},set(o){S=o}},positionProbeLeftLowerImageSrc:{get(){return P||this.positionProbeImageSrc},set(o){P=o}},separatorColor:{get(){return B||this.backgroundColor},set(o){B=o}},positionAdjustBackgroundColor:{get(){return T||this.backgroundColor},set(o){T=o}},positionAdjustForegroundColor:{get(){return L||this.foregroundColor},set(o){L=o}},timingBackgroundColor:{get(){return A||this.backgroundColor},set(o){A=o}},timingForegroundColor:{get(){return D||this.foregroundColor},set(o){D=o}},typeNumberBackgroundColor:{get(){return E||this.backgroundColor},set(o){E=o}},typeNumberForegroundColor:{get(){return N||this.foregroundColor},set(o){N=o}},darkBlockColor:{get(){return x||this.foregroundColor},set(o){x=o}},canvasContext:{get:()=>(void 0===R&&console.error("[uQRCode]: use drawCanvas, you need to set the canvasContext!"),R),set(o){R=a.getCanvasContext(o)}}}),o&&this.setOptions(o),e&&(this.canvasContext=a.getCanvasContext(e))}o.prototype={getLength:function(o){return this.data.length},write:function(o){for(var e=0;e<this.data.length;e++)o.put(this.data.charCodeAt(e),8)}},e.prototype={addData:function(e){var r=new o(e);this.dataList.push(r),this.dataCache=null},isDark:function(o,e){if(o<0||this.moduleCount<=o||e<0||this.moduleCount<=e)throw new Error(o+","+e);return this.modules[o][e]},getModuleCount:function(){return this.moduleCount},make:function(){if(this.typeNumber<1){var o=1;for(o=1;o<40;o++){for(var e=t.getRSBlocks(o,this.errorCorrectLevel),r=new i,n=0,a=0;a<e.length;a++)n+=e[a].dataCount;for(a=0;a<this.dataList.length;a++){var u=this.dataList[a];r.put(u.mode,4),r.put(u.getLength(),g.getLengthInBits(u.mode,o)),u.write(r)}if(r.getLengthInBits()<=8*n)break}this.typeNumber=o}this.makeImpl(!1,this.getBestMaskPattern())},makeImpl:function(o,r){this.moduleCount=4*this.typeNumber+17,this.modules=new Array(this.moduleCount);for(var t=0;t<this.moduleCount;t++){this.modules[t]=new Array(this.moduleCount);for(var i=0;i<this.moduleCount;i++)this.modules[t][i]=null}this.setupPositionProbePattern(0,0),this.setupPositionProbePattern(this.moduleCount-7,0),this.setupPositionProbePattern(0,this.moduleCount-7),this.setupPositionAdjustPattern(),this.setupTimingPattern(),this.setupTypeInfo(o,r),this.typeNumber>=7&&this.setupTypeNumber(o),null==this.dataCache&&(this.dataCache=e.createData(this.typeNumber,this.errorCorrectLevel,this.dataList)),this.mapData(this.dataCache,r)},setupPositionProbePattern:function(o,e){for(var r=-1;r<=7;r++)if(!(o+r<=-1||this.moduleCount<=o+r))for(var t=-1;t<=7;t++)e+t<=-1||this.moduleCount<=e+t||(this.modules[o+r][e+t]=0<=r&&r<=6&&(0==t||6==t)||0<=t&&t<=6&&(0==r||6==r)||2<=r&&r<=4&&2<=t&&t<=4)},getBestMaskPattern:function(){for(var o=0,e=0,r=0;r<8;r++){this.makeImpl(!0,r);var t=g.getLostPoint(this);(0==r||o>t)&&(o=t,e=r)}return e},createMovieClip:function(o,e,r){var t=o.createEmptyMovieClip(e,r),i=1;this.make();for(var n=0;n<this.modules.length;n++)for(var a=n*i,u=0;u<this.modules[n].length;u++){var d=u*i,s=this.modules[n][u];s&&(t.beginFill(0,100),t.moveTo(d,a),t.lineTo(d+i,a),t.lineTo(d+i,a+i),t.lineTo(d,a+i),t.endFill())}return t},setupTimingPattern:function(){for(var o=8;o<this.moduleCount-8;o++)null==this.modules[o][6]&&(this.modules[o][6]=o%2==0);for(var e=8;e<this.moduleCount-8;e++)null==this.modules[6][e]&&(this.modules[6][e]=e%2==0)},setupPositionAdjustPattern:function(){for(var o=g.getPatternPosition(this.typeNumber),e=0;e<o.length;e++)for(var r=0;r<o.length;r++){var t=o[e],i=o[r];if(null==this.modules[t][i])for(var n=-2;n<=2;n++)for(var a=-2;a<=2;a++)this.modules[t+n][i+a]=-2==n||2==n||-2==a||2==a||0==n&&0==a}},setupTypeNumber:function(o){for(var e=g.getBCHTypeNumber(this.typeNumber),r=0;r<18;r++){var t=!o&&1==(e>>r&1);this.modules[Math.floor(r/3)][r%3+this.moduleCount-8-3]=t}for(r=0;r<18;r++){t=!o&&1==(e>>r&1);this.modules[r%3+this.moduleCount-8-3][Math.floor(r/3)]=t}},setupTypeInfo:function(o,e){for(var r=this.errorCorrectLevel<<3|e,t=g.getBCHTypeInfo(r),i=0;i<15;i++){var n=!o&&1==(t>>i&1);i<6?this.modules[i][8]=n:i<8?this.modules[i+1][8]=n:this.modules[this.moduleCount-15+i][8]=n}for(i=0;i<15;i++){n=!o&&1==(t>>i&1);i<8?this.modules[8][this.moduleCount-i-1]=n:i<9?this.modules[8][15-i-1+1]=n:this.modules[8][15-i-1]=n}this.modules[this.moduleCount-8][8]=!o},mapData:function(o,e){for(var r=-1,t=this.moduleCount-1,i=7,n=0,a=this.moduleCount-1;a>0;a-=2)for(6==a&&a--;;){for(var u=0;u<2;u++)if(null==this.modules[t][a-u]){var d=!1;n<o.length&&(d=1==(o[n]>>>i&1));var s=g.getMask(e,t,a-u);s&&(d=!d),this.modules[t][a-u]=d,i--,-1==i&&(n++,i=7)}if(t+=r,t<0||this.moduleCount<=t){t-=r,r=-r;break}}}},e.PAD0=236,e.PAD1=17,e.createData=function(o,r,n){for(var a=t.getRSBlocks(o,r),u=new i,d=0;d<n.length;d++){var s=n[d];u.put(s.mode,4),u.put(s.getLength(),g.getLengthInBits(s.mode,o)),s.write(u)}var l=0;for(d=0;d<a.length;d++)l+=a[d].dataCount;if(u.getLengthInBits()>8*l)throw new Error("code length overflow. ("+u.getLengthInBits()+">"+8*l+")");for(u.getLengthInBits()+4<=8*l&&u.put(0,4);u.getLengthInBits()%8!=0;)u.putBit(!1);for(;!(u.getLengthInBits()>=8*l||(u.put(e.PAD0,8),u.getLengthInBits()>=8*l));)u.put(e.PAD1,8);return e.createBytes(u,a)},e.createBytes=function(o,e){for(var t=0,i=0,n=0,a=new Array(e.length),u=new Array(e.length),d=0;d<e.length;d++){var s=e[d].dataCount,l=e[d].totalCount-s;i=Math.max(i,s),n=Math.max(n,l),a[d]=new Array(s);for(var h=0;h<a[d].length;h++)a[d][h]=255&o.buffer[h+t];t+=s;var m=g.getErrorCorrectPolynomial(l),c=new r(a[d],m.getLength()-1),f=c.mod(m);u[d]=new Array(m.getLength()-1);for(h=0;h<u[d].length;h++){var v=h+f.getLength()-u[d].length;u[d][h]=v>=0?f.get(v):0}}var p=0;for(h=0;h<e.length;h++)p+=e[h].totalCount;var C=new Array(p),b=0;for(h=0;h<i;h++)for(d=0;d<e.length;d++)h<a[d].length&&(C[b++]=a[d][h]);for(h=0;h<n;h++)for(d=0;d<e.length;d++)h<u[d].length&&(C[b++]=u[d][h]);return C};for(var u={MODE_NUMBER:1,MODE_ALPHA_NUM:2,MODE_8BIT_BYTE:4,MODE_KANJI:8},d={L:1,M:0,Q:3,H:2},s={PATTERN000:0,PATTERN001:1,PATTERN010:2,PATTERN011:3,PATTERN100:4,PATTERN101:5,PATTERN110:6,PATTERN111:7},g={PATTERN_POSITION_TABLE:[[],[6,18],[6,22],[6,26],[6,30],[6,34],[6,22,38],[6,24,42],[6,26,46],[6,28,50],[6,30,54],[6,32,58],[6,34,62],[6,26,46,66],[6,26,48,70],[6,26,50,74],[6,30,54,78],[6,30,56,82],[6,30,58,86],[6,34,62,90],[6,28,50,72,94],[6,26,50,74,98],[6,30,54,78,102],[6,28,54,80,106],[6,32,58,84,110],[6,30,58,86,114],[6,34,62,90,118],[6,26,50,74,98,122],[6,30,54,78,102,126],[6,26,52,78,104,130],[6,30,56,82,108,134],[6,34,60,86,112,138],[6,30,58,86,114,142],[6,34,62,90,118,146],[6,30,54,78,102,126,150],[6,24,50,76,102,128,154],[6,28,54,80,106,132,158],[6,32,58,84,110,136,162],[6,26,54,82,110,138,166],[6,30,58,86,114,142,170]],G15:1335,G18:7973,G15_MASK:21522,getBCHTypeInfo:function(o){for(var e=o<<10;g.getBCHDigit(e)-g.getBCHDigit(g.G15)>=0;)e^=g.G15<<g.getBCHDigit(e)-g.getBCHDigit(g.G15);return(o<<10|e)^g.G15_MASK},getBCHTypeNumber:function(o){for(var e=o<<12;g.getBCHDigit(e)-g.getBCHDigit(g.G18)>=0;)e^=g.G18<<g.getBCHDigit(e)-g.getBCHDigit(g.G18);return o<<12|e},getBCHDigit:function(o){for(var e=0;0!=o;)e++,o>>>=1;return e},getPatternPosition:function(o){return g.PATTERN_POSITION_TABLE[o-1]},getMask:function(o,e,r){switch(o){case s.PATTERN000:return(e+r)%2==0;case s.PATTERN001:return e%2==0;case s.PATTERN010:return r%3==0;case s.PATTERN011:return(e+r)%3==0;case s.PATTERN100:return(Math.floor(e/2)+Math.floor(r/3))%2==0;case s.PATTERN101:return e*r%2+e*r%3==0;case s.PATTERN110:return(e*r%2+e*r%3)%2==0;case s.PATTERN111:return(e*r%3+(e+r)%2)%2==0;default:throw new Error("bad maskPattern:"+o)}},getErrorCorrectPolynomial:function(o){for(var e=new r([1],0),t=0;t<o;t++)e=e.multiply(new r([1,l.gexp(t)],0));return e},getLengthInBits:function(o,e){if(1<=e&&e<10)switch(o){case u.MODE_NUMBER:return 10;case u.MODE_ALPHA_NUM:return 9;case u.MODE_8BIT_BYTE:case u.MODE_KANJI:return 8;default:throw new Error("mode:"+o)}else if(e<27)switch(o){case u.MODE_NUMBER:return 12;case u.MODE_ALPHA_NUM:return 11;case u.MODE_8BIT_BYTE:return 16;case u.MODE_KANJI:return 10;default:throw new Error("mode:"+o)}else{if(!(e<41))throw new Error("type:"+e);switch(o){case u.MODE_NUMBER:return 14;case u.MODE_ALPHA_NUM:return 13;case u.MODE_8BIT_BYTE:return 16;case u.MODE_KANJI:return 12;default:throw new Error("mode:"+o)}}},getLostPoint:function(o){for(var e=o.getModuleCount(),r=0,t=0;t<e;t++)for(var i=0;i<e;i++){for(var n=0,a=o.isDark(t,i),u=-1;u<=1;u++)if(!(t+u<0||e<=t+u))for(var d=-1;d<=1;d++)i+d<0||e<=i+d||0==u&&0==d||a==o.isDark(t+u,i+d)&&n++;n>5&&(r+=3+n-5)}for(t=0;t<e-1;t++)for(i=0;i<e-1;i++){var s=0;o.isDark(t,i)&&s++,o.isDark(t+1,i)&&s++,o.isDark(t,i+1)&&s++,o.isDark(t+1,i+1)&&s++,0!=s&&4!=s||(r+=3)}for(t=0;t<e;t++)for(i=0;i<e-6;i++)o.isDark(t,i)&&!o.isDark(t,i+1)&&o.isDark(t,i+2)&&o.isDark(t,i+3)&&o.isDark(t,i+4)&&!o.isDark(t,i+5)&&o.isDark(t,i+6)&&(r+=40);for(i=0;i<e;i++)for(t=0;t<e-6;t++)o.isDark(t,i)&&!o.isDark(t+1,i)&&o.isDark(t+2,i)&&o.isDark(t+3,i)&&o.isDark(t+4,i)&&!o.isDark(t+5,i)&&o.isDark(t+6,i)&&(r+=40);var g=0;for(i=0;i<e;i++)for(t=0;t<e;t++)o.isDark(t,i)&&g++;var l=Math.abs(100*g/e/e-50)/5;return r+=10*l,r}},l={glog:function(o){if(o<1)throw new Error("glog("+o+")");return l.LOG_TABLE[o]},gexp:function(o){for(;o<0;)o+=255;for(;o>=256;)o-=255;return l.EXP_TABLE[o]},EXP_TABLE:new Array(256),LOG_TABLE:new Array(256)},h=0;h<8;h++)l.EXP_TABLE[h]=1<<h;for(h=8;h<256;h++)l.EXP_TABLE[h]=l.EXP_TABLE[h-4]^l.EXP_TABLE[h-5]^l.EXP_TABLE[h-6]^l.EXP_TABLE[h-8];for(h=0;h<255;h++)l.LOG_TABLE[l.EXP_TABLE[h]]=h;r.prototype={get:function(o){return this.num[o]},getLength:function(){return this.num.length},multiply:function(o){for(var e=new Array(this.getLength()+o.getLength()-1),t=0;t<this.getLength();t++)for(var i=0;i<o.getLength();i++)e[t+i]^=l.gexp(l.glog(this.get(t))+l.glog(o.get(i)));return new r(e,0)},mod:function(o){if(this.getLength()-o.getLength()<0)return this;for(var e=l.glog(this.get(0))-l.glog(o.get(0)),t=new Array(this.getLength()),i=0;i<this.getLength();i++)t[i]=this.get(i);for(i=0;i<o.getLength();i++)t[i]^=l.gexp(l.glog(o.get(i))+e);return new r(t,0).mod(o)}},t.RS_BLOCK_TABLE=[[1,26,19],[1,26,16],[1,26,13],[1,26,9],[1,44,34],[1,44,28],[1,44,22],[1,44,16],[1,70,55],[1,70,44],[2,35,17],[2,35,13],[1,100,80],[2,50,32],[2,50,24],[4,25,9],[1,134,108],[2,67,43],[2,33,15,2,34,16],[2,33,11,2,34,12],[2,86,68],[4,43,27],[4,43,19],[4,43,15],[2,98,78],[4,49,31],[2,32,14,4,33,15],[4,39,13,1,40,14],[2,121,97],[2,60,38,2,61,39],[4,40,18,2,41,19],[4,40,14,2,41,15],[2,146,116],[3,58,36,2,59,37],[4,36,16,4,37,17],[4,36,12,4,37,13],[2,86,68,2,87,69],[4,69,43,1,70,44],[6,43,19,2,44,20],[6,43,15,2,44,16],[4,101,81],[1,80,50,4,81,51],[4,50,22,4,51,23],[3,36,12,8,37,13],[2,116,92,2,117,93],[6,58,36,2,59,37],[4,46,20,6,47,21],[7,42,14,4,43,15],[4,133,107],[8,59,37,1,60,38],[8,44,20,4,45,21],[12,33,11,4,34,12],[3,145,115,1,146,116],[4,64,40,5,65,41],[11,36,16,5,37,17],[11,36,12,5,37,13],[5,109,87,1,110,88],[5,65,41,5,66,42],[5,54,24,7,55,25],[11,36,12],[5,122,98,1,123,99],[7,73,45,3,74,46],[15,43,19,2,44,20],[3,45,15,13,46,16],[1,135,107,5,136,108],[10,74,46,1,75,47],[1,50,22,15,51,23],[2,42,14,17,43,15],[5,150,120,1,151,121],[9,69,43,4,70,44],[17,50,22,1,51,23],[2,42,14,19,43,15],[3,141,113,4,142,114],[3,70,44,11,71,45],[17,47,21,4,48,22],[9,39,13,16,40,14],[3,135,107,5,136,108],[3,67,41,13,68,42],[15,54,24,5,55,25],[15,43,15,10,44,16],[4,144,116,4,145,117],[17,68,42],[17,50,22,6,51,23],[19,46,16,6,47,17],[2,139,111,7,140,112],[17,74,46],[7,54,24,16,55,25],[34,37,13],[4,151,121,5,152,122],[4,75,47,14,76,48],[11,54,24,14,55,25],[16,45,15,14,46,16],[6,147,117,4,148,118],[6,73,45,14,74,46],[11,54,24,16,55,25],[30,46,16,2,47,17],[8,132,106,4,133,107],[8,75,47,13,76,48],[7,54,24,22,55,25],[22,45,15,13,46,16],[10,142,114,2,143,115],[19,74,46,4,75,47],[28,50,22,6,51,23],[33,46,16,4,47,17],[8,152,122,4,153,123],[22,73,45,3,74,46],[8,53,23,26,54,24],[12,45,15,28,46,16],[3,147,117,10,148,118],[3,73,45,23,74,46],[4,54,24,31,55,25],[11,45,15,31,46,16],[7,146,116,7,147,117],[21,73,45,7,74,46],[1,53,23,37,54,24],[19,45,15,26,46,16],[5,145,115,10,146,116],[19,75,47,10,76,48],[15,54,24,25,55,25],[23,45,15,25,46,16],[13,145,115,3,146,116],[2,74,46,29,75,47],[42,54,24,1,55,25],[23,45,15,28,46,16],[17,145,115],[10,74,46,23,75,47],[10,54,24,35,55,25],[19,45,15,35,46,16],[17,145,115,1,146,116],[14,74,46,21,75,47],[29,54,24,19,55,25],[11,45,15,46,46,16],[13,145,115,6,146,116],[14,74,46,23,75,47],[44,54,24,7,55,25],[59,46,16,1,47,17],[12,151,121,7,152,122],[12,75,47,26,76,48],[39,54,24,14,55,25],[22,45,15,41,46,16],[6,151,121,14,152,122],[6,75,47,34,76,48],[46,54,24,10,55,25],[2,45,15,64,46,16],[17,152,122,4,153,123],[29,74,46,14,75,47],[49,54,24,10,55,25],[24,45,15,46,46,16],[4,152,122,18,153,123],[13,74,46,32,75,47],[48,54,24,14,55,25],[42,45,15,32,46,16],[20,147,117,4,148,118],[40,75,47,7,76,48],[43,54,24,22,55,25],[10,45,15,67,46,16],[19,148,118,6,149,119],[18,75,47,31,76,48],[34,54,24,34,55,25],[20,45,15,61,46,16]],t.getRSBlocks=function(o,e){var r=t.getRsBlockTable(o,e);if(null==r)throw new Error("bad rs block @ typeNumber:"+o+"/errorCorrectLevel:"+e);for(var i=r.length/3,n=new Array,a=0;a<i;a++)for(var u=r[3*a+0],d=r[3*a+1],s=r[3*a+2],g=0;g<u;g++)n.push(new t(d,s));return n},t.getRsBlockTable=function(o,e){switch(e){case d.L:return t.RS_BLOCK_TABLE[4*(o-1)+0];case d.M:return t.RS_BLOCK_TABLE[4*(o-1)+1];case d.Q:return t.RS_BLOCK_TABLE[4*(o-1)+2];case d.H:return t.RS_BLOCK_TABLE[4*(o-1)+3];default:return}},i.prototype={get:function(o){var e=Math.floor(o/8);return 1==(this.buffer[e]>>>7-o%8&1)},put:function(o,e){for(var r=0;r<e;r++)this.putBit(1==(o>>>e-r-1&1))},getLengthInBits:function(){return this.length},putBit:function(o){var e=Math.floor(this.length/8);this.buffer.length<=e&&this.buffer.push(0),o&&(this.buffer[e]|=128>>>this.length%8),this.length++}},a.errorCorrectLevel=d,a.queue=new n,a.queueLoadImage=new n,a.isQueueLoadImage=!1,a.loadImageCache=[],a.utf16To8=function(o){for(var e,r="",t=0;t<o.length;t++)e=o.charCodeAt(t),e>=1&&e<=127?r+=o.charAt(t):e>2047?(r+=String.fromCharCode(224|e>>12&15),r+=String.fromCharCode(128|e>>6&63),r+=String.fromCharCode(128|e>>0&63)):(r+=String.fromCharCode(192|e>>6&31),r+=String.fromCharCode(128|e>>0&63));return r},a.deepReplace=function(o={},e={},r=!1){let t;t=r?o:{...o};for(let o in e){var i=e[o];null!=i&&(i.constructor==Object?t[o]=this.deepReplace(t[o],i):i.constructor!=String||i?t[o]=i:t[o]=t[o])}return t},a.getSomePropertyToNewObject=function(o={},e=[]){let r={};return e.forEach(e=>{r[e]=o[e]}),r},a.getCanvasContext=function(o){return o.setFillStyle=o.setFillStyle||function(e){o.fillStyle=e},o.setFontSize=o.setFontSize||function(e){o.font=`${e}px`},o.setTextAlign=o.setTextAlign||function(e){o.textAlign=e},o.setTextBaseline=o.setTextBaseline||function(e){o.textBaseline=e},o.draw=o.draw||function(o,e){e&&e()},o},a.getLoadImage=function(o){return"function"==typeof o?function(e,r=!1){return a.isQueueLoadImage?a.queueLoadImage.exec(()=>new Promise((t,i)=>{setTimeout(()=>{const r=a.loadImageCache.find(o=>o.src==e);r?t(r.img):o(e).then(o=>{a.loadImageCache.push({src:e,img:o}),t(o)}).catch(o=>{i(o)})},r?150:10)})):o(e)}:function(o){return Promise.resolve(o)}};var m=a.loadImage=function(o){return Promise.resolve(o)};Object.defineProperty(a,"loadImage",{get:()=>m,set(o){m=a.getLoadImage(o)}}),a.prototype={setOptions(o){var e,r,t,i,n,u,d,s,g,l,h,m,c,f,v,p,C,b,y,I,k,w,S,P,B,T,L,A,D,E,N,x,R,z,_,M,O,F,j,H,X,Y,U,Q,G,K,W,q,J,$,V,Z,oo,eo,ro,to,io,no,ao,uo,so,go,lo,ho,mo,co,fo,vo,po,Co,bo,yo,Io,ko,wo,So,Po,Bo,To,Lo,Ao,Do,Eo,No,xo;o&&a.deepReplace(this,{data:o.data||o.text,size:o.size,typeNumber:o.typeNumber,errorCorrectLevel:o.errorCorrectLevel,useDynamicSize:o.useDynamicSize,margin:o.margin,backgroundColor:o.backgroundColor||(null===(e=o.background)||void 0===e?void 0:e.color),backgroundImageSrc:o.backgroundImageSrc||(null===(r=o.background)||void 0===r?void 0:null===(t=r.image)||void 0===t?void 0:t.src),backgroundImageWidth:o.backgroundImageWidth||(null===(i=o.background)||void 0===i?void 0:null===(n=i.image)||void 0===n?void 0:n.width),backgroundImageHeight:o.backgroundImageHeight||(null===(u=o.background)||void 0===u?void 0:null===(d=u.image)||void 0===d?void 0:d.height),backgroundImageX:o.backgroundImageX||(null===(s=o.background)||void 0===s?void 0:null===(g=s.image)||void 0===g?void 0:g.x),backgroundImageY:o.backgroundImageY||(null===(l=o.background)||void 0===l?void 0:null===(h=l.image)||void 0===h?void 0:h.y),backgroundImageAlpha:o.backgroundImageAlpha||(null===(m=o.background)||void 0===m?void 0:null===(c=m.image)||void 0===c?void 0:c.alpha),backgroundImageBorderRadius:o.backgroundImageBorderRadius||(null===(f=o.background)||void 0===f?void 0:null===(v=f.image)||void 0===v?void 0:v.borderRadius),foregroundColor:o.foregroundColor||(null===(p=o.foreground)||void 0===p?void 0:p.color),foregroundImageSrc:o.foregroundImageSrc||(null===(C=o.foreground)||void 0===C?void 0:null===(b=C.image)||void 0===b?void 0:b.src),foregroundImageWidth:o.foregroundImageWidth||(null===(y=o.foreground)||void 0===y?void 0:null===(I=y.image)||void 0===I?void 0:I.width),foregroundImageHeight:o.foregroundImageHeight||(null===(k=o.foreground)||void 0===k?void 0:null===(w=k.image)||void 0===w?void 0:w.height),foregroundImageX:o.foregroundImageX||(null===(S=o.foreground)||void 0===S?void 0:null===(P=S.image)||void 0===P?void 0:P.x),foregroundImageY:o.foregroundImageY||(null===(B=o.foreground)||void 0===B?void 0:null===(T=B.image)||void 0===T?void 0:T.y),foregroundImagePadding:o.foregroundImagePadding||(null===(L=o.foreground)||void 0===L?void 0:null===(A=L.image)||void 0===A?void 0:A.padding),foregroundImageBackgroundColor:o.foregroundImageBackgroundColor||(null===(D=o.foreground)||void 0===D?void 0:null===(E=D.image)||void 0===E?void 0:E.backgroundColor),foregroundImageBorderRadius:o.foregroundImageBorderRadius||(null===(N=o.foreground)||void 0===N?void 0:null===(x=N.image)||void 0===x?void 0:x.borderRadius),foregroundImageShadowOffsetX:o.foregroundImageShadowOffsetX||(null===(R=o.foreground)||void 0===R?void 0:null===(z=R.image)||void 0===z?void 0:z.shadowOffsetX),foregroundImageShadowOffsetY:o.foregroundImageShadowOffsetY||(null===(_=o.foreground)||void 0===_?void 0:null===(M=_.image)||void 0===M?void 0:M.shadowOffsetY),foregroundImageShadowBlur:o.foregroundImageShadowBlur||(null===(O=o.foreground)||void 0===O?void 0:null===(F=O.image)||void 0===F?void 0:F.shadowBlur),foregroundImageShadowColor:o.foregroundImageShadowColor||(null===(j=o.foreground)||void 0===j?void 0:null===(H=j.image)||void 0===H?void 0:H.shadowColor),positionProbeBackgroundColor:o.positionProbeBackgroundColor||(null===(X=o.positionProbe)||void 0===X?void 0:X.backgroundColor)||(null===(Y=o.positionDetection)||void 0===Y?void 0:Y.backgroundColor),positionProbeForegroundColor:o.positionProbeForegroundColor||(null===(U=o.positionProbe)||void 0===U?void 0:U.foregroundColor)||(null===(Q=o.positionDetection)||void 0===Q?void 0:Q.foregroundColor),positionProbeImageSrc:o.positionProbeImageSrc||(null===(G=o.art)||void 0===G?void 0:null===(K=G.positionProbe)||void 0===K?void 0:K.imageSrc)||(null===(W=o.art)||void 0===W?void 0:null===(q=W.positionDetection)||void 0===q?void 0:q.image),positionProbeLeftUpperImageSrc:o.positionProbeLeftUpperImageSrc||(null===(J=o.art)||void 0===J?void 0:null===($=J.positionProbe)||void 0===$?void 0:null===(V=$.leftUpper)||void 0===V?void 0:V.imageSrc)||(null===(Z=o.art)||void 0===Z?void 0:null===(oo=Z.positionDetection)||void 0===oo?void 0:null===(eo=oo.upperLeft)||void 0===eo?void 0:eo.image),positionProbeRightUpperImageSrc:o.positionProbeRightUpperImageSrc||(null===(ro=o.art)||void 0===ro?void 0:null===(to=ro.positionProbe)||void 0===to?void 0:null===(io=to.rightUpper)||void 0===io?void 0:io.imageSrc)||(null===(no=o.art)||void 0===no?void 0:null===(ao=no.positionDetection)||void 0===ao?void 0:null===(uo=ao.upperRight)||void 0===uo?void 0:uo.image),positionProbeLeftLowerImageSrc:o.positionProbeLeftLowerImageSrc||(null===(so=o.art)||void 0===so?void 0:null===(go=so.positionProbe)||void 0===go?void 0:null===(lo=go.leftLower)||void 0===lo?void 0:lo.imageSrc)||(null===(ho=o.art)||void 0===ho?void 0:null===(mo=ho.positionDetection)||void 0===mo?void 0:null===(co=mo.lowerLeft)||void 0===co?void 0:co.image),separatorColor:o.separatorColor||(null===(fo=o.separator)||void 0===fo?void 0:fo.color),positionAdjustBackgroundColor:o.positionAdjustBackgroundColor||(null===(vo=o.positionAdjust)||void 0===vo?void 0:vo.backgroundColor)||(null===(po=o.alignment)||void 0===po?void 0:po.backgroundColor),positionAdjustForegroundColor:o.positionAdjustForegroundColor||(null===(Co=o.positionAdjust)||void 0===Co?void 0:Co.foregroundColor)||(null===(bo=o.alignment)||void 0===bo?void 0:bo.foregroundColor),positionAdjustImageSrc:o.positionAdjustImageSrc||(null===(yo=o.art)||void 0===yo?void 0:null===(Io=yo.positionAdjust)||void 0===Io?void 0:Io.imageSrc)||(null===(ko=o.art)||void 0===ko?void 0:null===(wo=ko.alignment)||void 0===wo?void 0:wo.image),timingBackgroundColor:o.timingBackgroundColor||(null===(So=o.timing)||void 0===So?void 0:So.backgroundColor),timingForegroundColor:o.timingForegroundColor||(null===(Po=o.timing)||void 0===Po?void 0:Po.foregroundColor),typeNumberBackgroundColor:o.typeNumberBackgroundColor||(null===(Bo=o.typeNumber)||void 0===Bo?void 0:Bo.backgroundColor)||(null===(To=o.versionInformation)||void 0===To?void 0:To.backgroundColor),typeNumberForegroundColor:o.typeNumberForegroundColor||(null===(Lo=o.typeNumber)||void 0===Lo?void 0:Lo.foregroundColor)||(null===(Ao=o.versionInformation)||void 0===Ao?void 0:Ao.foregroundColor),darkBlockColor:o.darkBlockColor||(null===(Do=o.darkBlock)||void 0===Do?void 0:Do.color),patterns:o.patterns||(null===(Eo=o.art)||void 0===Eo?void 0:Eo.patterns)||(null===(No=o.art)||void 0===No?void 0:null===(xo=No.shape)||void 0===xo?void 0:xo.map(o=>(o.imageSrc=o.image,o))),queue:o.queue},!0)},make(){this.foregroundColor===this.backgroundColor&&console.error("[uQRCode]: foregroundColor and backgroundColor cannot be the same!");var o=new e(this.typeNumber,this.errorCorrectLevel);o.addData(a.utf16To8(this.data.toString())),o.make(),this.typeNumber=o.typeNumber,this.modules=o.modules,this.moduleCount=o.moduleCount;var r=this.size-2*this.margin;this.dynamicSize=Math.ceil(r/o.moduleCount)*o.moduleCount+2*this.margin,this.useDynamicSize||(this.dynamicSize=this.size),this.paintData(),this.paintPositionProbe(),this.paintSeparator(),this.paintTiming(),this.paintPositionAdjust(),this.paintDarkBlock(),this.paintTypeNumber(),this.getDrawModules()},paintData(){let{dynamicSize:o,margin:e,backgroundColor:r,foregroundColor:t,modules:i,moduleCount:n}=this,a=(o-2*e)/n;for(var u=0;u<n;u++)for(var d=0;d<n;d++){var s=i[u][d];i[u][d]=s?{size:a,x:d*a+e,y:u*a+e,type:["foreground"],color:t,isBlack:!0,isDrawn:!1}:{size:a,x:d*a+e,y:u*a+e,type:["background"],color:r,isBlack:!1,isDrawn:!1}}},paintPositionProbe(){let{modules:o,moduleCount:e,positionProbeBackgroundColor:r,positionProbeForegroundColor:t}=this,i=[[0,0,1],[1,0,1],[2,0,1],[3,0,1],[4,0,1],[5,0,1],[6,0,1],[0,1,1],[1,1,0],[2,1,0],[3,1,0],[4,1,0],[5,1,0],[6,1,1],[0,2,1],[1,2,0],[2,2,1],[3,2,1],[4,2,1],[5,2,0],[6,2,1],[0,3,1],[1,3,0],[2,3,1],[3,3,1],[4,3,1],[5,3,0],[6,3,1],[0,4,1],[1,4,0],[2,4,1],[3,4,1],[4,4,1],[5,4,0],[6,4,1],[0,5,1],[1,5,0],[2,5,0],[3,5,0],[4,5,0],[5,5,0],[6,5,1],[0,6,1],[1,6,1],[2,6,1],[3,6,1],[4,6,1],[5,6,1],[6,6,1]],n=e-7;i.forEach(e=>{var i=o[e[0]][e[1]],a=o[e[0]+n][e[1]],u=o[e[0]][e[1]+n];u.type.push("positionProbe"),a.type.push("positionProbe"),i.type.push("positionProbe"),i.color=1==e[2]?t:r,a.color=1==e[2]?t:r,u.color=1==e[2]?t:r})},paintSeparator(){let{modules:o,moduleCount:e,separatorColor:r}=this;[[7,0],[7,1],[7,2],[7,3],[7,4],[7,5],[7,6],[7,7],[0,7],[1,7],[2,7],[3,7],[4,7],[5,7],[6,7]].forEach(t=>{var i=o[t[0]][t[1]],n=o[e-t[0]-1][t[1]],a=o[t[0]][e-t[1]-1];a.type.push("separator"),n.type.push("separator"),i.type.push("separator"),i.color=r,n.color=r,a.color=r})},paintPositionAdjust(){let{typeNumber:o,modules:e,moduleCount:r,foregroundColor:t,backgroundColor:i,positionAdjustForegroundColor:n,positionAdjustBackgroundColor:a,timingForegroundColor:u,timingBackgroundColor:d}=this;const s=[[],[6,18],[6,22],[6,26],[6,30],[6,34],[6,22,38],[6,24,42],[6,26,46],[6,28,50],[6,30,54],[6,32,58],[6,34,62],[6,26,46,66],[6,26,48,70],[6,26,50,74],[6,30,54,78],[6,30,56,82],[6,30,58,86],[6,34,62,90],[6,28,50,72,94],[6,26,50,74,98],[6,30,54,78,102],[6,28,54,80,106],[6,32,58,84,110],[6,30,58,86,114],[6,34,62,90,118],[6,26,50,74,98,122],[6,30,54,78,102,126],[6,26,52,78,104,130],[6,30,56,82,108,134],[6,34,60,86,112,138],[6,30,58,86,114,142],[6,34,62,90,118,146],[6,30,54,78,102,126,150],[6,24,50,76,102,128,154],[6,28,54,80,106,132,158],[6,32,58,84,110,136,162],[6,26,54,82,110,138,166],[6,30,58,86,114,142,170]],g=s[o-1];if(g){const o=[[-2,-2,1],[-1,-2,1],[0,-2,1],[1,-2,1],[2,-2,1],[-2,-1,1],[-1,-1,0],[0,-1,0],[1,-1,0],[2,-1,1],[-2,0,1],[-1,0,0],[0,0,1],[1,0,0],[2,0,1],[-2,1,1],[-1,1,0],[0,1,0],[1,1,0],[2,1,1],[-2,2,1],[-1,2,1],[0,2,1],[1,2,1],[2,2,1]],s=g.length;for(let l=0;l<s;l++)for(let h=0;h<s;h++){let{x:s,y:m}={x:g[l],y:g[h]};s<9&&m<9||s>r-9-1&&m<9||m>r-9-1&&s<9||o.forEach(o=>{var r=e[s+o[0]][m+o[1]];r.type.push("positionAdjust"),r.type.includes("timing")?1==o[2]?r.color=n==t?u:n:r.color=n==t&&a==i?d:a:r.color=1==o[2]?n:a})}}},paintTiming(){let{modules:o,moduleCount:e,timingForegroundColor:r,timingBackgroundColor:t}=this,i=e-16;for(let e=0;e<i;e++){var n=o[6][8+e],a=o[8+e][6];n.type.push("timing"),a.type.push("timing"),n.color=1&e^1?r:t,a.color=1&e^1?r:t}},paintDarkBlock(){let{modules:o,moduleCount:e,darkBlockColor:r}=this;var t=o[e-7-1][8];t.type.push("darkBlock"),t.color=r},paintTypeNumber(){let{typeNumber:o,modules:e,moduleCount:r,typeNumberBackgroundColor:t,typeNumberForegroundColor:i}=this;if(o<7)return e;const n=[0,0,0,0,0,0,0,"000111110010010100","001000010110111100","001001101010011001","001010010011010011","001011101111110110","001100011101100010","001101100001000111","001110011000001101","001111100100101000","010000101101111000","010001010001011101","010010101000010111","010011010100110010","010100100110100110","010101011010000011","010110100011001001","010111011111101100","011000111011000100","011001000111100001","011010111110101011","011011000010001110","011100110000011010","011101001100111111","011110110101110101","011111001001010000","100000100111010101","100001011011110000","100010100010111010","100011011110011111","100100101100001011","100101010000101110","100110101001100100","100111010101000001","101000110001101001"];let a=n[o]+n[o],u=[r-11,r-10,r-9],d=[[5,u[2]],[5,u[1]],[5,u[0]],[4,u[2]],[4,u[1]],[4,u[0]],[3,u[2]],[3,u[1]],[3,u[0]],[2,u[2]],[2,u[1]],[2,u[0]],[1,u[2]],[1,u[1]],[1,u[0]],[0,u[2]],[0,u[1]],[0,u[0]],[u[2],5],[u[1],5],[u[0],5],[u[2],4],[u[1],4],[u[0],4],[u[2],3],[u[1],3],[u[0],3],[u[2],2],[u[1],2],[u[0],2],[u[2],1],[u[1],1],[u[0],1],[u[2],0],[u[1],0],[u[0],0]];d.forEach((o,r)=>{var n=e[o[0]][o[1]];n.type.push("typeNumber"),n.color="1"==a[r]?i:t})},getDrawModules(){let o=this.drawModules=[],{modules:e,moduleCount:r,dynamicSize:t,backgroundColor:i,backgroundImageSrc:n,backgroundImageX:a,backgroundImageY:u,backgroundImageWidth:d,backgroundImageHeight:s,backgroundImageAlpha:g,backgroundImageBorderRadius:l,positionProbeLeftUpperImageSrc:h,positionProbeRightUpperImageSrc:m,positionProbeLeftLowerImageSrc:c,positionAdjustImageSrc:f,patterns:v,foregroundImageSrc:p,foregroundImageX:C,foregroundImageY:b,foregroundImageWidth:y,foregroundImageHeight:I,foregroundImagePadding:k,foregroundImageBackgroundColor:w,foregroundImageBorderRadius:S,foregroundImageShadowOffsetX:P,foregroundImageShadowOffsetY:B,foregroundImageShadowBlur:T,foregroundImageShadowColor:L}=this;if(i&&o.push({name:"background",type:"block",color:i,x:0,y:0,width:t,height:t}),n&&o.push({name:"backgroundImage",type:"image",imageSrc:n,imageSource:"backgroundImageSrc",x:a,y:u,width:d,height:s,alpha:g,borderRadius:l}),h){o.push({name:"foreground",type:"image",imageSrc:h,imageSource:"positionProbeLeftUpperImageSrc",x:e[0][0].x,y:e[0][0].y,width:e[0][7].x-e[0][0].x,height:e[7][0].y-e[0][0].y});for(var A=0;A<7;A++)for(var D=0;D<7;D++){var E=e[A][D];E.isDrawn=!0}}if(m){o.push({name:"foreground",type:"image",imageSrc:m,imageSource:"positionProbeRightUpperImageSrc",x:e[0][r-7].x,y:e[0][r-7].y,width:e[0][r-1].x-e[0][r-7-1].x,height:e[7][r-7-1].y-e[0][r-7].y});for(A=0;A<7;A++)for(D=7;D>0;D--){E=e[A][r-D];E.isDrawn=!0}}if(c){o.push({name:"foreground",type:"image",imageSrc:c,imageSource:"positionProbeLeftLowerImageSrc",x:e[r-7][0].x,y:e[r-7][0].y,width:e[r-7][7].x-e[r-7][0].x,height:e[r-1][0].y-e[r-7-1][0].y});for(A=7;A>0;A--)for(D=0;D<7;D++){E=e[r-A][D];E.isDrawn=!0}}if(f){let t=[];for(var N=0;N<r;N++)for(var x=0;x<r;x++){E=e[N][x];if(E.type.includes("positionAdjust")&&!E.isSign){for(var R={x:E.x,y:E.y,rowIndex:N,columnIndex:x},z=1;;){var _=e[N+z][x];if(!_.type.includes("positionAdjust"))break;z++}for(var M=1;;){_=e[N][x+M];if(!_.type.includes("positionAdjust"))break;M++}R.width=e[N][x+M].x-e[N][x].x,R.height=e[N+z][x].y-e[N][x].y,R.relativeLastRowIndex=z,R.relativeLastColumnIndex=M;for(A=0;A<z;A++)for(D=0;D<M;D++){var O=e[N+A][x+D];O.isSign=!0}t.push(R)}}t.forEach(r=>{o.push({name:"foreground",type:"image",imageSrc:f,imageSource:"positionAdjustImageSrc",x:r.x,y:r.y,width:r.width,height:r.height});for(var t=0;t<r.relativeLastRowIndex;t++)for(var i=0;i<r.relativeLastColumnIndex;i++){var n=e[r.rowIndex+t][r.columnIndex+i];n.isDrawn=!0}})}var F=v.filter(o=>o.imageSrc);if(F.length>0)for(A=0;A<F.length;A++){var j=F[A];for(N=0;N<r;N++)for(x=0;x<r;x++){E=e[N][x];if(!E.isDrawn&&(!j.isRandom||j.isRandom&&1==parseInt(2*Math.random()))){var H=j.matrix.length,X=j.matrix[0].length,Y=!0;if(N+H<=r&&x+X<=r)for(var U=0;U<H&&Y;U++)for(var Q=0;Q<X&&Y;Q++){var G=j.matrix[U][Q],K=e[N+U][x+Q];Y=1==G&&1==K.isBlack&&!K.isDrawn||(0==G&&0==K.isBlack&&!K.isDrawn||null==G&&!K.isDrawn)}else Y=!1;if(Y){o.push({name:"foreground",type:"image",imageSrc:j.imageSrc,imageSource:`patterns[${A}].imageSrc`,x:E.x,y:E.y,width:E.size*X,height:E.size*H});for(U=0;U<H;U++)for(Q=0;Q<X;Q++){G=j.matrix[U][Q],K=e[N+U][x+Q];null!=G&&(K.isDrawn=!0)}}}}}for(N=0;N<r;N++)for(x=0;x<r;x++){E=e[N][x];E.isDrawn||E.color==i||(o.push({name:"foreground",type:"block",color:E.color,x:E.x,y:E.y,width:E.size,height:E.size}),E.isDrawn=!0)}p&&o.push({name:"foregroundImage",type:"image",imageSrc:p,imageSource:"foregroundImageSrc",x:C,y:b,width:y,height:I,padding:k,backgroundColor:w,borderRadius:S,shadowOffsetX:P,shadowOffsetY:B,shadowBlur:T,shadowColor:L})},drawCanvas(){let{drawModules:o,canvasContext:e,foregroundColor:r,backgroundColor:t,queue:i}=this;if(r===t)return Promise.reject({errmsg:"[uQRCode]: foregroundColor and backgroundColor cannot be the same!"});let n=async(r,t)=>{e.draw(!1);let n=!1;for(var u=0;u<o.length;u++){var d=o[u];switch(e.save(),d.type){case"block":e.setFillStyle(d.color),e.fillRect(d.x,d.y,d.width,d.height);break;case"image":if("backgroundImage"===d.name){var s=d.x,g=d.y,l=d.width,h=d.height,m=d.borderRadius;l<2*m&&(m=l/2),h<2*m&&(m=h/2),e.globalAlpha=d.alpha,e.beginPath(),e.moveTo(s+m,g),e.arcTo(s+l,g,s+l,g+h,m),e.arcTo(s+l,g+h,s,g+h,m),e.arcTo(s,g+h,s,g,m),e.arcTo(s,g,s+l,g,m),e.closePath(),e.strokeStyle="rgba(0,0,0,0)",e.stroke(),e.clip()}else if("foregroundImage"===d.name){s=d.x,g=d.y,l=d.width,h=d.height,m=d.borderRadius;l<2*m&&(m=l/2),h<2*m&&(m=h/2);var c=d.x-d.padding,f=d.y-d.padding,v=d.width+2*d.padding,p=d.height+2*d.padding,C=v/l*m;v<2*C&&(C=v/2),p<2*C&&(C=p/2),e.save(),e.shadowOffsetX=d.shadowOffsetX,e.shadowOffsetY=d.shadowOffsetY,e.shadowBlur=d.shadowBlur,e.shadowColor=d.shadowColor,e.beginPath(),e.moveTo(c+C,f),e.arcTo(c+v,f,c+v,f+p,C),e.arcTo(c+v,f+p,c,f+p,C),e.arcTo(c,f+p,c,f,C),e.arcTo(c,f,c+v,f,C),e.closePath(),e.setFillStyle(d.backgroundColor),e.fill(),e.restore(),e.beginPath(),e.moveTo(c+C,f),e.arcTo(c+v,f,c+v,f+p,C),e.arcTo(c+v,f+p,c,f+p,C),e.arcTo(c,f+p,c,f,C),e.arcTo(c,f,c+v,f,C),e.closePath(),e.setFillStyle(d.padding>0?d.backgroundColor:"rgba(0,0,0,0)"),e.fill(),e.beginPath(),e.moveTo(s+m,g),e.arcTo(s+l,g,s+l,g+h,m),e.arcTo(s+l,g+h,s,g+h,m),e.arcTo(s,g+h,s,g,m),e.arcTo(s,g,s+l,g,m),e.closePath(),e.strokeStyle="rgba(0,0,0,0)",e.stroke(),e.clip()}try{var b=await a.loadImage(d.imageSrc);e.drawImage(b,d.x,d.y,d.width,d.height)}catch(o){console.error(`[uQRCode]: ${d.imageSource} invalid!`),t({errmsg:`[uQRCode]: ${d.imageSource} invalid!`}),n=!0}}if(n)return;i&&e.draw(!0),e.restore()}e.draw(!0),setTimeout(r,150)};return new Promise((o,e)=>{i?a.queue.exec(()=>new Promise((o,e)=>{n(o,e)})).then(()=>{setTimeout(o,150)}).catch(o=>{e(o)}):n(o,e)})},draw(){return this.drawCanvas()}},uQRCode=a,uQRCode.export=function(){var o,e;o="undefined"!=typeof window?window:global,e=uQRCode,"undefined"!=typeof module&&"object"==typeof exports?module.exports=e:"function"==typeof define&&(define.amd||define.cmd)?define(function(){return e}):o.UQRCode=e}}();
//---------------------------------------------------------------------
// 默认导出方式,非vite(vue3)使用该方式。
// ↓
//---------------------------------------------------------------------
// uQRCode.export();
//---------------------------------------------------------------------
// ES6导出方式,vite(vue3)使用该方式。
// ↓
//---------------------------------------------------------------------
export default uQRCode;
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
{
"id": "Sansnn-uQRCode",
"displayName": "uQRCode 全端二维码生成插件 支持nvue 支持nodejs服务端",
"version": "3.5.1",
"description": "uQRCode是一款基于Javascript环境开发的二维码生成插件,适用所有Javascript运行环境的前端应用和Node.js。",
"keywords": [
"uQRCode",
"二维码",
"qrcode",
"qr"
],
"repository": "https://github.com/Sansnn/uQRCode",
"engines": {
},
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/uqrcodejs",
"type": "sdk-js"
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "y",
"联盟": "y"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}
# 介绍
`uQRCode`是一款基于`Javascript`环境开发的二维码生成插件,适用所有`Javascript`运行环境的前端应用和`Node.js`应用。
`uQRCode`可扩展性高,它支持自定义渲染二维码,可通过`uQRCode API`得到二维码绘制关键信息后,使用`canvas``svg``js`操作`dom`的方式绘制二维码图案。还可自定义二维码样式,如随机颜色、圆点、方块、块与块之间的间距等。
欢迎加入群聊【uQRCode交流群】:[695070434](https://jq.qq.com/?_wv=1027&k=JRjzDqiw)
# 快速上手
> 在`uni-app`中,我们更推荐使用组件方式来生成二维码,组件方式大大提高了页面的可读性以及避开了一些平台容易出问题的地方,当组件无法满足需求的时候,再考虑切换成原生方式。
官方文档:[https://doc.uqrcode.cn](https://doc.uqrcode.cn)
github地址:[https://github.com/Sansnn/uQRCode](https://github.com/Sansnn/uQRCode)
npm地址:[https://www.npmjs.com/package/uqrcodejs](https://www.npmjs.com/package/uqrcodejs)
uni-app插件市场地址:[https://ext.dcloud.net.cn/plugin?id=1287](https://ext.dcloud.net.cn/plugin?id=1287)
## 原生方式
原生方式仅需要获取`uqrcode.js`文件便可使用。
### 安装
1. 通过`npm`安装,成功后即可使用`import``require`进行引用。
``` bash
# npm安装
npm install uqrcodejs
# 或者
npm install @uqrcode/js
```
2. 通过项目开源地址获取`uqrcode.js`,下载`uqrcode.js`后,将其复制到您项目指定目录,在页面中引入`uqrcode.js`文件即可开始使用。
### 引入
- 通过`import`引入。
``` javascript
import UQRCode from 'uqrcode';
```
- `Node.js`通过`require`引入。
``` javascript
const UQRCode = require('uqrcode');
```
- 原生浏览器环境,在js脚本加载时添加到`window`
``` html
<script type="text/javascript" src="uqrcode.js"></script>
<script>
var UQRCode = window.UQRCode;
</script>
```
> `vue3`推荐使用`npm`安装,非`npm`安装直接引入`uqrcode.js`文件如果出现报错:`SyntaxError: The requested module 'uqrcode.js' does not provide an export named 'default'`,在`uqrcode.js`文件中最后一行添加`export default uQRCode`即可。
### 简单用法
`uQRCode`基于`Canvas API`封装了一套方法,建议开发者使用`canvas`生成,一键调用,非常方便。以下是示例:
- HTML部分
``` html
<canvas id="qrcode" width="200" height="200"></canvas>
```
- JS部分
``` javascript
// 获取uQRCode实例
var qr = new UQRCode();
// 设置二维码内容
qr.data = "https://doc.uqrcode.cn";
// 设置二维码大小,必须与canvas设置的宽高一致
qr.size = 200;
// 调用制作二维码方法
qr.make();
// 获取canvas元素
var canvas = document.getElementById("qrcode");
// 获取canvas上下文
var canvasContext = canvas.getContext("2d");
// 设置uQRCode实例的canvas上下文
qr.canvasContext = canvasContext;
// 调用绘制方法将二维码图案绘制到canvas上
qr.drawCanvas();
```
### 高级用法
考虑到部分平台可能不支持`canvas`,所以`uQRCode`并没有强制要求和`canvas`一起使用,您还可以选择其他方式来生成二维码,例如使用`js`操作`dom`进行绘制或是使用`svg`绘制等。以下是示例:
- js操作dom
``` html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>uQRCode二维码生成</title>
</head>
<body>
<div id="qrcode" style="position: relative;"></div>
<script type="text/javascript" src="uqrcode.js"></script>
<script>
// 引入uQRCode
var UQRCode = window.UQRCode;
// 获取uQRCode实例
var qr = new UQRCode();
// 设置二维码内容
qr.data = "https://doc.uqrcode.cn";
// 设置二维码大小,必须与canvas设置的宽高一致
qr.size = 200;
// 设置二维码前景图,可以是路径
qr.foregroundImageSrc =
'data:image/png;base64,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';
// 调用制作二维码方法
qr.make();
// 遍历drawModules创建dom元素
var qrHtml = '';
for (var i = 0; i < qr.drawModules.length; i++) {
var drawModule = qr.drawModules[i];
switch (drawModule.type) {
case 'block':
/* 绘制小块 */
qrHtml += `<div style="position: absolute;left: ${drawModule.x}px;top: ${drawModule.y}px;width: ${drawModule.width}px;height: ${drawModule.height}px;background: ${drawModule.color};"></div>`;
break;
case 'image':
/* 绘制图像 */
qrHtml += `<img style="position: absolute;left: ${drawModule.x}px;top: ${drawModule.y}px;width: ${drawModule.width}px;height: ${drawModule.height}px;" src="${drawModule.imageSrc}" />`;
break;
}
}
document.getElementById('qrcode').innerHTML = qrHtml;
</script>
</body>
</html>
```
- svg
``` html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>uQRCode二维码生成</title>
</head>
<body>
<svg id="qrcode" width="200" height="200" xmlns="http://www.w3.org/2000/svg" version="1.1"></svg>
<script type="text/javascript" src="uqrcode.js"></script>
<script>
// 引入uQRCode
var UQRCode = window.UQRCode;
// 获取uQRCode实例
var qr = new UQRCode();
// 设置二维码内容
qr.data = "https://doc.uqrcode.cn";
// 设置二维码大小,必须与canvas设置的宽高一致
qr.size = 200;
// 设置二维码前景图,可以是路径
qr.foregroundImageSrc =
'data:image/png;base64,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';
// 调用制作二维码方法
qr.make();
// 遍历drawModules创建svg元素
var qrHtml = '';
for (var i = 0; i < qr.drawModules.length; i++) {
var drawModule = qr.drawModules[i];
switch (drawModule.type) {
case 'block':
/* 绘制小块 */
qrHtml += `<rect x="${drawModule.x}" y="${drawModule.y}" width="${drawModule.width}" height="${drawModule.height}" style="fill: ${drawModule.color};" />`;
break;
case 'image':
/* 绘制图像 */
qrHtml += `<image href="${drawModule.imageSrc}" x="${drawModule.x}" y="${drawModule.y}" width="${drawModule.width}" height="${drawModule.height}" />`;
break;
}
}
document.getElementById('qrcode').innerHTML = qrHtml;
</script>
</body>
</html>
```
> 更多用法大家自行探索咯,期待分享哟~
### 导出临时文件路径
原生方式基于`Canvas`的,请自行参阅各平台`Canvas`的导出方式。以下是部分示例:
- uni-app
```javascript
// 通过uni.createCanvasContext方式创建绘制上下文的,对应导出API为uni.canvasToTempFilePath
// 调用完ctx.draw()方法后不能第一时间导出,否则会异常,需要有一定的延时
setTimeout(() => {
uni.canvasToTempFilePath(
{
canvasId: this.canvasId,
fileType: this.fileType,
width: this.canvasWidth,
height: this.canvasHeight,
success: res => {
console.log(res);
},
fail: err => {
console.log(err);
}
},
// this // 组件内使用必传当前实例
);
}, 300);
```
- Canvas2D
```javascript
// 得到base64
console.log(canvas.toDataURL());
// 得到buffer
console.log(canvas.toBuffer());
```
### 保存二维码到本地相册
必须在导出临时文件路径成功后再执行保存。uni-app通用保存方式(H5除外):
```javascript
uni.saveImageToPhotosAlbum({
filePath: tempFilePath,
success: res => {
console.log(res);
},
fail: err => {
console.log(err);
}
});
```
H5可以通过设置`<a>`标签`href`属性的方式进行保存:
```javascript
const aEle = document.createElement('a');
aEle.download = 'uQRCode'; // 设置下载的文件名,默认是'下载'
aEle.href = tempFilePath;
document.body.appendChild(aEle);
aEle.click();
aEle.remove(); // 下载之后把创建的元素删除
```
经过测试,PC端浏览器可以下载,部分安卓自带或第三方浏览器可以下载,安卓微信浏览器不适用,移动端iOS所有浏览器均不适用,差异较大,还是推荐各位导出文件给图片组件显示,然后提示用户通过长按图片进行保存这种方式。
## uni-app组件方式
### 安装
通过uni-app插件市场地址安装:[https://ext.dcloud.net.cn/plugin?id=1287](https://ext.dcloud.net.cn/plugin?id=1287)
### 引入
uni-app默认为easycom模式,可直接键入`<uqrcode>`标签。
### 简单用法
安装`uqrcode`组件后,在`template`中键入`<uqrcode/>`。设置`ref`属性可使用组件内部方法,`canvas-id`属性为组件内部的canvas组件标识,`value`属性为二维码生成对应内容。
``` html
<uqrcode ref="qrcode" canvas-id="qrcode" value="https://doc.uqrcode.cn"></uqrcode>
```
### 导出临时文件路径
为了保证方法调用成功,请在 [complete](/document/uni-app.md#complete) 事件返回`success=true`后调用。
```javascript
// uqrcode为组件的ref名称
this.$refs.uqrcode.toTempFilePath({
success: res => {
console.log(res);
}
});
```
### 保存二维码到本地相册
为了保证方法调用成功,请在 [complete](/document/uni-app.md#complete) 事件返回`success=true`后调用。
```javascript
// uqrcode为组件的ref名称
this.$refs.uqrcode.save({
success: () => {
uni.showToast({
icon: 'success',
title: '保存成功'
});
}
});
```
## 更多配置说明请前往官方文档查看:[https://doc.uqrcode.cn](https://doc.uqrcode.cn)。
\ No newline at end of file
## 1.0.21(2022-09-21)
- 修复 store.hasLogin的值在某些情况下会出错的bug
## 1.0.20(2022-09-21)
- 新增 store 账号信息状态管理,详情:用户中心页面 路径:`/uni_modules/uni-id-pages/pages/userinfo/userinfo`
## 1.0.19(2022-09-20)
- 修复 小程序端,使用将自定义节点设置成[虚拟节点](https://uniapp.dcloud.net.cn/tutorial/vue-api.html#%E5%85%B6%E4%BB%96%E9%85%8D%E7%BD%AE)的uni-ui组件,样式错乱的问题
## 1.0.18(2022-09-20)
......
import pagesJson from '@/pages.json'
const uniIdCo = uniCloud.importObject("uni-id-co")
export default {
async logout() {
await uniIdCo.logout()
uni.removeStorageSync('uni_id_token');
uni.setStorageSync('uni_id_token_expired', 0)
uni.redirectTo({
url: `/${pagesJson.uniIdRouter?.loginPage ?? 'uni_modules/uni-id-pages/pages/login/login-withoutpwd'}`,
});
uni.$emit('uni-id-pages-logout')
},
}
import loginSuccess from './loginSuccess.js';
import {
store,
mutations
} from '@/uni_modules/uni-id-pages/common/store.js'
import config from '@/uni_modules/uni-id-pages/config.js'
let mixin = {
data() {
......@@ -75,7 +78,7 @@ let mixin = {
},
methods: {
loginSuccess(e) {
loginSuccess({
mutations.loginSuccess({
...e,
uniIdRedirectUrl: this.uniIdRedirectUrl
})
......
......@@ -51,7 +51,12 @@
.register-back{
display: none;
}
}
uni-button{
padding-bottom: 1px;
}
/* #endif */
}
......@@ -81,13 +86,13 @@
}
/* #ifdef MP */
/* #ifndef APP-NVUE */
// 解决小程序端开启虚拟节点virtualHost引起的 class = input-box丢失的问题 [详情参考](https://uniapp.dcloud.net.cn/matter.html#%E5%90%84%E5%AE%B6%E5%B0%8F%E7%A8%8B%E5%BA%8F%E5%AE%9E%E7%8E%B0%E6%9C%BA%E5%88%B6%E4%B8%8D%E5%90%8C-%E5%8F%AF%E8%83%BD%E5%AD%98%E5%9C%A8%E7%9A%84%E5%B9%B3%E5%8F%B0%E5%85%BC%E5%AE%B9%E9%97%AE%E9%A2%98)
.uni-content ::v-deep .uni-easyinput__content,
/* #endif */
.input-box {
padding: 4px;
height: 44px;
background-color: #F8F8F8 !important;
border-radius: 0;
font-size: 14px;
......
import pagesJson from '@/pages.json'
export default function(e = {}) {
const {
showToast = true, toastText = '登录成功', autoBack = true, uniIdRedirectUrl = ''
} = e
console.log({
toastText,
autoBack
});
if (showToast) {
uni.showToast({
title: toastText,
icon: 'none'
});
}
if (autoBack) {
let delta = 0; //判断需要返回几层
let pages = getCurrentPages();
uni.$emit('uni-id-pages-login-success',pages)
console.log(pages);
pages.forEach((page, index) => {
if (pages[pages.length - index - 1].route.split('/')[3] == 'login') {
delta++
}
})
console.log('判断需要返回几层:',pages, delta);
if (uniIdRedirectUrl) {
return uni.reLaunch({
url: uniIdRedirectUrl
})
}
// #ifdef H5
if(e.loginType == 'weixin'){
console.log('window.history',window.history);
return window.history.go(-3)
}
// #endif
if (delta) {
const page = pagesJson.pages[0]
return uni.reLaunch({
url: `/${page.path}`
})
}
uni.navigateBack({
delta
})
}
}
import pagesJson from '@/pages.json'
const uniIdCo = uniCloud.importObject("uni-id-co")
const db = uniCloud.database();
const usersTable = db.collection('uni-id-users')
let hostUserInfo = uni.getStorageSync('uni-id-pages-userInfo')||{}
console.log( hostUserInfo);
const data = {
userInfo: hostUserInfo,
hasLogin: Object.keys(hostUserInfo).length != 0
}
console.log('data', data);
// 定义 mutations, 修改属性
export const mutations = {
// data不为空,表示传递要更新的值(注意不是覆盖是合并),什么也不传时,直接查库获取更新
async updateUserInfo(data = false) {
if (data) {
usersTable.where('_id==$env.uid').update(data).then(e => {
console.log(e);
if (e.result.updated) {
uni.showToast({
title: "更新成功",
icon: 'none'
});
this.setUserInfo(data)
} else {
uni.showToast({
title: "没有改变",
icon: 'none'
});
}
})
} else {
try {
let res = await usersTable.where("'_id' == $cloudEnv_uid")
.field('mobile,nickname,user_name,email,avatar_file')
.get()
console.log('fromDbData',res.result.data);
this.setUserInfo(res.result.data[0])
} catch (e) {
this.setUserInfo({},{cover:true})
console.error(e.message, e.errCode);
}
}
},
async setUserInfo(data, {cover}={cover:false}) {
console.log('set-userInfo', data);
let userInfo = cover?data:Object.assign(store.userInfo,data)
store.userInfo = Object.assign({},userInfo)
store.hasLogin = Object.keys(store.userInfo).length != 0
console.log('store.userInfo', store.userInfo);
uni.setStorage({
key: "uni-id-pages-userInfo",
data:store.userInfo
})
return data
},
async logout() {
await uniIdCo.logout()
uni.removeStorageSync('uni_id_token');
uni.setStorageSync('uni_id_token_expired', 0)
uni.redirectTo({
url: `/${pagesJson.uniIdRouter?.loginPage ?? 'uni_modules/uni-id-pages/pages/login/login-withoutpwd'}`,
});
uni.$emit('uni-id-pages-logout')
this.setUserInfo({},{cover:true})
},
loginSuccess(e){
const {
showToast = true, toastText = '登录成功', autoBack = true, uniIdRedirectUrl = ''
} = e
console.log({
toastText,
autoBack
});
if (showToast) {
uni.showToast({
title: toastText,
icon: 'none'
});
}
this.updateUserInfo()
uni.$emit('uni-id-pages-login-success')
if (autoBack) {
let delta = 0; //判断需要返回几层
let pages = getCurrentPages();
// console.log(pages);
pages.forEach((page, index) => {
if (pages[pages.length - index - 1].route.split('/')[3] == 'login') {
delta++
}
})
console.log('判断需要返回几层:', pages, delta);
if (uniIdRedirectUrl) {
return uni.reLaunch({
url: uniIdRedirectUrl
})
}
// #ifdef H5
if (e.loginType == 'weixin') {
console.log('window.history', window.history);
return window.history.go(-3)
}
// #endif
if (delta) {
const page = pagesJson.pages[0]
return uni.reLaunch({
url: `/${page.path}`
})
}
uni.navigateBack({
delta
})
}
}
}
// #ifdef VUE2
import Vue from 'vue'
// 通过Vue.observable创建一个可响应的对象
export const store = Vue.observable(data)
// #endif
// #ifdef VUE3
import {
reactive
} from 'vue'
// 通过Vue.observable创建一个可响应的对象
export const store = reactive(data)
// #endif
......@@ -67,7 +67,7 @@
},
methods: {
popupConfirm(){
console.log("popupConfirm");
// console.log("popupConfirm");
this.isAgree = true
retryFun()
// this.$emit('popupConfirm')
......
<template>
<view @click="uploadAvatarImg">
<view @click="uploadAvatarImg" class="box" :class="{'showBorder':border}" :style="{width,height,lineHeight:height}">
<cloud-image v-if="avatar_file" :src="avatar_file.url" :width="width" :height="height"></cloud-image>
<uni-icons v-else :style="{width,height,lineHeight:height}" class="chooseAvatar" type="plusempty" size="30"
color="#dddddd"></uni-icons>
......@@ -7,20 +7,20 @@
</template>
<script>
const db = uniCloud.database();
const usersTable = db.collection('uni-id-users')
import {
store,
mutations
} from '@/uni_modules/uni-id-pages/common/store.js'
/**
* uni-id-pages-avatar
* @description 用户头像组件
* @property {String} width 图片的宽,默认为:50px
* @property {String} height 图片的高,默认为:50px
*/
export default {
export default {
data() {
return {
userInfo: {},
isPC: false,
hasLogin:false
isPC: false
}
},
props: {
......@@ -37,71 +37,38 @@
default () {
return "50px"
}
},
border:{
type: Boolean,
default () {
return false
}
}
},
async mounted() {
usersTable.where("'_id' == $cloudEnv_uid").field('avatar_file,mobile,nickname').get().then(res=>{
this.userInfo = res.result.data[0]||{}
console.log('this.userInfo', this.userInfo);
this.hasLogin = true
}).catch (e=>{
this.userInfo = {}
this.hasLogin = false
console.log(e.message, e.errCode);
})
// try {
// let res = await usersTable.where("'_id' == $cloudEnv_uid").field('avatar_file').get()
// this.userInfo = res.result.data[0]
// console.log('this.userInfo', this.userInfo);
// } catch (e) {
// console.log(e.message);
// }
// #ifdef H5
this.isPC = !['ios', 'android'].includes(uni.getSystemInfoSync().platform);
console.log(' this.isPC', this.isPC, uni.getSystemInfoSync().platform);
// #endif
},
computed: {
avatar_file() {
if (this.userInfo.avatar_file && this.userInfo.avatar_file.url) {
return this.userInfo.avatar_file
}
hasLogin() {
return store.hasLogin
},
userInfo() {
return store.userInfo
},
avatar_file() {
return store.userInfo.avatar_file
}
},
methods: {
setAvatarFile(avatar_file) {
uni.showLoading({
title: "设置中",
mask: true
});
// 使用 clientDB 提交数据
usersTable.where('_id==$env.uid').update({
avatar_file
}).then((res) => {
console.log(res);
if (avatar_file) {
uni.showToast({
icon: 'none',
title: "更新成功"
})
} else {
uni.showToast({
icon: 'none',
title: "删除成功"
})
}
this.$set(this.userInfo, 'avatar_file', avatar_file)
}).catch((err) => {
uni.showModal({
content: err.message || "请求失败",
showCancel: false
})
}).finally(() => {
uni.hideLoading()
})
// 使用 clientDB 提交数据
mutations.updateUserInfo({avatar_file})
},
uploadAvatarImg(res) {
uploadAvatarImg(res) {
console.log(this.hasLogin);
if(!this.hasLogin){
return uni.navigateTo({
url:'/uni_modules/uni-id-pages/pages/login/login-withoutpwd'
......@@ -176,13 +143,24 @@
}
</script>
<style>
<style>
/* #ifndef APP-NVUE */
.box{
overflow: hidden;
}
/* #endif */
.chooseAvatar {
/* #ifndef APP-NVUE */
display: inline-block;
display: inline-block;
box-sizing: border-box;
/* #endif */
border: dotted 1px #ddd;
border-radius: 10px;
text-align: center;
text-align: center;
padding: 1px;
}
.showBorder{
border: solid 1px #ddd;
}
</style>
......@@ -14,8 +14,11 @@
</template>
<script>
import config from '@/uni_modules/uni-id-pages/config.js'
//前一个窗口的页面地址。控制点击切换快捷登录方式是创建还是返回
import loginSuccess from '../../common/loginSuccess.js';
//前一个窗口的页面地址。控制点击切换快捷登录方式是创建还是返回
import {
store,
mutations
} from '@/uni_modules/uni-id-pages/common/store.js'
const db = uniCloud.database();
const usersTable = db.collection('uni-id-users')
......@@ -438,8 +441,8 @@
});
// #ifdef MP-WEIXIN
//如果是微信小程序端的微信登录,且为首次登录,就弹出获取微信昵称+头像用于绑定资料
if (type == 'weixin' && result.type == "register") {
loginSuccess({
if (type == 'weixin' && result.type == "register") {
mutations.loginSuccess({
...result,
showToast: false,
autoBack: false
......@@ -450,7 +453,7 @@
// #ifdef H5
result.loginType = type
// #endif
loginSuccess(result)
mutations.loginSuccess(result)
})
.catch(e=>{
console.log(e);
......@@ -469,7 +472,7 @@
},
doUserProfileNext() {
try {
loginSuccess()
mutations.loginSuccess()
} catch (e) {
console.log(e);
}
......
{
"id": "uni-id-pages",
"displayName": "uni-id-pages",
"version": "1.0.19",
"version": "1.0.21",
"description": "云端一体简单、统一、可扩展的用户中心页面模版",
"keywords": [
"用户管理",
......
......@@ -56,8 +56,8 @@
},
async onLoad(e) {
console.log(e);
let type = e.type
// console.log({type});
//获取通过url传递的参数type设置当前登录方式,如果没传递直接默认以配置的登录
let type = e.type || config.loginTypes[0]
this.type = type
if(type != 'univerify'){
this.focusPhone = true
......@@ -65,8 +65,7 @@
this.$nextTick(() => {
//关闭重复显示的登录快捷方式
if (['weixin', 'apple'].includes(type)) {
this.$refs.uniFabLogin.servicesList = this.$refs.uniFabLogin.servicesList.filter(item =>
item.id != type)
this.$refs.uniFabLogin.servicesList = this.$refs.uniFabLogin.servicesList.filter(item =>item.id != type)
}
})
uni.$on('uni-id-pages-set-login-type', type => {
......
<!-- 账号密码登录页 -->
<template>
<view class="uni-content">
<view class="login-logo">
<image :src="logo"></image>
</view>
<!-- 顶部文字 -->
<text class="title title-box">账号密码登录</text>
<uni-forms>
<uni-forms-item name="username">
<uni-easyinput :focus="focusUsername" @blur="focusUsername = false" class="input-box" :inputBorder="false" v-model="username" placeholder="请输入手机号/用户名/邮箱" />
</uni-forms-item>
<uni-forms-item name="password">
<uni-easyinput :focus="focusPassword" @blur="focusPassword = false" class="input-box" clearable type="password" :inputBorder="false" v-model="password"
placeholder="请输入密码" />
</uni-forms-item>
</uni-forms>
<uni-captcha v-if="needCaptcha" focus ref="captcha" scene="login-by-pwd" v-model="captcha" />
<!-- 带选择框的隐私政策协议组件 -->
<uni-id-pages-agreements scope="login" ref="agreements" ></uni-id-pages-agreements>
<button class="uni-btn" type="primary" @click="pwdLogin">登录</button>
<!-- 忘记密码 -->
<view class="link-box">
<view v-if="!config.isAdmin">
<text class="forget">忘记了?</text>
<text class="link" @click="toRetrievePwd">找回密码</text>
</view>
<text class="link" @click="toRegister">{{config.isAdmin ? '注册管理员账号': '注册账号'}}</text>
<!-- <text class="link" @click="toRegister" v-if="!config.isAdmin">注册账号</text> -->
</view>
<!-- 悬浮登录方式组件 -->
<uni-id-pages-fab-login ref="uniFabLogin"></uni-id-pages-fab-login>
</view>
</template>
<script>
import mixin from '@/uni_modules/uni-id-pages/common/login-page.mixin.js';
const uniIdCo = uniCloud.importObject("uni-id-co",{
errorOptions:{
type:'toast'
}
})
export default {
mixins: [mixin],
data() {
return {
"password": "",
"username": "",
"captcha": "",
"needCaptcha": false,
"focusUsername":false,
"focusPassword":false,
"logo": "/static/logo.png"
}
},
onShow() {
// #ifdef H5
document.onkeydown = event => {
var e = event || window.event;
if (e && e.keyCode == 13) { //回车键的键值为13
this.pwdLogin()
}
};
// #endif
},
methods: {
// 页面跳转,找回密码
toRetrievePwd() {
let url = '/uni_modules/uni-id-pages/pages/retrieve/retrieve'
//如果刚好用户名输入框的值为手机号码,就把它传到retrieve页面,根据该手机号找回密码
if (/^1\d{10}$/.test(this.username)) {
url += `?phoneNumber=${this.username}`
}
uni.navigateTo({
url
})
},
/**
* 密码登录
*/
pwdLogin() {
if(!this.password.length){
this.focusPassword = true
return uni.showToast({
title: '请输入密码',
icon: 'none'
});
}
if(!this.username.length){
this.focusUsername = true
return uni.showToast({
title: '请输入手机号/用户名/邮箱',
icon: 'none'
});
}
if(this.needCaptcha && this.captcha.length!=4){
this.$refs.captcha.getImageCaptcha()
return uni.showToast({
title: '请输入验证码',
icon: 'none'
});
}
if (this.needAgreements && !this.agree) {
return this.$refs.agreements.popup(this.pwdLogin)
}
let data = {
"password": this.password,
"captcha": this.captcha
}
if (/^1\d{10}$/.test(this.username)) {
data.mobile = this.username
}else if(/@/.test(this.username)) {
data.email = this.username
}else{
data.username = this.username
}
uniIdCo.login(data).then(e => {
this.loginSuccess(e)
}).catch(e => {
if(e.errCode == 'uni-id-captcha-required'){
this.needCaptcha = true
}else if(this.needCaptcha){
//登录失败,自动重新获取验证码
this.$refs.captcha.getImageCaptcha()
}
})
},
/* 前往注册 */
toRegister() {
uni.navigateTo({
url: this.config.isAdmin ? '/uni_modules/uni-id-pages/pages/register/register-admin': '/uni_modules/uni-id-pages/pages/register/register',
fail(e) {
console.error(e);
}
})
}
}
}
</script>
<style lang="scss" scoped>
@import "@/uni_modules/uni-id-pages/common/login-page.scss";
@media screen and (min-width: 690px) {
}
.forget{
font-size: 12px;
color: #8a8f8b;
}
.link-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: space-between;
margin-top: 20px;
}
.link {
font-size: 12px;
}
<!-- 账号密码登录页 -->
<template>
<view class="uni-content">
<view class="login-logo">
<image :src="logo"></image>
</view>
<!-- 顶部文字 -->
<text class="title title-box">账号密码登录</text>
<uni-forms>
<uni-forms-item name="username">
<uni-easyinput :focus="focusUsername" @blur="focusUsername = false" class="input-box"
:inputBorder="false" v-model="username" placeholder="请输入手机号/用户名/邮箱" />
</uni-forms-item>
<uni-forms-item name="password">
<uni-easyinput :focus="focusPassword" @blur="focusPassword = false" class="input-box" clearable
type="password" :inputBorder="false" v-model="password" placeholder="请输入密码" />
</uni-forms-item>
</uni-forms>
<uni-captcha v-if="needCaptcha" focus ref="captcha" scene="login-by-pwd" v-model="captcha" />
<!-- 带选择框的隐私政策协议组件 -->
<uni-id-pages-agreements scope="login" ref="agreements"></uni-id-pages-agreements>
<button class="uni-btn" type="primary" @click="pwdLogin">登录</button>
<!-- 忘记密码 -->
<view class="link-box">
<view v-if="!config.isAdmin">
<text class="forget">忘记了?</text>
<text class="link" @click="toRetrievePwd">找回密码</text>
</view>
<text class="link" @click="toRegister">{{config.isAdmin ? '注册管理员账号': '注册账号'}}</text>
<!-- <text class="link" @click="toRegister" v-if="!config.isAdmin">注册账号</text> -->
</view>
<!-- 悬浮登录方式组件 -->
<uni-id-pages-fab-login ref="uniFabLogin"></uni-id-pages-fab-login>
</view>
</template>
<script>
import mixin from '@/uni_modules/uni-id-pages/common/login-page.mixin.js';
const uniIdCo = uniCloud.importObject("uni-id-co", {
errorOptions: {
type: 'toast'
}
})
export default {
mixins: [mixin],
data() {
return {
"password": "",
"username": "",
"captcha": "",
"needCaptcha": false,
"focusUsername": false,
"focusPassword": false,
"logo": "/static/logo.png"
}
},
onShow() {
// #ifdef H5
document.onkeydown = event => {
var e = event || window.event;
if (e && e.keyCode == 13) { //回车键的键值为13
this.pwdLogin()
}
};
// #endif
},
methods: {
// 页面跳转,找回密码
toRetrievePwd() {
let url = '/uni_modules/uni-id-pages/pages/retrieve/retrieve'
//如果刚好用户名输入框的值为手机号码,就把它传到retrieve页面,根据该手机号找回密码
if (/^1\d{10}$/.test(this.username)) {
url += `?phoneNumber=${this.username}`
}
uni.navigateTo({
url
})
},
/**
* 密码登录
*/
pwdLogin() {
if (!this.password.length) {
this.focusPassword = true
return uni.showToast({
title: '请输入密码',
icon: 'none'
});
}
if (!this.username.length) {
this.focusUsername = true
return uni.showToast({
title: '请输入手机号/用户名/邮箱',
icon: 'none'
});
}
if (this.needCaptcha && this.captcha.length != 4) {
this.$refs.captcha.getImageCaptcha()
return uni.showToast({
title: '请输入验证码',
icon: 'none'
});
}
if (this.needAgreements && !this.agree) {
return this.$refs.agreements.popup(this.pwdLogin)
}
let data = {
"password": this.password,
"captcha": this.captcha
}
if (/^1\d{10}$/.test(this.username)) {
data.mobile = this.username
} else if (/@/.test(this.username)) {
data.email = this.username
} else {
data.username = this.username
}
uniIdCo.login(data).then(e => {
this.loginSuccess(e)
}).catch(e => {
if (e.errCode == 'uni-id-captcha-required') {
this.needCaptcha = true
} else if (this.needCaptcha) {
//登录失败,自动重新获取验证码
this.$refs.captcha.getImageCaptcha()
}
})
},
/* 前往注册 */
toRegister() {
uni.navigateTo({
url: this.config.isAdmin ? '/uni_modules/uni-id-pages/pages/register/register-admin' :
'/uni_modules/uni-id-pages/pages/register/register',
fail(e) {
console.error(e);
}
})
}
}
}
</script>
<style lang="scss" scoped>
@import "@/uni_modules/uni-id-pages/common/login-page.scss";
@media screen and (min-width: 690px) {
.uni-content {
max-height: 650px;
}
}
.forget {
font-size: 12px;
color: #8a8f8b;
}
.link-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: space-between;
margin-top: 20px;
}
.link {
font-size: 12px;
}
</style>
......@@ -191,7 +191,7 @@
@media screen and (min-width: 690px) {
.uni-content{
padding: 30px 40px;
max-height: 550px;
max-height: 650px;
}
.link-box {
/* #ifndef APP-NVUE */
......
<!-- 账号注册页 -->
<template>
<view class="uni-content">
<match-media :min-width="690">
<view class="login-logo">
<image :src="logo"></image>
</view>
<!-- 顶部文字 -->
<text class="title title-box">用户名密码注册</text>
</match-media>
<uni-forms ref="form" :value="formData" :rules="rules" validate-trigger="submit" err-show-type="toast">
<uni-forms-item name="username" required>
<uni-easyinput :inputBorder="false" :focus="focusUsername" @blur="focusUsername = false"
class="input-box" placeholder="请输入用户名" v-model="formData.username" trim="both" />
</uni-forms-item>
<uni-forms-item name="nickname">
<uni-easyinput :inputBorder="false" :focus="focusNickname" @blur="focusNickname = false" class="input-box" placeholder="请输入用户昵称" v-model="formData.nickname"
trim="both" />
</uni-forms-item>
<uni-forms-item name="password" v-model="formData.password" required>
<uni-easyinput :inputBorder="false" :focus="focusPassword" @blur="focusPassword = false"
class="input-box" maxlength="20" :placeholder="'请输入' + (config.passwordStrength == 'weak'?'6':'8') + '-16位密码'" type="password"
v-model="formData.password" trim="both" />
</uni-forms-item>
<uni-forms-item name="password2" v-model="formData.password2" required>
<uni-easyinput :inputBorder="false" :focus="focusPassword2" @blur="focusPassword2 =false"
class="input-box" placeholder="再次输入密码" maxlength="20" type="password" v-model="formData.password2"
trim="both" />
</uni-forms-item>
<uni-forms-item>
<uni-captcha ref="captcha" scene="register" v-model="formData.captcha" />
</uni-forms-item>
<uni-id-pages-agreements scope="register" ref="agreements" ></uni-id-pages-agreements>
<button class="uni-btn" type="primary" @click="submit">注册</button>
<button @click="navigateBack" class="register-back">返回</button>
<match-media :min-width="690">
<view class="link-box">
<text class="link" @click="registerByEmail">邮箱验证码注册</text>
<text class="link" @click="toLogin">已有账号?点此登录</text>
</view>
</match-media>
</uni-forms>
</view>
</template>
<script>
import rules from './validator.js';
import mixin from '@/uni_modules/uni-id-pages/common/login-page.mixin.js';
import config from '@/uni_modules/uni-id-pages/config.js'
const uniIdCo = uniCloud.importObject("uni-id-co")
export default {
mixins: [mixin],
data() {
return {
formData: {
username: "",
nickname: "",
password: "",
password2: "",
captcha: ""
},
rules,
focusUsername:false,
focusNickname:false,
focusPassword:false,
focusPassword2:false,
logo: "/static/logo.png"
}
},
onReady() {
this.$refs.form.setRules(this.rules)
},
onShow() {
// #ifdef H5
document.onkeydown = event => {
var e = event || window.event;
if (e && e.keyCode == 13) { //回车键的键值为13
this.submit()
}
};
// #endif
},
methods: {
/**
* 触发表单提交
*/
submit() {
this.$refs.form.validate().then((res) => {
if(this.formData.captcha.length != 4){
this.$refs.captcha.focusCaptchaInput = true
return uni.showToast({
title: '请输入验证码',
icon: 'none'
});
}
if (this.needAgreements && !this.agree) {
return this.$refs.agreements.popup(()=>{
this.submitForm(res)
})
}
this.submitForm(res)
}).catch((errors) => {
let key = errors[0].key
key = key.replace(key[0], key[0].toUpperCase())
console.log(key);
this['focus'+key] = true
})
},
submitForm(params) {
uniIdCo.registerUser(this.formData).then(e => {
console.log(e);
uni.navigateBack()
})
.catch(e => {
console.log(e);
console.log(e.message);
//更好的体验:登录错误,直接刷新验证码
this.$refs.captcha.getImageCaptcha()
})
},
navigateBack() {
uni.navigateBack()
},
toLogin() {
uni.navigateTo({
url: '/uni_modules/uni-id-pages/pages/login/login-withpwd'
})
},
registerByEmail() {
uni.navigateTo({
url: '/uni_modules/uni-id-pages/pages/register/register-by-email'
})
}
}
}
</script>
<style lang="scss">
@import "@/uni_modules/uni-id-pages/common/login-page.scss";
@media screen and (max-width: 690px) {
.uni-content{
margin-top: 15px;
height: 100%;
<!-- 账号注册页 -->
<template>
<view class="uni-content">
<match-media :min-width="690">
<view class="login-logo">
<image :src="logo"></image>
</view>
<!-- 顶部文字 -->
<text class="title title-box">用户名密码注册</text>
</match-media>
<uni-forms ref="form" :value="formData" :rules="rules" validate-trigger="submit" err-show-type="toast">
<uni-forms-item name="username" required>
<uni-easyinput :inputBorder="false" :focus="focusUsername" @blur="focusUsername = false"
class="input-box" placeholder="请输入用户名" v-model="formData.username" trim="both" />
</uni-forms-item>
<uni-forms-item name="nickname">
<uni-easyinput :inputBorder="false" :focus="focusNickname" @blur="focusNickname = false"
class="input-box" placeholder="请输入用户昵称" v-model="formData.nickname" trim="both" />
</uni-forms-item>
<uni-forms-item name="password" v-model="formData.password" required>
<uni-easyinput :inputBorder="false" :focus="focusPassword" @blur="focusPassword = false"
class="input-box" maxlength="20"
:placeholder="'请输入' + (config.passwordStrength == 'weak'?'6':'8') + '-16位密码'" type="password"
v-model="formData.password" trim="both" />
</uni-forms-item>
<uni-forms-item name="password2" v-model="formData.password2" required>
<uni-easyinput :inputBorder="false" :focus="focusPassword2" @blur="focusPassword2 =false"
class="input-box" placeholder="再次输入密码" maxlength="20" type="password" v-model="formData.password2"
trim="both" />
</uni-forms-item>
<uni-forms-item>
<uni-captcha ref="captcha" scene="register" v-model="formData.captcha" />
</uni-forms-item>
<uni-id-pages-agreements scope="register" ref="agreements"></uni-id-pages-agreements>
<button class="uni-btn" type="primary" @click="submit">注册</button>
<button @click="navigateBack" class="register-back">返回</button>
<match-media :min-width="690">
<view class="link-box">
<text class="link" @click="registerByEmail">邮箱验证码注册</text>
<text class="link" @click="toLogin">已有账号?点此登录</text>
</view>
</match-media>
</uni-forms>
</view>
</template>
<script>
import rules from './validator.js';
import mixin from '@/uni_modules/uni-id-pages/common/login-page.mixin.js';
import config from '@/uni_modules/uni-id-pages/config.js'
import {
store,
mutations
} from '@/uni_modules/uni-id-pages/common/store.js'
const {
loginSuccess
} = mutations
const uniIdCo = uniCloud.importObject("uni-id-co")
export default {
mixins: [mixin],
data() {
return {
formData: {
username: "",
nickname: "",
password: "",
password2: "",
captcha: ""
},
rules,
focusUsername: false,
focusNickname: false,
focusPassword: false,
focusPassword2: false,
logo: "/static/logo.png"
}
},
onReady() {
this.$refs.form.setRules(this.rules)
},
onShow() {
// #ifdef H5
document.onkeydown = event => {
var e = event || window.event;
if (e && e.keyCode == 13) { //回车键的键值为13
this.submit()
}
};
// #endif
},
methods: {
/**
* 触发表单提交
*/
submit() {
this.$refs.form.validate().then((res) => {
if (this.formData.captcha.length != 4) {
this.$refs.captcha.focusCaptchaInput = true
return uni.showToast({
title: '请输入验证码',
icon: 'none'
});
}
if (this.needAgreements && !this.agree) {
return this.$refs.agreements.popup(() => {
this.submitForm(res)
})
}
this.submitForm(res)
}).catch((errors) => {
let key = errors[0].key
key = key.replace(key[0], key[0].toUpperCase())
console.log(key);
this['focus' + key] = true
})
},
submitForm(params) {
uniIdCo.registerUser(this.formData).then(e => {
console.log(e);
loginSuccess()
})
.catch(e => {
console.log(e);
console.log(e.message);
//更好的体验:登录错误,直接刷新验证码
this.$refs.captcha.getImageCaptcha()
})
},
navigateBack() {
uni.navigateBack()
},
toLogin() {
uni.navigateTo({
url: '/uni_modules/uni-id-pages/pages/login/login-withpwd'
})
},
registerByEmail() {
uni.navigateTo({
url: '/uni_modules/uni-id-pages/pages/register/register-by-email'
})
}
}
}
</script>
<style lang="scss">
@import "@/uni_modules/uni-id-pages/common/login-page.scss";
@media screen and (max-width: 690px) {
.uni-content {
margin-top: 15px;
height: 100%;
background-color: #fff;
}
}
@media screen and (min-width: 690px) {
.uni-content{
}
}
@media screen and (min-width: 690px) {
.uni-content {
padding: 30px 40px 60px;
}
.link-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: space-between;
margin-top: 10px;
}
.link {
font-size: 12px;
}
}
.uni-content ::v-deep .uni-forms-item__label {
position: absolute;
left: -15px;
}
button {
margin-top: 15px;
}
max-height: 530px;
}
.link-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: space-between;
margin-top: 10px;
}
.link {
font-size: 12px;
}
}
.uni-content ::v-deep .uni-forms-item__label {
position: absolute;
left: -15px;
}
button {
margin-top: 15px;
}
</style>
......@@ -204,6 +204,7 @@
@media screen and (min-width: 690px) {
.uni-content{
padding: 30px 40px 40px;
max-height: 650px;
}
.link-box {
......
......@@ -228,6 +228,7 @@
@media screen and (min-width: 690px) {
.uni-content{
padding: 30px 40px 40px;
max-height: 650px;
}
.link-box {
/* #ifndef APP-NVUE */
......
......@@ -19,6 +19,10 @@
</view>
</template>
<script>
import {
store,
mutations
} from '@/uni_modules/uni-id-pages/common/store.js'
export default {
data() {
return {
......@@ -73,7 +77,7 @@
// #ifndef APP-NVUE
const eventChannel = this.getOpenerEventChannel();
// #endif
eventChannel.emit('getUserInfo')
mutations.setUserInfo(this.formData)
uni.navigateBack()
}).catch(e => {
console.log(e);
......
const db = uniCloud.database();
const usersTable = db.collection('uni-id-users')
const uniIdCo = uniCloud.importObject("uni-id-co")
export default {
data() {
return {
univerifyStyle: {
authButton: {
"title": "本机号码一键绑定", // 授权按钮文案
},
otherLoginButton: {
"title": "其他号码绑定",
}
},
userInfo: {
mobile: '',
nickname: ''
},
hasLogin: false,
hasPwd: false
}
},
async onShow() {
this.univerifyStyle.authButton.title = "本机号码一键绑定"
this.univerifyStyle.otherLoginButton.title = "其他号码绑定"
},
async onLoad() {
this.getUserInfo()
//判断当前用户是否有密码,否则就不显示密码修改功能
let res = await uniIdCo.getAccountInfo()
this.hasPwd = res.isPasswordSet
},
methods: {
login() {
uni.navigateTo({
url: '/uni_modules/uni-id-pages/pages/login/login-withoutpwd',
complete: (e) => {
console.log(e);
}
})
},
async logout() {
await uniIdCo.logout()
uni.removeStorageSync('uni_id_token');
uni.setStorageSync('uni_id_token_expired', 0)
uni.redirectTo({
url: '/uni_modules/uni-id-pages/pages/login/login-withoutpwd',
});
},
changePassword() {
uni.navigateTo({
url: '/uni_modules/uni-id-pages/pages/userinfo/change_pwd/change_pwd',
complete: (e) => {
console.log(e);
}
})
},
getUserInfo(e) {
uni.showLoading({
mask: true
});
usersTable.where("'_id' == $cloudEnv_uid").field('mobile,nickname').get().then(res => {
console.log({
res
});
this.userInfo = res.result.data[0]
console.log('this.userInfo', this.userInfo);
this.hasLogin = true
}).catch(e => {
this.userInfo = {}
this.hasLogin = false
console.log(e.message, e.errCode);
}).finally(e => {
// console.log(e);
uni.hideLoading()
})
},
bindMobile() {
// #ifdef APP-PLUS
uni.preLogin({
provider: 'univerify',
success: this.univerify(), //预登录成功
fail: (res) => { // 预登录失败
// 不显示一键登录选项(或置灰)
console.log(res)
this.bindMobileBySmsCode()
}
})
// #endif
// #ifdef MP-WEIXIN
this.$refs['bind-mobile'].open()
// #endif
// #ifdef H5
//...去用验证码绑定
this.bindMobileBySmsCode()
// #endif
},
univerify() {
uni.login({
"provider": 'univerify',
"univerifyStyle": this.univerifyStyle,
success: async e => {
console.log(e.authResult);
uniIdCo.bindMobileByUniverify(e.authResult).then(res => {
console.log(res);
this.getUserInfo()
}).catch(e => {
console.log(e);
}).finally(e => {
console.log(e);
uni.closeAuthView()
})
},
fail: (err) => {
console.log(err);
if (err.code == '30002' || err.code == '30001') {
this.bindMobileBySmsCode()
}
}
})
},
bindMobileBySmsCode() {
uni.navigateTo({
url: './bind-mobile/bind-mobile',
events: {
getUserInfo: () => {
this.getUserInfo()
}
},
complete(e) {
console.log(e);
}
})
},
setNickname(nickname) {
console.log(nickname);
if (nickname) {
usersTable.where('_id==$env.uid').update({
nickname
}).then(e => {
console.log(e);
if (e.result.updated) {
uni.showToast({
title: "更新成功",
icon: 'none'
});
this.userInfo.nickname = nickname
} else {
uni.showToast({
title: "没有改变",
icon: 'none'
});
}
})
this.$refs.dialog.close()
} else {
this.$refs.dialog.open()
}
},
deactivate() {
uni.navigateTo({
url: "/uni_modules/uni-id-pages/pages/userinfo/deactivate/deactivate"
})
}
}
}
......@@ -22,9 +22,9 @@
placeholder="请输入要设置的昵称">
</uni-popup-dialog>
</uni-popup>
<uni-id-pages-bind-mobile ref="bind-mobile-by-sms" @success="getUserInfo"></uni-id-pages-bind-mobile>
<uni-id-pages-bind-mobile ref="bind-mobile-by-sms" @success="bindMobileSuccess"></uni-id-pages-bind-mobile>
<template v-if="showLoginManage">
<button v-if="hasLogin" @click="logout">退出登录</button>
<button v-if="userInfo._id" @click="logout">退出登录</button>
<button v-else @click="login">去登录</button>
</template>
</view>
......@@ -33,8 +33,16 @@
const db = uniCloud.database();
const usersTable = db.collection('uni-id-users')
const uniIdCo = uniCloud.importObject("uni-id-co")
import common from '@/uni_modules/uni-id-pages/common/common.js';
import {
store,
mutations
} from '@/uni_modules/uni-id-pages/common/store.js'
export default {
computed: {
userInfo() {
return store.userInfo
}
},
data() {
return {
univerifyStyle: {
......@@ -45,11 +53,10 @@
"title": "其他号码绑定",
}
},
userInfo: {
mobile:'',
nickname:''
},
hasLogin: false,
// userInfo: {
// mobile:'',
// nickname:''
// },
hasPwd:false,
showLoginManage:false//通过页面传参隐藏登录&退出登录按钮
}
......@@ -62,7 +69,6 @@
if(e.showLoginManage){
this.showLoginManage = true//通过页面传参隐藏登录&退出登录按钮
}
this.getUserInfo()
//判断当前用户是否有密码,否则就不显示密码修改功能
let res = await uniIdCo.getAccountInfo()
this.hasPwd = res.isPasswordSet
......@@ -76,7 +82,12 @@
}
})
},
logout:common.logout,
logout(){
mutations.logout()
},
bindMobileSuccess(){
mutations.updateUserInfo()
},
changePassword(){
uni.navigateTo({
url: '/uni_modules/uni-id-pages/pages/userinfo/change_pwd/change_pwd',
......@@ -85,24 +96,6 @@
}
})
},
getUserInfo(e) {
uni.showLoading({
mask: true
});
usersTable.where("'_id' == $cloudEnv_uid").field('mobile,nickname,email').get().then(res => {
console.log({res});
this.userInfo = res.result.data[0]
console.log('this.userInfo', this.userInfo);
this.hasLogin = true
}).catch(e => {
this.userInfo = {}
this.hasLogin = false
console.log(e.message, e.errCode);
}).finally(e => {
// console.log(e);
uni.hideLoading()
})
},
bindMobile() {
// #ifdef APP-PLUS
uni.preLogin({
......@@ -133,7 +126,7 @@
console.log(e.authResult);
uniIdCo.bindMobileByUniverify(e.authResult).then(res => {
console.log(res);
this.getUserInfo()
mutations.updateUserInfo()
}).catch(e => {
console.log(e);
}).finally(e=>{
......@@ -151,37 +144,13 @@
},
bindMobileBySmsCode() {
uni.navigateTo({
url: './bind-mobile/bind-mobile',
events: {
getUserInfo: () => {
this.getUserInfo()
}
},
complete(e) {
console.log(e);
}
url: './bind-mobile/bind-mobile'
})
},
setNickname(nickname) {
console.log(nickname);
if (nickname) {
usersTable.where('_id==$env.uid').update({
nickname
}).then(e => {
console.log(e);
if (e.result.updated) {
uni.showToast({
title: "更新成功",
icon: 'none'
});
this.userInfo.nickname = nickname
} else {
uni.showToast({
title: "没有改变",
icon: 'none'
});
}
})
mutations.updateUserInfo({nickname})
this.$refs.dialog.close()
} else {
this.$refs.dialog.open()
......@@ -196,7 +165,8 @@
}
</script>
<style lang="scss" scoped>
@import url("/uni_modules/uni-id-pages/common/login-page.scss");
@import "@/uni_modules/uni-id-pages/common/login-page.scss";
.uni-content {
padding: 0;
......
{
"pages": [
{
"path": "uni_modules/uni-id-pages/pages/userinfo/deactivate/deactivate",
"style": {
"navigationBarTitleText": "注销账号"
}
},
{
"path": "uni_modules/uni-id-pages/pages/userinfo/userinfo",
"style": {
"navigationBarTitleText": "个人资料"
}
},
{
"path": "uni_modules/uni-id-pages/pages/userinfo/bind-mobile/bind-mobile",
"style": {
"navigationBarTitleText": "绑定手机号码"
}
},
{
"path": "uni_modules/uni-id-pages/pages/userinfo/cropImage/cropImage",
"style": {
"navigationBarTitleText": ""
}
},
{
"path": "uni_modules/uni-id-pages/pages/login/login-withoutpwd",
"style": {
"navigationBarTitleText": ""
}
},
{
"path": "uni_modules/uni-id-pages/pages/login/login-withpwd",
"style": {
"navigationBarTitleText": ""
}
},
{
"path": "uni_modules/uni-id-pages/pages/login/login-smscode",
"style": {
"navigationBarTitleText": "手机验证码登录"
}
},
{
"path": "uni_modules/uni-id-pages/pages/register/register",
"style": {
"navigationBarTitleText": "注册"
}
},
{
"path": "uni_modules/uni-id-pages/pages/register/register-by-email",
"style": {
"navigationBarTitleText": "邮箱验证码注册"
}
},
{
"path": "uni_modules/uni-id-pages/pages/retrieve/retrieve",
"style": {
"navigationBarTitleText": "重置密码"
}
},
{
"path": "uni_modules/uni-id-pages/pages/retrieve/retrieve-by-email",
"style": {
"navigationBarTitleText": "通过邮箱重置密码"
}
},
{
"path": "uni_modules/uni-id-pages/pages/common/webview/webview",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
}
,{
"path" : "uni_modules/uni-id-pages/pages/userinfo/change_pwd/change_pwd",
"style" :
{
"navigationBarTitleText": "修改密码",
"enablePullDownRefresh": false
}
}
]
}
\ No newline at end of file
const assert = require('assert')
const {
Validator
} = require('./validator')
const {
ERROR
} = require('./error')
const {
getType
} = require('./utils')
const testCaseList = [{
value: {
username: 'uname'
},
schema: {
username: 'username'
},
expected: undefined
}, {
value: {
username: '123456'
},
schema: {
username: 'username'
},
expected: {
errCode: ERROR.INVALID_USERNAME
}
}, {
value: {
username: '数字天堂'
},
schema: {
username: 'username'
},
expected: {
errCode: ERROR.INVALID_USERNAME
}
}, {
value: {
password: '123456abc'
},
schema: {
password: 'password'
}
}, {
value: {
password: '123456def'
},
schema: {
password: 'password'
},
mixin: [{
type: 'password',
handler: function (password) {
if (typeof password !== 'string' || password.length < 10) {
return {
errCode: ERROR.INVALID_PASSWORD
}
}
}
}],
expected: {
errCode: ERROR.INVALID_PASSWORD
}
}, {
value: {
numberOrString: '123456'
},
schema: {
numberOrString: 'number|string'
}
}, {
value: {
numberOrString: 123456
},
schema: {
numberOrString: 'number|string'
}
}, {
value: {
numberOrString: '123456'
},
schema: {
numberOrString: 'string|number'
}
}, {
value: {
numberOrString: 123456
},
schema: {
numberOrString: 'string|number'
}
}, {
value: {
numberOrString: ['123456']
},
schema: {
numberOrString: 'array<number|string>'
}
}, {
value: {
numberOrString: [123456]
},
schema: {
numberOrString: 'array<number|string>'
}
}, {
value: {
numberOrString: [123456, '123456']
},
schema: {
numberOrString: 'array<number|string>'
}
}, {
value: {
numberOrString: ['123456']
},
schema: {
numberOrString: 'array<string|number>'
}
}, {
value: {
numberOrString: [123456]
},
schema: {
numberOrString: 'array<string|number>'
}
}, {
value: {
numberOrString: [123456, '123456']
},
schema: {
numberOrString: 'array<string|number>'
}
}, {
value: {
numberOrString: ['123456']
},
mixin: [{
type: '1to6',
handler: function (val) {
if (val !== '123456') {
return {
errCode: ERROR.INVALID_PARAM
}
}
}
}],
schema: {
numberOrString: 'array<number|1to6>'
}
}]
function execTestCase ({
value = {},
schema = {},
mixin = [],
expected = undefined,
error = ''
} = {}) {
const validator = new Validator()
for (let i = 0; i < mixin.length; i++) {
const {
type,
handler
} = mixin[i]
validator.mixin(type, handler)
}
let validateResult,
validateError
try {
validateResult = validator.validate(value, schema)
} catch (err) {
validateError = err
}
const tag = JSON.stringify({ value, schema })
if (error) {
if (typeof error === 'string') {
assert.strictEqual(validateError.message.indexOf(error) > -1, true, `[${tag}] error message error`)
} else if (getType(error) === 'regexp') {
assert.strictEqual(error.test(validateError), true, `[${tag}] error message error`)
} else {
throw new Error(`[${tag}] invalid test case`)
}
return
}
if (expected === undefined) {
assert.strictEqual(validateResult, undefined, `[${tag}] validate result error`)
return
}
const expectedKeys = Object.keys(expected)
let passResultCheck = true
for (let i = 0; i < expectedKeys.length; i++) {
const key = expectedKeys[i]
if (expected[key] !== validateResult[key]) {
passResultCheck = false
break
}
}
assert.strictEqual(passResultCheck, true, `[${tag}] validate result error`)
}
for (let i = 0; i < testCaseList.length; i++) {
console.log(`test case: ${i}`)
execTestCase(testCaseList[i])
console.log(`test case: ${i}, pass`)
}
const {
getWeixinPlatform
} = require('../../lib/utils/weixin')
const {
getNonceStr
} = require('../../common/utils')
const {
createHash
} = require('crypto')
/**
* 获取微信公众号config参数
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#get-h5-weixin-config
* @param {object} params
* @param {string} params.url 当前页面url不带hash部分
* @returns
*/
module.exports = async function (params) {
const schema = {
url: 'string'
}
this.middleware.validate(params, schema)
const {
url
} = params
const oauthConfig = this.configUtils.getOauthConfig({
provider: 'weixin'
})
const {
appId
} = this.getClientInfo()
const weixinPlatform = getWeixinPlatform.call(this)
const getTicketRes = await this.uniOpenBridge.getTicket({
dcloudAppid: appId,
platform: weixinPlatform + '-weixin'
})
if (!getTicketRes) {
throw new Error('Wechat official account ticket not found, please referer to: https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#login-by-weixin-h5')
}
const ticket = getTicketRes.ticket
const signContent = {
jsapi_ticket: ticket,
noncestr: getNonceStr(),
timestamp: Math.floor(Date.now() / 1000),
url: url.split('#')[0]
}
const signStr = Object.keys(signContent).sort().reduce(function (str, key) {
return str + key + '=' + signContent[key] + '&'
}, '').replace(/&$/, '')
const signature = createHash('sha1').update(signStr, 'utf8').digest('hex')
return {
errCode: 0,
appId: oauthConfig.appid, // 公众号的唯一标识
timestamp: signContent.timestamp, // 生成签名的时间戳
nonceStr: signContent.noncestr, // 生成签名的随机串
signature // 签名
}
}
## 1.0.4(2022-09-21)
- 新增 支持使用阿里云固定IP获取微信公众号H5凭据 access_token、ticket,开发者需要在微信公众平台配置阿里云固定IP,[固定IP详情](https://uniapp.dcloud.net.cn/uniCloud/cf-functions.html#aliyun-eip)
## 1.0.3(2022-09-06)
- 修复 过期时间问题,容错 AccessToken 默认 fallback 逻辑,当微信服务器没有返回过期时间时设置为2小时后过期
## 1.0.2(2022-09-02)
......
{
"id": "uni-open-bridge-common",
"displayName": "uni-open-bridge-common",
"version": "1.0.3",
"version": "1.0.4",
"description": "统一接管微信等三方平台认证凭据",
"keywords": [
"uni-open-bridge-common",
......
......@@ -124,8 +124,10 @@ class Ticket extends Storage {
const responseData = await WeixinServer.GetH5TicketData(accessToken)
const duration = responseData.expires_in
const duration = responseData.expires_in || (60 * 60 * 2)
delete responseData.expires_in
delete responseData.errcode
delete responseData.errmsg
return {
value: responseData,
......
......@@ -62,7 +62,7 @@ class WeixinServer {
})
}
getAccessTokenH5() {
getH5AccessToken() {
return uniCloud.httpclient.request(WeixinServer.AccessToken_H5_Url, {
dataType: 'json',
method: 'GET',
......@@ -74,7 +74,7 @@ class WeixinServer {
})
}
getTicket(access_token) {
getH5Ticket(access_token) {
return uniCloud.httpclient.request(WeixinServer.Ticket_Url, {
dataType: 'json',
dataAsQueryString: true,
......@@ -84,6 +84,25 @@ class WeixinServer {
}
})
}
getH5AccessTokenForEip() {
return uniCloud.httpProxyForEip.postForm(WeixinServer.AccessToken_H5_Url, {
appid: this._appid,
secret: this._secret,
grant_type: "client_credential"
}, {
dataType: 'json'
})
}
getH5TicketForEip(access_token) {
return uniCloud.httpProxyForEip.postForm(WeixinServer.Ticket_Url, {
access_token
}, {
dataType: 'json',
dataAsQueryString: true
})
}
}
WeixinServer.AccessToken_Url = 'https://api.weixin.qq.com/cgi-bin/token'
......@@ -105,23 +124,27 @@ WeixinServer.GetUserEncryptKey = function(options) {
}
WeixinServer.GetH5AccessToken = function(options) {
return new WeixinServer(options).getAccessTokenH5()
return new WeixinServer(options).getH5AccessToken()
}
WeixinServer.GetH5Ticket = function(options) {
return new WeixinServer(options).getTicket(options.access_token)
return new WeixinServer(options).getH5Ticket(options.access_token)
}
////////////////////////////////////////////////////////////////
function isAliyun() {
return (uniCloud.getCloudInfos()[0].provider === 'aliyun')
}
WeixinServer.GetResponseData = function(response) {
console.log("WeixinServer::response", response)
if (response.status !== HTTP_STATUS.SUCCESS) {
throw new BridgeError(response.status, response.status)
if (!(response.status === HTTP_STATUS.SUCCESS || response.statusCodeValue === HTTP_STATUS.SUCCESS)) {
throw new BridgeError(response.status || response.statusCodeValue, response.status || response.statusCodeValue)
}
const responseData = response.data
const responseData = response.data || response.body
if (responseData.errcode !== undefined && responseData.errcode !== 0) {
throw new BridgeError(responseData.errcode, responseData.errmsg)
......@@ -146,12 +169,30 @@ WeixinServer.GetUserEncryptKeyData = async function(options) {
}
WeixinServer.GetH5AccessTokenData = async function(options) {
const response = await new WeixinServer(options).getAccessTokenH5()
const ws = new WeixinServer(options)
let response
if (isAliyun()) {
response = await ws.getH5AccessTokenForEip()
if (typeof response === 'string') {
response = JSON.parse(response)
}
} else {
response = await ws.getH5AccessToken()
}
return WeixinServer.GetResponseData(response)
}
WeixinServer.GetH5TicketData = async function(options) {
const response = await new WeixinServer(options).getTicket(options.access_token)
const ws = new WeixinServer(options)
let response
if (isAliyun()) {
response = await ws.getH5TicketForEip(options.access_token)
if (typeof response === 'string') {
response = JSON.parse(response)
}
} else {
response = await ws.getH5Ticket(options.access_token)
}
return WeixinServer.GetResponseData(response)
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册