index.vue 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. <template>
  2. <view class="custom-scan-container">
  3. <!-- 扫码区域 -->
  4. <view id="barcodeView" class="barcode-view">
  5. <!-- 扫码框和动画效果 -->
  6. <view class="scan-frame">
  7. <view class="scan-line-animation"></view>
  8. <view class="corner top-left"></view>
  9. <view class="corner top-right"></view>
  10. <view class="corner bottom-left"></view>
  11. <view class="corner bottom-right"></view>
  12. </view>
  13. </view>
  14. <!-- 控制面板 -->
  15. <view class="control-panel">
  16. <button class="control-btn" @tap="toggleFlash">
  17. <text class="icon">&#128261;</text>
  18. <text>{{ flashOn ? '关闭闪光灯' : '打开闪光灯' }}</text>
  19. </button>
  20. <button class="control-btn" @tap="switchCamera">
  21. <text class="icon">&#128247;</text>
  22. <text>切换摄像头</text>
  23. </button>
  24. <button class="control-btn" @tap="stopScan">
  25. <text class="icon">&#10006;</text>
  26. <text>停止扫码</text>
  27. </button>
  28. </view>
  29. <!-- 结果展示 -->
  30. <view v-if="scanResult" class="result-panel">
  31. <text class="result-title">扫码结果:</text>
  32. <text class="result-content">{{ scanResult }}</text>
  33. </view>
  34. </view>
  35. </template>
  36. <script>
  37. export default {
  38. data() {
  39. return {
  40. barcodeInstance: null,
  41. flashOn: false,
  42. scanResult: '',
  43. isScanning: false
  44. }
  45. },
  46. onLoad() {
  47. // 页面加载时初始化扫码
  48. this.initBarcodeScan();
  49. },
  50. onUnload() {
  51. // 页面卸载时释放资源
  52. this.stopScan();
  53. },
  54. methods: {
  55. // 初始化扫码功能
  56. initBarcodeScan() {
  57. // 判断运行环境
  58. if (plus.os.name === 'iOS' || plus.os.name === 'Android') {
  59. this.initAppBarcode();
  60. } else {
  61. this.initH5Barcode();
  62. }
  63. },
  64. // App端初始化
  65. initAppBarcode() {
  66. const currentWebview = plus.webview.currentWebview();
  67. this.barcodeInstance = plus.barcode.create('barcode', [
  68. plus.barcode.QR,
  69. plus.barcode.EAN8,
  70. plus.barcode.EAN13,
  71. plus.barcode.CODE128
  72. ], {
  73. top: '0px',
  74. left: '0px',
  75. width: '100%',
  76. height: '70%',
  77. position: 'static',
  78. frameColor: '#00FF00',
  79. scanbarColor: '#00FF00'
  80. });
  81. // 设置扫码回调
  82. this.barcodeInstance.onmarked = (type, result) => {
  83. this.handleScanSuccess(type, result);
  84. };
  85. // 开始扫码
  86. this.barcodeInstance.start();
  87. this.isScanning = true;
  88. currentWebview.append(this.barcodeInstance);
  89. },
  90. // H5端初始化
  91. initH5Barcode() {
  92. // 使用之前提到的ZXing.js方案
  93. this.startH5Scan();
  94. },
  95. // 处理扫码成功
  96. handleScanSuccess(type, result) {
  97. this.scanResult = result;
  98. console.log(`扫码类型:${type},结果:${result}`);
  99. // 显示成功提示
  100. uni.showToast({
  101. title: '扫码成功',
  102. icon: 'success'
  103. });
  104. // 可选:震动反馈
  105. if (plus.os.name === 'iOS' || plus.os.name === 'Android') {
  106. plus.vibrate.vibrate(200);
  107. }
  108. // 触发自定义事件
  109. this.$emit('scanSuccess', { type, result });
  110. },
  111. // 切换闪光灯
  112. toggleFlash() {
  113. if (this.barcodeInstance) {
  114. this.flashOn = !this.flashOn;
  115. this.barcodeInstance.setFlash(this.flashOn);
  116. }
  117. },
  118. // 切换摄像头
  119. switchCamera() {
  120. if (this.barcodeInstance) {
  121. this.barcodeInstance.switchCamera();
  122. }
  123. },
  124. // 停止扫码
  125. stopScan() {
  126. if (this.barcodeInstance) {
  127. this.barcodeInstance.cancel();
  128. this.barcodeInstance.close();
  129. this.isScanning = false;
  130. }
  131. },
  132. // 重新开始扫码
  133. restartScan() {
  134. this.stopScan();
  135. setTimeout(() => {
  136. this.initBarcodeScan();
  137. }, 500);
  138. }
  139. }
  140. }
  141. </script>
  142. <style scoped>
  143. .custom-scan-container {
  144. height: 100vh;
  145. background: #000;
  146. display: flex;
  147. flex-direction: column;
  148. }
  149. .barcode-view {
  150. flex: 1;
  151. position: relative;
  152. background: transparent;
  153. }
  154. .scan-frame {
  155. position: absolute;
  156. top: 50%;
  157. left: 50%;
  158. transform: translate(-50%, -50%);
  159. width: 250px;
  160. height: 250px;
  161. border: 2px solid rgba(255, 255, 255, 0.8);
  162. }
  163. .scan-line-animation {
  164. position: absolute;
  165. width: 100%;
  166. height: 2px;
  167. background: linear-gradient(90deg, transparent, #00FF00, transparent);
  168. animation: scanLine 2s infinite linear;
  169. }
  170. @keyframes scanLine {
  171. 0% { top: 0; opacity: 0; }
  172. 50% { opacity: 1; }
  173. 100% { top: 100%; opacity: 0; }
  174. }
  175. .corner {
  176. position: absolute;
  177. width: 20px;
  178. height: 20px;
  179. border-color: #00FF00;
  180. border-style: solid;
  181. }
  182. .top-left {
  183. top: -2px;
  184. left: -2px;
  185. border-width: 2px 0 0 2px;
  186. }
  187. /* 其他角样式类似 */
  188. .control-panel {
  189. padding: 20px;
  190. background: rgba(0, 0, 0, 0.8);
  191. display: flex;
  192. justify-content: space-around;
  193. }
  194. .control-btn {
  195. background: rgba(255, 255, 255, 0.1);
  196. color: white;
  197. border: none;
  198. padding: 10px 15px;
  199. border-radius: 20px;
  200. display: flex;
  201. align-items: center;
  202. gap: 5px;
  203. }
  204. .result-panel {
  205. padding: 15px;
  206. background: rgba(255, 255, 255, 0.9);
  207. border-radius: 10px;
  208. margin: 10px;
  209. }
  210. </style>