Files
ZhHealth/uni_modules/Sansnn-uQRCode/components/uqrcode/uqrcode.vue

486 lines
13 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="uqrcode" :style="{'width': `${size}px`, 'height': `${size}px`}">
<block v-if="!isReload">
<!-- canvas模式默认 -->
<block v-if="mode === 'canvas'">
<!-- #ifdef APP-NVUE -->
<gcanvas class="uqrcode-canvas" ref="gcanvas" :style="{'width': `${size}px`, 'height': `${size}px`}"></gcanvas>
<!-- #endif -->
<!-- #ifndef APP-NVUE -->
<canvas class="uqrcode-canvas" :id="id" :canvas-id="id" :style="{'width': `${size}px`, 'height': `${size}px`}"></canvas>
<!-- #endif -->
</block>
<!-- view模式兼容 -->
<view v-else-if="mode === 'view'" class="uqrcode-view" :style="{
'width': `${size}px`,
'height': `${size}px`,
'padding': `${margin}px`,
'background-color': backgroundColor
}">
<view class="uqrcode-view-row" v-for="(row, rowIndex) in modules.length" :key="rowIndex">
<view class="uqrcode-view-col" v-for="(col, colIndex) in modules.length" :key="colIndex" :style="{
'width': `${tileSize}px`,
'height': `${tileSize}px`,
'background-color': modules[rowIndex][colIndex] ? foregroundColor : backgroundColor
}">
</view>
</view>
</view>
</block>
<!-- 生成二维码的loading效果 -->
<!-- <view class="uqrcode-makeing" :class="{'uqrcode-make-complete': !makeing}">loading...</view> -->
<!-- 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>
</template>
<script>
/* 引入uqrcode核心js */
import uqrcode from './common/uqrcode'
/* 引入nvue所需模块 */
// #ifdef APP-NVUE
import {
enable,
WeexBridge
} from './gcanvas'
let modal = weex.requireModule("modal")
// #endif
export default {
name: 'uqrcode',
props: {
// id
id: {
type: String,
default: uuid()
},
// 生成模式
mode: {
type: String,
default: 'canvas' // canvas|view (nvue不支持canvas模式)
},
// 二维码内容
text: String,
// 二维码大小
size: {
type: Number,
default: 256
},
// 填充边距
margin: {
type: Number,
default: 0
},
// 背景色
backgroundColor: {
type: String,
default: '#FFFFFF'
},
// 前景色
foregroundColor: {
type: String,
default: '#000000'
},
// 纠错等级
errorCorrectLevel: {
type: [String, Number],
default: uqrcode.errorCorrectLevel.H
},
// 版本
typeNumber: {
type: Number,
default: -1
},
// 导出的文件类型
fileType: {
type: String,
default: 'png'
}
},
data() {
return {
canvasContext: null,
makeing: false,
delegate: null,
delegateParams: null,
tempFilePath: '',
isH5Save: false,
isReload: false
}
},
computed: {
modules() {
let options = {
...this.$props
}
if (typeof options.errorCorrectLevel === 'string') {
options.errorCorrectLevel = uqrcode.errorCorrectLevel[options.errorCorrectLevel]
}
return uqrcode.getModules(options)
},
tileSize() {
return (this.size - this.margin * 2) / this.modules.length
}
},
watch: {
/* 深度监听props任意属性一发生改变立即重绘二维码 */
$props: {
handler() {
this.reload()
},
deep: true
},
makeing(val) {
if (!val) {
if (typeof this.delegate === 'function') {
this.delegate(this.delegateParams)
}
}
}
},
mounted() {
this.$nextTick(() => {
this.make()
})
},
methods: {
reload() {
/* 重载组件 */
this.isReloadMake = true
this.isReload = true
this.$nextTick(() => {
this.isReload = false
this.$nextTick(() => {
setTimeout(() => {
this.make()
}, 150)
})
})
},
make() {
if (this.makeing) {
return
}
this.makeing = true
if (this.mode === 'canvas') {
let ctx = null
// #ifdef APP-NVUE
/* 获取元素引用 */
let gcanvas = this.$refs["gcanvas"]
/* 通过元素引用获取canvas对象 */
let canvasObj = enable(gcanvas, {
bridge: WeexBridge
})
/* 获取绘图所需的上下文目前不支持3d */
ctx = canvasObj.getContext('2d')
// #endif
// #ifndef APP-NVUE
/* 获取绘图所需的上下文 */
ctx = uni.createCanvasContext(this.id, this)
// #endif
this.canvasContext = ctx
ctx.draw() // 清空之前的画布内容
ctx.setFillStyle(this.backgroundColor)
ctx.fillRect(0, 0, this.size, this.size)
for (var row = 0; row < this.modules.length; row++) {
for (var col = 0; col < this.modules.length; col++) {
// 计算每一个小块的位置
var x = col * this.tileSize + this.margin
var y = row * this.tileSize + this.margin
var w = this.tileSize
var h = this.tileSize
var style = this.modules[row][col] ? this.foregroundColor : this.backgroundColor
ctx.setFillStyle(style)
ctx.fillRect(x, y, w, h)
}
}
ctx.draw(false, () => {
// setTimeout(() => {
this.complete()
// }, 3000)
})
} else if (this.mode === 'view') {
this.complete()
}
},
complete(e = {}) {
let basic = {
id: this.id,
text: this.text,
mode: this.mode
}
let ages = {
...basic,
...e
}
this.makeing = false
this.$emit('complete', ages)
},
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.delegate = this.toTempFilePath
this.delegateParams = callback
return
} else {
this.delegate = null
this.delegateParams = null
}
let _this = this
// #ifdef APP-NVUE
this.canvasContext.toTempFilePath(
0,
0,
_this.size * 3, // 不知道什么原因,最少要*3不然输出的图片只有一个角
_this.size * 3, // 不知道什么原因,最少要*3不然输出的图片只有一个角
_this.size,
_this.size,
_this.fileType,
1,
res => {
_this.tempFilePath = res.tempFilePath
callback.success(res)
callback.complete(res)
}
)
// #endif
// #ifndef APP-NVUE
uni.canvasToTempFilePath({
canvasId: this.id,
fileType: this.fileType,
width: this.size,
height: this.size,
success: res => {
this.tempFilePath = res.tempFilePath
callback.success(res)
},
fail: err => {
callback.fail(err)
},
complete: res => {
callback.complete(res)
}
}, this)
// #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 => {
// #ifdef H5
this.isH5Save = true
callback.success({
msg: 'H5请长按图片保存'
})
callback.complete({
msg: 'H5请长按图片保存'
})
// #endif
// #ifndef H5
uni.saveImageToPhotosAlbum({
filePath: this.tempFilePath,
success: res1 => {
callback.success({
msg: '保存成功'
})
},
fail: err1 => {
callback.fail(err1)
},
complete: res1 => {
callback.complete(res1)
}
})
// #endif
},
fail: err => {
callback.fail(err)
}
})
}
}
}
function uuid(len = 32, firstU = true, radix = null) {
let chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
let uuid = [];
radix = radix || chars.length;
if (len) {
// 如果指定uuid长度,只是取随机的字符,0|x为位运算,能去掉x的小数位,返回整数位
for (let i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix];
} else {
let r;
// rfc4122标准要求返回的uuid中,某些位为固定的字符
uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
uuid[14] = '4';
for (let i = 0; i < 36; i++) {
if (!uuid[i]) {
r = 0 | Math.random() * 16;
uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
}
}
}
// 移除第一个字符,并用u替代,因为第一个字符为数值时,该guuid不能用作id或者class
if (firstU) {
uuid.shift();
return 'u' + uuid.join('');
} else {
return uuid.join('');
}
}
</script>
<style>
.uqrcode {
position: relative;
}
.uqrcode-makeing {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
/* #ifndef APP-NVUE */
display: flex;
box-sizing: border-box;
/* #endif */
justify-content: center;
align-items: center;
background-color: #FFFFFF;
transition-property: opacity;
transition-duration: 0.25s;
opacity: 0.88;
}
.uqrcode-make-complete {
opacity: 0;
}
.uqrcode-view {
/* #ifndef APP-NVUE */
display: flex;
box-sizing: border-box;
/* #endif */
flex-direction: column;
}
.uqrcode-view-row {
/* #ifndef APP-NVUE */
display: flex;
box-sizing: border-box;
/* #endif */
flex-direction: row;
}
.uqrcode-view-col {
/* #ifndef APP-NVUE */
display: flex;
box-sizing: border-box;
/* #endif */
}
/* #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>