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>


©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容