欢迎你的到此一游,在查看的过程中有疑问可在主页添加博主咨询,也可在下方评论留言。

vue3+vite+ts+vue3-qr-reader实现移动端h5+pc端调起摄像头核销二维码

1
1、首先我们看示例图:  h5:pc:

 

 

 

1
2、我们开始做第一步就是装依赖:yarn add vue3-qr-reader 或者 npm install vue3-qr-reader  我记得装完后还需要装一个 yarn add -D sass 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
3、封装一个组件公用:组件位置你们自己定
  我写在了components/QrScanner/index  这里面我用到了 element-plus 的icon 想用的可以安装对应依赖 https://s-test.belle.cn/zh-CN/<template>
    <div>
      <QrStream
        :style="scannerStyle"
        @decode="handleDecode"
        @init="handleInit"
        @error="handleError"
      >
        <template v-if="showCloseButton">
          <div class="qr-scanner-container">
            <!-- <div class="close-view dis-center" @click="closeScanner">X</div> -->
            <el-icon @click="closeScanner" class="close-view dis-center"><CircleClose /></el-icon>
            <div class="qr-scanner">
              <div class="box">
                <div class="line"></div>
                <div class="angle"></div>
              </div>
            </div>
          </div>
        </template>
      </QrStream>
    </div>
  </template>
  
  <script setup>
  import { ref, defineExpose } from 'vue'
  import { QrStream } from 'vue3-qr-reader'
  import { CircleClose } from '@element-plus/icons-vue'
  
  const emit = defineEmits(['decode','close'])
  
  const scannerStyle = {
    position: 'fixed',
    top: 0,
    left: 0,
    width: '100vw',
    height: '100vh',
    zIndex: 9999,
  }
  
  const showCloseButton = ref(false)
  
  const qrcodeData = ref(null)
  
  const handleDecode = (data) => {
    console.log('Decoded data:', data)
    emit('decode', data)
    qrcodeData.value = data
    
  }
  
  const closeScanner = () => {
    emit('close')
  }
  
  const handleInit = async (promise) => {
    try {
      const { capabilities } = await promise
      console.log('Camera capabilities:', capabilities)
      showCloseButton.value = true
    } catch (error) {
      handleError(error)
      
    }
  }
  
  const handleError = (error) => {
    const errorMessages = {
      NotAllowedError: '您需要授予相机访问权限',
      NotFoundError: '这个设备上没有摄像头',
      NotSupportedError: '所需的安全上下文(HTTPS、本地主机)',
      NotReadableError: '相机被占用',
      OverconstrainedError: '安装摄像头不合适',
      StreamApiNotSupportedError: '此浏览器不支持流API',
      InsecureContextError: '仅允许在安全上下文中访问摄像机。使用HTTPS或本地主机,而不是HTTP。',
    }
  
    const message = errorMessages[error.name] || 'ERROR: 摄像头错误'
    message.error(message)
    console.error(message)
  }
  
  defineExpose({ qrcodeData })
  </script>
  
  <style scoped lang="scss">
  .qr-scanner-container {
    position: relative;
    width: 100%;
    height: 100%;
  
    .close-view {
        position: absolute;
        top: 20px;
        right: 20px;
        font-size: 40px;
        color: #FFFFFF;
        z-index: 1000000;
    }
  }
  
  .qr-scanner {
    background-image: linear-gradient(
        0deg,
        transparent 24%,
        rgba(32, 255, 77, 0.1) 25%,
        rgba(32, 255, 77, 0.1) 26%,
        transparent 27%,
        transparent 74%,
        rgba(32, 255, 77, 0.1) 75%,
        rgba(32, 255, 77, 0.1) 76%,
        transparent 77%,
        transparent
      ),
      linear-gradient(
        90deg,
        transparent 24%,
        rgba(32, 255, 77, 0.1) 25%,
        rgba(32, 255, 77, 0.1) 26%,
        transparent 27%,
        transparent 74%,
        rgba(32, 255, 77, 0.1) 75%,
        rgba(32, 255, 77, 0.1) 76%,
        transparent 77%,
        transparent
      );
    background-size: 3rem 3rem;
    background-position: -1rem -1rem;
    width: 100%;
    /* height: 100%; */
    height: 100vh;
    position: relative;
    ">#1110;
  
    /* */
  }
  
  .qr-scanner .box {
    width: 213px;
    height: 213px;
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    overflow: hidden;
    border: 0.1rem solid rgba(0, 255, 51, 0.2);
    /* background: url('http://resource.beige.world/imgs/gongconghao.png') no-repeat center center; */
  }
  
  .qr-scanner .line {
    height: calc(100% - 2px);
    width: 100%;
    background: linear-gradient(180deg, rgba(0, 255, 51, 0) 43%, #00ff33 211%);
    border-bottom: 3px solid #00ff33;
    transform: translateY(-100%);
    animation: radar-beam 2s infinite alternate;
    animation-timing-function: cubic-bezier(0.53, 0, 0.43, 0.99);
    animation-delay: 1.4s;
  }
  
  .qr-scanner .box:after,
  .qr-scanner .box:before,
  .qr-scanner .angle:after,
  .qr-scanner .angle:before {
    content: '';
    display: block;
    position: absolute;
    width: 3vw;
    height: 3vw;
  
    border: 0.2rem solid transparent;
  }
  
  .qr-scanner .box:after,
  .qr-scanner .box:before {
    top: 0;
    border-top-color: #00ff33;
  }
  
  .qr-scanner .angle:after,
  .qr-scanner .angle:before {
    bottom: 0;
    border-bottom-color: #00ff33;
  }
  
  .qr-scanner .box:before,
  .qr-scanner .angle:before {
    left: 0;
    border-left-color: #00ff33;
  }
  
  .qr-scanner .box:after,
  .qr-scanner .angle:after {
    right: 0;
    border-right-color: #00ff33;
  }
  
  @keyframes radar-beam {
    0% {
      transform: translateY(-100%);
    }
  
    100% {
      transform: translateY(0);
    }
  }
  </style>

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
4、显示的页面里使用:
<template>
    <QrScanner v-if="showQrCodeReader" @decode="onDecodeHandler" @close="qrReaderClose"></QrScanner>
</template>
<script setup>
import QrScanner from "@/components/QrScanner/index.vue"
import { ref, reactive, onMounted, onUnmounted, nextTick, getCurrentInstance, watchEffect } from "vue";
 
const showQrCodeReader = ref(false)
const paymentData = reactive({
  orderId: '',
  authCode: '',
  drawer: false
})
const qrcodeDetail = ref({})
 
/*
data 的值为下列地址为扫描二维码后得到的数据
 http://localhost:8000?content=p6hi1rQzu%2B956WKJ%2BomXQVxuvddBBgPdVxKvDXBiIoO9HhE%2FLdR0pyikGRrAYjMGbcraGZjravDGcAjYdDSu9Q%3D%3D
 
使用getContentFromUrl() 获取content的值
*/
const onDecodeHandler = (data) => {
  paymentData.authCode = getContentFromUrl(data)
  showQrCodeReader.value = false
   
}
const qrReaderClose = () => {
  showQrCodeReader.value = false
}
const getContentFromUrl = (url) => {
  const urlObj = new URL(url);
  const content = urlObj.searchParams.get('content');
  return content;
}
 
</script>

  

 

posted @   廖客  阅读(363)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示