Files

537 lines
15 KiB
Vue
Raw Permalink 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="u-qrcode"
:id="rootId"
:style="{
width: useRootHeightAndWidth ? '100%' : 'auto',
height: useRootHeightAndWidth ? '100%' : 'auto',
}"
@longpress="longpress">
<view class="u-qrcode__content" @click="preview">
<!-- #ifndef APP-NVUE || APP-VUE -->
<canvas
class="u-qrcode__canvas"
:id="cid"
:canvas-id="cid"
type="2d"
:style="{ width: sizeLocal + unit, height: sizeLocal + unit }" />
<!-- #endif -->
<!-- #ifdef APP-VUE -->
<canvas
class="u-qrcode__canvas"
:id="cid"
:canvas-id="cid"
:style="{ width: sizeLocal + unit, height: sizeLocal + unit }" />
<!-- #endif -->
<!-- #ifdef APP-NVUE -->
<web-view v-if="icon != ''" ref="web" src="/static/app-plus/up-canvas/local.html"
:style="'width:' + sizeLocal + 'px;height:' + sizeLocal + 'px'"
@onPostMessage="_onMessage" />
<gcanvas v-else class="u-qrcode__canvas" ref="gcanvess"
:style="{ width: sizeLocal + unit, height: sizeLocal + unit }">
</gcanvas>
<!-- #endif -->
<view v-if="showLoading && loading" class="u-qrcode__loading"
:style="{ width: sizeLocal + unit, height: sizeLocal + unit }">
<up-loading-icon vertical :text="loadingText" textSize="14px"></up-loading-icon>
</view>
</view>
</view>
</template>
<script>
import QRCode from "./qrcode.js"
// #ifdef APP-NVUE
// https://github.com/dcloudio/NvueCanvasDemo/blob/master/README.md
import {
enable,
WeexBridge,
Image as GImage
} from '../../libs/util/gcanvas/index.js';
// #endif
let qrcode
export default {
name: "u-qrcode",
props: {
cid: {
type: String,
default: () => `u-qrcode-canvas${Math.floor(Math.random() * 1000000)}`
},
size: {
type: Number,
default: 200
},
unit: {
type: String,
default: 'px'
},
show: {
type: Boolean,
default: true
},
val: {
type: String,
default: ''
},
background: {
type: String,
default: '#ffffff'
},
foreground: {
type: String,
default: '#000000'
},
pdground: {
type: String,
default: '#000000'
},
icon: {
type: String,
default: ''
},
iconSize: {
type: Number,
default: 40
},
lv: {
type: Number,
default: 3
},
onval: {
type: Boolean,
default: true
},
loadMake: {
type: Boolean,
default: true
},
usingComponents: {
type: Boolean,
default: true
},
showLoading: {
type: Boolean,
default: true
},
loadingText: {
type: String,
default: '生成中'
},
allowPreview: {
type: Boolean,
default: false
},
// 是否使用根节点宽高
useRootHeightAndWidth: {
type: Boolean,
default: () => false
},
},
emits: ['result', 'longpressCallback'],
data() {
return {
loading: false,
result: '',
popupShow: false,
list: [
{
name: '保存二维码',
}
],
rootId: `rootId${Number(Math.random() * 100).toFixed(0)}`,
ganvas: null,
canvasObj: {},
sizeLocal: this.size,
ctx: null, // ctx 在new Qrcode 时js文件内部设置
canvas: null, // ctx 在new Qrcode 时js文件内部设置
_ready: false
}
},
async mounted(){
// 如果使用根节点的宽高 则 重新设置 size
if(this.useRootHeightAndWidth){
await this.setNewSize()
}
this.canvas = await this.getCanvasNode(this.cid)
// #ifdef APP-NVUE
this.isNvue = true
/*获取绘图所需的上下文目前不支持3d*/
this.ctx = this.canvas.getContext('2d')
// #endif
// #ifndef APP-NVUE
this.ctx = this.getContext()
// #endif
if (this.loadMake) {
if (!this._empty(this.val)) {
setTimeout(() => {
setTimeout(()=>{
this._makeCode()
})
}, 0);
}
}
},
methods: {
_onMessage(e) {
// console.log('post message', e)
const message = e.detail.data[0]
switch (message.action) {
// web-view 初始化完毕
case 'onJSBridgeReady':
this._ready = true
this.$refs.web.evalJs('setContent('+JSON.stringify(this.$props) +')')
break
// qrcodeOk
case 'qrcodeOk':
this._result(message.imageData)
// this.$emit('load')
break
}
},
_makeCode() {
let that = this
if (!this._empty(this.val)) {
// #ifndef APP-NVUE
this.loading = true
// #endif
// nvue下时因为gcanvas的GImage不生效因此icon模式会采用webview
if ((this.icon == '' && that.isNvue) || !that.isNvue) {
qrcode = new QRCode({
vuectx: that, // 上下文环境
canvasId: that.cid, // canvas-id
canvas: that.canvas,
ctx: that.ctx,
isNvue: that.isNvue,
usingComponents: that.usingComponents, // 是否是自定义组件
showLoading: false, // 是否显示loading
loadingText: that.loadingText, // loading文字
text: that.val, // 生成内容
size: that.sizeLocal, // 二维码大小
background: that.background, // 背景色
foreground: that.foreground, // 前景色
pdground: that.pdground, // 定位角点颜色
correctLevel: that.lv, // 容错级别
image: that.icon, // 二维码图标
imageSize: that.iconSize,// 二维码图标大小
cbResult: function (res) { // 生成二维码的回调
that._result(res)
},
});
}
} else {
uni.showToast({
title: '二维码内容不能为空',
icon: 'none',
duration: 2000
});
}
},
_clearCode() {
this._result('')
qrcode.clear()
},
_saveCode() {
let that = this;
if (this.result != "") {
uni.saveImageToPhotosAlbum({
filePath: that.result,
success: function () {
uni.showToast({
title: '二维码保存成功',
icon: 'success',
duration: 2000
});
}
});
} else {
this.toTempFilePath({
success: res => {
that.result = res.tempFilePath
uni.saveImageToPhotosAlbum({
filePath: that.result,
success: function () {
uni.showToast({
title: '二维码保存成功',
icon: 'success',
duration: 2000
});
}
});
},
fail: err => {
}
})
}
},
preview(e) {
// 预览图片
// console.log(this.result)
if (this.allowPreview) {
uni.previewImage({
urls: [this.result],
longPressActions: {
itemList: ['保存二维码图片'],
success: function(data) {
// console.log('选中了第' + (data.tapIndex + 1) + '个按钮,第' + (data.index + 1) + '张图片');
switch (data.tapIndex) {
case 0:
that._saveCode();
break;
}
},
fail: function(err) {
console.log(err.errMsg);
}
}
});
}
this.$emit('preview', {
url: this.result
}, e)
},
async toTempFilePath({success, fail}) {
if (this.ct) {
this.ctx.toTempFilePath(
0,
0,
this.sizeLocal,
this.sizeLocal,
this.sizeLocal,
this.sizeLocal,
"",
1,
res => {
success(res)
}
);
}
else {
// #ifdef H5
success({
tempFilePath: this.ctx.canvas.toDataURL("image/png", 1)
})
// #endif
// #ifndef H5
uni.canvasToTempFilePath(
{
canvasId: this.cid,
success :res => {
success(res)
},
fail: fail
},
this)
// #endif
}
},
async longpress() {
this.toTempFilePath({
success: res => {
this.$emit('longpressCallback', res.tempFilePath)
},
fail: err => {
}
})
},
/**
* 使用根节点宽高 设置新的size
* @return {Promise<void>}
*/
async setNewSize(){
const rootNode = await this.getCanvasNode(this.rootId, false);
const { width , height } = rootNode;
// 将最短的设置为二维码 的size
if(width > height){
this.sizeLocal = height
}
else{
this.sizeLocal = width
}
},
/**
* 获取节点
* @param id 节点id
* @param isCanvas 是否为Canvas节点
* @return {Promise<unknown>}
*/
async getCanvasNode(id, isCanvas = true) {
return new Promise((resolve, reject) => {
try {
// #ifdef APP-NVUE
setTimeout(() => {
/*获取元素引用*/
this.ganvas = this.$refs["gcanvess"]
/*通过元素引用获取canvas对象*/
let canvasNode = enable(this.ganvas, {
bridge: WeexBridge
})
resolve(canvasNode)
}, 200)
// #endif
// #ifndef APP-NVUE
const query = uni.createSelectorQuery().in(this);
query.select(`#${id}`)
.fields({
node: true,
size: true
})
.exec((res) => {
if (isCanvas) {
resolve(res[0].node)
} else {
resolve(res[0])
}
})
// #endif
} catch (e) {
console.error("获取节点失败", e)
}
})
},
getContext() {
// #ifdef APP-VUE
return uni.createCanvasContext(this.cid, this);
// #endif
// #ifndef APP-VUE
return this.canvas.getContext('2d');
// #endif
},
drawImage(url, x, y, w, h) {
try {
let img = {}
// #ifdef APP-NVUE
img = new GImage();
// #endif
// #ifdef H5
// APP下不支持会一直卡住
img = new Image();
// #endif
// #ifdef MP
// 小程序2d
// https://developers.weixin.qq.com/miniprogram/dev/api/canvas/Canvas.createImage.html
img = canvas.createImage();
// #endif
// #ifdef APP-NVUE
let that = this
console.log(img)
img.onload = function(){
if (process.env.NODE_ENV === 'development') {
console.log('drawImage绘制2...')
}
that.cxt.drawImage(img, x, y, w, h);
}
// #endif
// #ifdef H5 || MP
img.onload = () => {
this.ctx.drawImage(img, x, y, w, h);
};
// #endif
img.src = url;
// #ifdef APP-VUE
this.ctx.drawImage(url, x, y, w, h);
// #endif
} catch (error) {
console.log('drawImage绘制出错', error)
}
},
selectClick(index) {
switch (index) {
case 0:
alert('保存二维码')
this._saveCode();
break;
}
},
_result(res) {
this.loading = false;
this.result = res;
this.$emit('result', res);
},
_empty(v) {
let tp = typeof v,
rt = false;
if (tp == "number" && String(v) == "") {
rt = true
} else if (tp == "undefined") {
rt = true
} else if (tp == "object") {
if (JSON.stringify(v) == "{}" || JSON.stringify(v) == "[]" || v == null) rt = true
} else if (tp == "string") {
if (v == "" || v == "undefined" || v == "null" || v == "{}" || v == "[]") rt = true
} else if (tp == "function") {
rt = false
}
return rt
},
},
watch: {
size: function (n, o) {
if (n != o && !this._empty(n)) {
this.cSize = n
if (!this._empty(this.val)) {
setTimeout(() => {
this._makeCode()
}, 100);
}
}
},
val: function (n, o) {
if (this.onval) {
if (n != o && !this._empty(n)) {
setTimeout(() => {
this._makeCode()
}, 0);
}
}
}
},
computed: {
}
}
</script>
<style lang="scss" scoped>
.u-qrcode {
&__loading {
display: flex;
justify-content: center;
align-items: center;
background-color: #f7f7f7;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
/* #ifdef MP-TOUTIAO */
/**字节小程序在编译时会出现一个 [hidde]:{ display: none !important; } 这个样式
* 会导致canvas 隐藏掉 没有找到具体原因先这样处理
*/
&__canvas {
display: block !important;
}
/* #endif */
&__content {
position: relative;
&__canvas {
position: fixed;
top: -99999rpx;
left: -99999rpx;
z-index: -99999;
}
}
}
</style>