uni-app中开发app端及微信小程序端自定义扫码

使用uniapp的app-nvue页面并设置独立路由

因为在app端自定义组件brcode只支持app-nvue,如果页面中用的是app-nvue,可将其设为easycom组件,设为组件在传入prop时会更加的友好。
若使用的是app-nvue页面可使用uni.$emit进行页面通信或者使用uni.navigateTo的eventChannel进行页面通信,不过需要注意的是eventChannel在app-nvue中是不支持的,可使用条件编译,app端使用vuex。

微信小程序端

使用uni-app组件 camera https://uniapp.dcloud.io/component/camera

app端

使用uni-app组件 Barcode https://uniapp.dcloud.io/component/barcode

代码示例

<template>
    <view>
        <!-- #ifdef MP-WEIXIN -->
        <view>
            <u-sticky>
                <view v-if="showCamera">
                    <camera
                        device-position="back"
                        mode="scanCode"
                        flash="off"
                        @error="cameraError"
                        class="cam-container"
                        @scancode="scancode"
                    ></camera>
                </view>
                 <u-alert-tips v-if="showTips" type="warning" :title="tips" class="u-m-b-10">
                </u-alert-tips>
                <u-alert-tips v-if="showResult" type="primary" :title="scanResult" class="u-m-b-10">
                </u-alert-tips>
            </u-sticky>
           
            <!-- <button type="primary" @click="takePhoto">拍照</button> -->
            <uni-list class="content" :border="false">
                <uni-list-item
                    v-for="(codeItem, index) in qrCodeList"
                    :key="index"
                    class="codeList"
                    :title="codeItem.cntrNum"
                    :note="codeItem.cntrTypeName"
                >
                    <view slot="footer">
                        <icon v-if="showClose" type="cancel" size="26" @click="deleteQrCode(index)"/>
                    </view>
                </uni-list-item>
            </uni-list>
            <!-- <image mode="widthFix" :src="src" /> -->
        </view>
        <!-- #endif -->

        <!-- app端 -->
        <!-- #ifdef APP-PLUS -->
        <view>
            <app-scan :showTips="showTips" :showResult="showResult" :showCamera="showCamera" :tips="tips" :scanResult="scanResult"></app-scan>
        </view>
        <!-- #endif -->

    </view>
</template>

<script>
    /**
     * @description 载具二维码扫描组件  因目前需要扫描页面均为vue页面  未来可重构为nvue页面
     * @eventProp {Array} targetQrcodeList 需扫码列表
     * @eventProp {Array} initQrcodeList 初始载具码
     * @eventProp {number} index 回调索引
     * @eventProp {bool} showTips 显示tips
     * @eventProp {bool} showResult 显示扫码结果
     * @eventProp {bool} showCamera 显示扫码框
     * @eventProp {bool} showClose 可删除码
     */
    import appScan from './app-scan.nvue';
    import { arrayGroupBy } from '@/common/util/common.js';

    export default {
        name: 'Scan',
        components: {
            'app-scan': appScan,
        },
        data() {
            return {
                qrCodeList: [],
                targetQrcodeList: [],
                eventChannel: {},
                index: '',
                showTips: false,
                showCamera: false,
                showResult: false,
                showClose: true
            };
        },
        computed: {
            // 显示的tips 需要扫码的载具
            tips() {
                let result = '可扫码项:';
                const groupList = arrayGroupBy(this.targetQrcodeList,qitem=> {
                    return qitem.cntrTypeId;
                });
                groupList.forEach((gItem) => {
                    if (gItem.length) {
                        result += `${gItem[0].cntrTypeName} x ${gItem.length};`;
                    }
                });
                return result;
            },
            // 扫码结果提示
            scanResult() {
                const groupList = arrayGroupBy(this.qrCodeList,qitem=> {
                    return qitem.cntrTypeId;
                });
                let result = '已扫:';
                groupList.forEach((gItem) => {
                    if (gItem.length) {
                        result += `${gItem[0].cntrTypeName} x /${gItem.length};`;
                    }
                });
                return result;
            },
        },
        onLoad(option) {
            // #ifdef APP-PLUS
                const data = getApp().vuex_scan.params || {};
                const { targetQrcodeList = [], initQrcodeList = [], includeList, index = '', showTips = true, showCamera = true, showResult = true, showClose = true } = data;
                this.targetQrcodeList = targetQrcodeList;
                this.qrCodeList = initQrcodeList;
                this.showClose = showClose;
                this.index = index;
                this.showTips = showTips;
                this.showCamera = showCamera;
                this.showResult = showResult;
                this.showClose = showClose;
            // #endif


            // #ifndef APP-PLUS
            // 非app端
            this.eventChannel = this.getOpenerEventChannel();
            const _this = this;
            // 监听acceptDataFromOpenerPage事件,获取上一页面通过eventChannel传送到当前页面的数据
            this.eventChannel.on('acceptDataFromOpenerPage', function (data) {
                const { targetQrcodeList = [], initQrcodeList = [], index = '', showTips = true, showCamera = true, showResult = true, showClose = true } = data;
                _this.targetQrcodeList = targetQrcodeList;
                _this.qrCodeList = initQrcodeList;
                _this.index = index;
                _this.showTips = showTips;
                _this.showCamera = showCamera;
                _this.showResult = showResult;
                _this.showClose = showClose;
            });
            // #endif
        },
        onUnload() {
            this.eventChannel.off('acceptDataFromOpenerPage');
        },
        methods: {
            scancode(scanRes) {
                const { detail } = scanRes;
                try {

                    // 二维码内容 可随实际情况调整
                    const result = JSON.parse(detail.result);

                    // 判断二维码是否为目标列表内
                    if(this.targetQrcodeList && this.targetQrcodeList.length) {
                        const isTargetCode = this.targetQrcodeList.some(tItem=> {
                            return tItem.cntrNum === result.cntrNum;
                        });
                        if(!isTargetCode) {
                            this.$u.toast('扫描的二维码不在需扫码项内~');
                            return;
                        }
                    }
                    // 判断是否已扫过
                    const isInclude = this.qrCodeList.findIndex((codeItem) => {
                        return codeItem.cntrNum === result.cntrNum;
                    });

                    if (
                        !(isInclude !== -1) &&
                        (detail.type === 'QR_CODE' || detail.type === 'qrcode')
                    ) {
                        if (result) {
                            this.qrCodeList.push(result);
                        }
                    } else if (isInclude !== -1) {
                        this.$u.toast('二维码已添加~');
                    } else {
                        this.$u.toast('错误码~');
                    }
                } catch (error) {
                    this.$u.toast('扫描二维码错误~');
                }
            },
            deleteQrCode(index) {
                this.qrCodeList.splice(index, 1);
            },
            cameraError(e) {
                console.log(e);
            },
            // 根据id获取已扫二维码
            getCntrNumByid(id) {
                return this.qrCodeList.filter((item) => {
                    return item.cntrTypeId === id;
                });
            },
            buttonClick(options) {
                if (options.content.type === 'back') {
                    // 返回按钮
                    // this.$emit('onClose');
                    this.eventChannel.emit('onCencel');
                    uni.navigateBack();
                } else if (options.content.type === 'ok') {
                    // 确认按钮
                    this.eventChannel.emit('scanOk', {
                        result: this.qrCodeList,
                        index: this.index,
                    });
                    uni.navigateBack();
                }
            },
        },
    };
</script>

<style>
    .cam-container {
        width: 100%;
        height: 300px;
        margin-bottom: 10rpx;
    }
</style>


  • app-scan.nvue
<template>
    <view>
        <view class="camera-cont">
            <barcode
                id="1"
                class="barcode"
                ref="barcode"
                background="rgb(0,0,0)"
                frameColor="#1C86EE"
                scanbarColor="#1C86EE"
                @marked="success1"
                @error="fail1"
                v-if="showCamera" 
            ></barcode>
            <view v-if="showTips">
                <text class="tips target">{{tips}}</text>
            </view>
            <view v-if="showResult">
                <text class="tips result">{{scanResult}}</text>
            </view>

        </view>
        <!-- <button class="btn" @click="toStart">{{tips}}</button>
        <button class="btn" @click="tocancel">取消扫码识别</button>
        <button class="btn" @click="toFlash">开启闪光灯</button>
        <button class="btn" @click="toscan">预览</button> -->
    </view>
</template>

<script>
    export default {
        mounted() {
            this.$refs.barcode.start({
                conserve: false,
                sound: 'default',
                vibrate: false,
            });
        },
        props: {
            showTips: {
                type: Boolean,
                default: true,
            },
            showCamera: {
                type: Boolean,
                default: true,
            },
            showResult: {
                type: Boolean,
                default: true,
            },
            tips: {
                type: String,
                default: () => {
                    return '';
                },
            },
            scanResult: {
                type: String,
                default: () => {
                    return '';
                },
            },
        },
        data() {
            return {};
        },

        methods: {
            success1(e) {
                console.log('success1:' + JSON.stringify(e));
            },
            fail1(e) {
                console.log('fail1:' + JSON.stringify(e));
            },
            toStart: function () {
                this.$refs.barcode.start({
                    conserve: false,
                    sound: 'default',
                    vibrate: false,
                });
            },
            tocancel: function () {
                this.$refs.barcode.cancel();
            },
            toFlash: function () {
                this.$refs.barcode.setFlash(true);
            },

            toscan: function () {
                console.log('scan:');
                const barcodeModule = uni.requireNativePlugin('barcodeScan');
                barcodeModule.scan('/static/barcode1.png', (e) => {
                    console.log('scan_error:' + JSON.stringify(e));
                });
            },
        },
    };
</script>

<style>
    .barcode {
        width: 750rpx;
        height: 500rpx;
        background-color: #808080;
    }

    .btn {
        top: 20rpx;
        width: 730rpx;
        margin-left: 10rpx;
        margin-top: 10rpx;
        background-color: #458b00;
        border-radius: 10rpx;
    }
    .camera-cont {
        width: 750rpx;
        height: 650rpx;
    }
    .tips {
        font-size: 28rpx;
        /* color: #ff9900; */
        display: flex;
        align-items: center;
        padding: 16rpx 30rpx;
        border-radius: 8rpx;
        transition: all 0.3s linear;
        border: 1px solid #fff;
        margin: 5rpx 0;
    }
    .target {
        border-color: #fcbd71;
        background-color: #fdf6ec;
    }
    .result {
        border-color: #a0cfff;
        background-color: #ecf5ff;
    }
</style>


©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容