123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- <template>
- <view class="u-qrcode" :style="[{
- width: $u.addUnit(size),
- height: $u.addUnit(size)
- }]" @longpress="handleLongpress">
- <u-canvas
- ref="canvasRef"
- :width="size"
- :height="size"
- :customStyle="mode === 'image' ? 'position: absolute; left: -9999px; top: -9999px;' : ''"
- />
- <view class="u-qrcode__image-wrapper" v-if="mode === 'image'">
- <image :src="imageUrl" class="u-qrcode__image" mode="widthFix"/>
- </view>
- <view class="u-qrcode__mask" v-if="status === 'loading'">
- <slot name="loading">
- <u-loading-icon mode="semicircle"></u-loading-icon>
- </slot>
- </view>
- <view class="u-qrcode__mask" v-if="status === 'expired'">
- <slot name="expired">
- <text class="u-qrcode__expired-message">{{ expiredText }}</text>
- <view class="u-qrcode__expired-btn" @click="handleRefresh">
- <u-icon name="reload" size="20" color="primary" :label="refreshText" labelColor="primary"></u-icon>
- </view>
- </slot>
- </view>
- <view class="u-qrcode__mask" v-if="status === 'scanned'">
- <slot name="scanned">
- <u-icon name="checkmark-circle-fill" size="20" color="primary" :label="scannedText" labelColor="primary"></u-icon>
- </slot>
- </view>
-
- </view>
- </template>
- <script>
- import props from './props.js';
- import mixin from '../../libs/mixin/mixin'
- import mpMixin from '../../libs/mixin/mpMixin';
- import QRCode from '../../libs/util/qrcode.js';
- /**
- * qrcode 二维码
- * @description 二维码生成
- * @tutorial https://uview.d3u.cn/components/qrcode.html
- * @property {String} background 背景色
- * @property {String} foreground 前景色
- * @property {String} pdground 定位角点颜色
- * @property {String} level 容错级别
- * @property {String} value 二维码内容 (start为true时必填 )
- * @property {String} expiredText 过期文本
- * @property {String} scannedText 扫描文本
- * @property {String} refreshText 刷新文本
- * @property {String | Number} size 二维码尺寸
- * @property {String} icon 二维码图标
- * @property {Number} iconSize 二维码图标大小
- * @property {String} status 状态 expired,scanned,loading
- *
- * @example <u-qrcode ref="qrcode" size="200px" value="https://uview.d3u.cn"></u-qrcode>
- */
- export default {
- name: 'u-qrcode',
- mixins: [mpMixin, mixin, props],
- data() {
- return {
- imageUrl: '',
- };
- },
- watch: {
- value: {
- handler(newVal) {
- if(newVal){
- this.remake();
- }
- }
- },
- size: {
- handler(newVal) {
- if(newVal && newVal !== this.size){
- this.remake();
- }
- }
- }
- },
- mounted() {
- this.make();
- },
- // #ifdef VUE3
- emits: ["change", "refresh","onLongpress","error"],
- // #endif
- methods: {
- async make() {
- await this.$nextTick();
- const { canvas } = await this.$refs.canvasRef.getCanvasContext();
- new QRCode({
- canvas: canvas,
- text: this.value,
- size: this.size,
- background: this.background,
- foreground: this.foreground,
- pdground: this.pdground,
- correctLevel: this.level,
- icon: this.icon,
- iconSize: this.iconSize,
- callback: () => {
- if(this.mode === 'image') {
- this.getTempFile((tempFilePath)=>{
- this.imageUrl = tempFilePath;
- })
- }
- }
- });
- },
- getTempFile(callback) {
- this.$refs.canvasRef.canvasToTempFilePath({
- width: this.size,
- height: this.size,
- fileType: 'png',
- quality: 1,
- }).then((tempFilePath) => {
- callback(tempFilePath);
- }).catch((error) => {
- this.$emit('error', error);
- });
- },
- remake() {
- this.make();
- this.$emit('change');
- },
- handleRefresh() {
- this.$emit('refresh');
- },
- handleLongpress() {
- this.getTempFile((tempFilePath)=>{
- this.$emit('onLongpress', tempFilePath);
- })
- }
- }
- };
- </script>
- <style lang="scss" scoped>
- @import "../../libs/css/components.scss";
- .u-qrcode{
- position: relative;
-
- &__image {
- width: 100%;
- height: 100%;
- &-wrapper{
- width: 100%;
- height: 100%;
- }
- }
- &__mask{
- @include flex(row);
- flex-direction: column;
- position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- z-index: 10;
- justify-content: center;
- align-items: center;
- background: rgba(255, 255, 255, 0.9);
- }
- &__expired-message {
- font-size: 15px;
- font-weight: 800;
- color: #333;
- }
- &__expired-btn {
- @include flex(row);
- align-items: center;
- justify-content: center;
- margin-top: 5px;
- }
- }
- </style>
|