likes
comments
collection
share

微信小程序内嵌h5实现扫码功能

作者站长头像
站长
· 阅读数 2

前言

需求描述:微信小程序通过webview内嵌一个h5应用,h5应用中有一个扫码功能。

技术方案:通过调用微信小程序原生扫码功能实现。

具体步骤:在h5中点击扫码按钮,跳转到微信小程序的扫码页面,进入之后会立即扫码,拿到扫码结果后,跳转到小程序定义好的webview页面,在该页面跳转h5。

实现

微信小程序使用taro+vue3来实现。

小程序嵌入h5

在小程序中创建一个webview页面,通过设置web-view容器的src地址为h5地址,加载h5页面,这个容器会自动铺满整个小程序。

微信小程序webview文档

在小程序中创建一个扫码页面webview/index

核心代码:

<template>
  <view class="webview-container">
    <web-view
      v-if="src"
      :src="src"
      @message="onMessage"
      @load="onLoad"
      @error="onError"
    />
  </view>
</template>
<script setup lang="ts">
import { useRouter, useDidShow } from "@tarojs/taro";
const router = useRouter();

const src = ref("");

const onMessage = (e) => {
  console.log("webview-onMessage", e.detail.data);
};
const onLoad = (e) => {
  console.log("webview-onLoad", e.detail.src);
};
const onError = (e) => {
  console.log("webview-onError", e.detail.src);
};

const getURL = (url = "") => {
  let tempURL = decodeURIComponent(url);
  console.log("webview-url", url, " => ", tempURL);

  let infix = tempURL.indexOf("?") > -1 ? "&" : "?";
  let suffix = `orgCode=${parkCode.value}&terminal=${client.value}`;
  tempURL = tempURL + infix + suffix;

  src.value = tempURL;
};

useDidShow(() => {
  if (router.params.src) {
    getURL(router.params.src);
  }
});
</script>

h5唤起小程序原生扫码功能

点击扫码按钮,跳转到小程序内部的扫码页面,调用原生扫码接口,获取扫码结果后再进入到h5页面。

h5应用使用vue2来编写。

1、安装依赖

npm install weixin-js-sdk --save
or
yarn add weixin-js-sdk --save

2、在需要扫码的页面引入

需要扫描的页面地址是:home/index.vue

核心代码:

<template>
    <img class="scan" src="@/assets/images/scan.svg" @click="goScan" />
</tempate>

<script>
import wx from "weixin-js-sdk";
export default {
    methods: {
        // 扫一扫
        goScan() {
          if (navigator.userAgent.toLowerCase().indexOf("miniprogram") !== -1) {
            // 判断是否是微信环境
            wx.miniProgram.getEnv((res) => {
              if (res.miniprogram) {
                // 再次扫描后重置核销标志
                localStorage.setItem("complateScan", "0");
                // url为扫码成功后需要跳转的地址
                const url = window.location.href;

                // 小程序环境下逻辑,跳转到小程序的扫描页面地址(/pages/scan/index,自己定义的地址),可以带上页面返回时需要的参数
                wx.miniProgram.redirectTo({
                  url: `/pages/scan/index?url=${encodeURIComponent(url)}`,
                });
              } else {
                window.console.log(res, "res");
                this.$toast("非微信环境逻辑");
              }
            });
          } else {
            if (
              navigator.userAgent.toLowerCase().indexOf("micromessenger") !== -1
            ) {
              this.$toast("微信内置浏览器");
            } else this.$toast("非微信环境逻辑");
          }
        },
        
    }
}
</script>

3、小程序中的扫码页面

在小程序中创建一个扫码页面scan/index.vue,在这个页面中调用原生扫码接口,成功后跳转到h5页面


<script setup lang="ts">
import Taro from "@tarojs/taro";
import { ref, onMounted } from "vue";
const router = useRouter();

const result = ref();

const goScan = () => {
  Taro.scanCode({
    onlyFromCamera: false,
    scanType: ["barCode", "qrCode", "datamatrix", "pdf417"],
    success: (res) => {

      result.value = JSON.stringify(res);
      goNext();
    },
    fail: (err) => {

      if (err && err.errMsg === "scanCode:fail cancel") {
        Taro.navigateBack();
      } else {
        result.value = JSON.stringify(err);
        goNext();
      }
    },
    complete: (val) => {
      console.log("scanCode-complete", val);
    },
  });
};
const goNext = () => {
  let url = router.params.url;
  if (url) {
    let tempURL = decodeURIComponent(url);
    console.log("scan-url", url, " => ", tempURL);

    let infix = tempURL.indexOf("?") > -1 ? "&" : "?";
    let suffix = `result=${result.value}`;
    tempURL = tempURL + infix + suffix;

    let src = encodeURIComponent(tempURL);
    Taro.redirectTo({
      url: `/pages/webview/index?src=${src}`,
    });
  } else {
    Taro.navigateBack();
  }
};

onMounted(() => {
  goScan();
});
</script>

4、扫码成功后跳转到h5扫码回调页面

由于业务需要,需要扫码的页面与扫码回调页面为同一个页面。

也就是需要在home页面监听地址栏是否有result参数,若有即扫码成功,再处理一些业务逻辑。

由于是同一个页面,我们需要定义一个complateScan标志,表示是否扫码过,只有扫码后未进行核销才去调取核销功能。

注意:扫码成功后重新打开这个页面,所以需要将该标志存储在localStorage中,不然在页面重新进入后数据丢失。

如步骤2同样页面

<script>
export default {
    created() {
        // 是否核销过,1扫码后核销过,0扫码后未核销
        const complateScan = localStorage.getItem("complateScan");
        if (complateScan === "0") {
          // 获取传递回来的数据
          this.result = getLinkParams("result") || "";
          this.handleScanResult();
        }
    },
    methods: {
        
        // 处理扫描结果
        async handleScanResult() {
          if (this.result) {
            const obj = JSON.parse(this.result);
            // 表示已经核销过,下次在进入这个页面无需重复核销
            localStorage.setItem("complateScan", "1");

            // 扫码失败
            if (!obj.result) {
              this.$toast("扫码失败!");
            } else {
              // 扫码成功
              scanVerification({ content: obj.result })
                .then(() => {
                  this.$toast("签到成功!");
                })
                .catch(() => {
                  this.$toast("核销失败!");
                });
            }
          }
        },
    }
}
</script>

后记

在小程序中嵌入h5调用扫码功能,也可以使用微信提供的jssdk接口调取微信扫一扫。因为通过小程序webview容器嵌入的网页可以使用微信提供的jssdk接口。

通过使用微信JS-SDK,网页开发者可借助微信高效地使用拍照、选图、语音、位置等手机系统的能力,同时可以直接使用微信分享、扫一扫、卡券、支付等微信特有的能力,为微信用户提供更优质的网页体验。

具体方法可以查看JS-SDK说明文档

注意:需要先绑定一个微信公众号,并进向相应的配置后方可使用。