H5 静态页面跳转微信小程序

2023-11-18

官方文档指引:开放标签说明文档静态网站 H5 跳小程序

准备工作

开放标签

跳转小程序需要用到微信提供的开放标签:<wx-open-launch-weapp></wx-open-launch-weapp>

wx-open-launch-weapp:用于页面中提供一个可跳转指定小程序的按钮。使用此标签后,用户在网页内点击标签按钮,即可跳转小程序。

H5通过开放标签打开小程序的场景值为「1167」。

开放对象

开放对象:
1、已认证的服务号,服务号绑定“JS接口安全域名”下的网页可使用此标签跳转任意合法合规的小程序。
2、已认证的非个人主体的小程序,使用小程序云开发的静态网站托管绑定的域名下的网页,可以使用此标签跳转任意合法合规的小程序。

版本要求

系统版本要求:

  • 微信版本要求为:7.0.12 及以上
  • 系统版本要求为:iOS 10.3及以上、Android 5.0及以上
  • 注意:微信开发者工具暂时不支持!建议直接使用手机访问进行测试。

使用步骤

1、 绑定域名

登录 微信公众平台 进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。

2、引入 jweixin.js,需要 1.6.0 版本

在需要调用 JS 接口的页面引入如下 JS 文件:http://res.wx.qq.com/open/js/jweixin-1.6.0.js (支持https)。如下:

<script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>

如需进一步提升服务稳定性,当上述资源不可访问时,可改访问:http://res2.wx.qq.com/open/js/jweixin-1.6.0.js(支持https)。

备注:支持使用 AMD/CMD 标准模块加载方法加载。

jweixin.js引入过后,当前的浏览器环境会有一个全局变量 wx(直接wx访问,或者window.wx、globalThis.wx都是可以的)。但是,这个变量不能马上使用,必须将当前网页的路径(不包括#号以及后面的路径,包括#号前面的那个斜杠 / )传给后端,后端根据传的路径返回给前端 appId、timestamp、nonceStr、signature,然后根据这些参数调用 wx.config,进行wx的初始化,也就是下一步骤。

3、设置 wx.config

设置 wx.config,通过 config 接口注入权限验证配置并申请所需开放标签。

与使用 JS-SDK 配置方式相同,所有需要使用开放标签的页面必须先注入配置信息,并通过 openTagList 字段申请所需要的开放标签,否则将无法使用(同一个 url 仅需调用一次)。开放标签的申请和 JS 接口的申请相互独立,是可以同时申请的。如下:

wx.config({
  debug: false, // 开启调试模式,调用的所有 api 的返回值会在客户端 alert 出来,若要查看传入的参数,可以在 pc 端打开,参数信息会通过 log 打出,仅在 pc 端时才会打印
  appId: '', // 必填,公众号的唯一标识
  timestamp: , // 必填,生成签名的时间戳
  nonceStr: '', // 必填,生成签名的随机串
  signature: '',// 必填,签名
  jsApiList: [], // 必填,需要使用的 JS 接口列表
  openTagList: ["wx-open-launch-weapp"] // 需要使用的开放标签列表 小程序跳转按钮:<wx-open-launch-weapp>,app 跳转按钮:['wx-open-launch-app']
});

4、成功验证

通过 ready 接口处理成功验证,如下:

wx.ready(function () {
  // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中
});

5、失败验证

通过 error 接口处理失败验证,如下:

wx.error(function (res) {
  // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名
});

6、初始化 config 参数

 // 请求 config需要的参数
 getUrlConfig({url: encodeURIComponent(window.location.href.split("#")[0])}).then(res => {
     if (res.code === 100) {
         wx.config({
             debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
             appId: res.data.appId, // 必填,公众号的唯一标识
             timestamp: res.data.timeStamp, // 必填,生成签名的时间戳
             nonceStr: res.data.nonceStr, // 必填,生成签名的随机串
             signature: res.data.signature, // 必填,签名
             jsApiList: ['previewImage', 'chooseImage'],
             openTagList: ['wx-open-launch-weapp'] // 需要使用的开放标签列表,例如['wx-open-launch-app']
         });
         wx.ready(() => {})
         wx.error((error) => {})
     }
 })

7、vue 页面中使用

vue 页面中添加 wx-open-launch-weapp 标签:

<wx-open-launch-weapp
      id="launch-btn"
      username="gh_xxxxxxx"
      :path="pagePath"
      @ready="handleReadyFn" 
      @launch="handleLaunchFn" 
      @error="handleErrorFn"
    >
      <script type="text/wxtag-template">
        <style>.btn{
          width: 250px;
          height: 44px;
          background-color: #FFFFFF;
          border-radius: 3px;
          color: #ff6611;
          font-size: 14px;
          line-height: 44px;
          text-align: center;
         }</style>
        <button class="btn">打开小程序</button>
      </script>
</wx-open-launch-weapp>

username:要打开的小程序原始 id ,以 gh_ 开头的;

path:要打开的小程序页面。

vue 模板中使用 <wx-open-launch-weapp> 时,需要在 main.js 中忽略 wx-open-launch-weapp 标签检测,如下:

Vue.config.ignoredElements = ['wx-open-launch-weapp']

否则,页面会报错找不到模板 <wx-open-launch-weapp>

8、html 页面中使用

html 页面中添加 wx-open-launch-weapp 标签:

<wx-open-launch-weapp 
		 id="launch-btn"
      username="gh_xxxxxxx"
      :path="pagePath"
      @ready="handleReadyFn" 
      @launch="handleLaunchFn" 
      @error="handleErrorFn"
      >
        <template>
          <style>
            .btn {
              border: none;
              display: block;
              width: 250px;
              height: 44px;
              background: #FFFFFF;
              border-radius: 3px;
              color: #ff6611;
              font-size: 14px;
              line-height: 44px;             
          		text-align: center;
            }
          </style>
          <button class="btn">打开小程序</button>
        </template>
</wx-open-launch-weapp>

9、注意事项

  • 样式中不可添加 position:fixed 样式,不然微信开放标签跳转按钮不展示;

  • 在普通 html 页面中,使用 <template></template> 包裹 <wx-open-launch-weapp> 标签;

  • 对于 Vue 等视图框架,为了避免 template 标签冲突的问题,可使用 <script type="text/wxtag-template"><script> 进行代替,来包裹插槽模版和样式。

  • 还有一种方式,不管冲突不冲突都能用的(动态生成标签内容),如下:

<!-- 用docment对象来动态的生成节点,再加到页面 -->
<template>
    <div v-html="html"></div>
</template>
<script>
 export default {
        data () {
            return {
               html:'<wx-open-launch-weapp id="launch-btn" username="gh_xxxx" path="/pages/entryPage.html" @launch="handleLaunchFn" @error="handleErrorFn"><template><style>.btn { display:block;border:none;background:#FFFFFF;text-align:center;border-radius:3px;color:#ff6611;font-size:14px;font-weight:400;line-height:44px;width:250px;height: 44px; }</style><button class="btn">跳转小程序</button></template></wx-open-launch-weapp>' 
            }
        },
        created() {
        },
        mounted() {
        },
        methods: {
                  handleLaunchFn (e) {
                      console.log(e)
                  },
                  handleErrorFn(e){
                      console.log('fail', e.detail);
                  },                                            
           }                
       }                
</script>

小程序的 web-view 不支持 wx-open-launch-weapp,所以,在 h5 页面中使用 wx-open-launch-weapp 跳转 A 小程序时,如果将此 h5 通过 webview 的方式嵌入 B小程序,这个功能将失效,按钮也不会展示。

10、要点总结

  1. 保证引入的微信 sdk 是最新的1.6.0
 <script type="text/javascript" src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
  1. 保证当前域名已经加入公众号的安全域名,否则签名会失效;
  2. 保证已经签名成功,并且在 IDE上可以看到签名确实是ok;
  3. 如果是在 vue2.0 下,注意 template 的使用方式,会和脚手架的 template 起冲突;
<wx-open-launch-weapp id="launch-btn" username="gh_xxx" :path="pagePath" env-version="trial" @ready="handleReadyFn" @launch="handleLaunchFn" @error="handleErrorFn" style="position:absolute;top:0;left:0;right:0;bottom:0;width:250px;height:44px;">
        <!-- vue 2.x写法 -->
        <script type="text/wxtag-template">
          <div style="display:block;border:none;background:#FFFFFF;text-align:center;border-radius:3px;
          color:#28BECA;font-size:14px;font-weight:400;line-height:44px;width:250px;height: 44px;">
          打开小程序
        </div>
        </script>
      </wx-open-launch-weapp>
  1. 如果是在 vue3.0 下,注意 script 标签是不被允许写在页面上,要通过 v-is 来指定;
<wx-open-launch-weapp id="launch-btn" username="gh_xxx" :path="pagePath" env-version="trial" @ready="handleReadyFn" @launch="handleLaunchFn" @error="handleErrorFn" style="position:absolute;top:0;left:0;right:0;bottom:0;width:250px;height:44px;">
        <!-- vue 3.0写法,vue3.0新增指令 v-is,但是v-is已在 3.1.0 中被废弃 -->
        <div v-is="'script'" type="text/wxtag-template">
          <div style="position:absolute;left:0;top:0;display:block;border:none;background:#FFFFFF;
          border-radius:3px;color:#28BECA;font-size:14px;font-weight:400;line-height: 44px;width:100%;height:100%;">
            打开小程序
          </div>
        </div>
      </wx-open-launch-weapp>
  1. 如果显示出来了,但是点击无效,尝试看是否 wx-open-launch-weapp 有大小;
  2. 不建议在 wx-open-launch-weapp 标签内写内容。可以用相对定位来做,wx-open-launch-weapp 只是一个浮层,就盖在按钮上面;
  3. 当前 wx-open-launch-weapp 标签中的 Dom 只有在真机下才会显示,所以在 wx-open-launch-weapp 中写样式,实在是太麻烦了,在电脑端的浏览器、微信开发者工具、真机连接本地地址方式按钮都不会显示;这就导致了一个问题 wx-open-launch-weapp 里面的内容控制、样式调试等很难、一点样式改动就需要去部署,到真机上验证。针对这种情况,我的办法是:先不加 <template></template> 或者<script type="text/wxtag-template"><script> ,先在微信开发者工具里面调好样式,然后再加上 <template></template> 或者<script type="text/wxtag-template"><script>

11、完整版vue代码

<template>
  <!-- <section class="jump-mini-program"> -->
  <div class="jump-mini-program">
    <div class="main-content">
      <!-- 外部手机浏览器页面 -->
      <div id="public-web-container" class="hidden">
        <img class="jump-bg" src="xxx.png" alt="" />
        <p id="public-web-jump-button-loading-text" class="open_tips">
          <span id="public-web-jump-button-loading-icon" class="weui-primary-loading weui-primary-loading_transparent">
            <i class="weui-primary-loading__dot"></i>
          </span> 正在打开小程序…
        </p>
        <a id="public-web-jump-button" href="javascript:" class="weui-btn open_btn hidden" onclick="openWeapp()">打开小程序</a>
      </div>
      <!-- 微信手机浏览器页面 -->
      <div id="wechat-web-container" class="hidden">
        <img class="jump-bg" src="xxx.png" alt="" />
        <div class="open-tag-container">
          <wx-open-launch-weapp id="launch-btn" username="gh_xxx" :path="pagePath" @ready="handleReadyFn" @launch="handleLaunchFn" @error="handleErrorFn"
          style="position:absolute;top:0;left:0;right:0;bottom:0;width:250px;height:44px;" env-version="trial">
            <!-- vue 2.x写法 -->
            <script type="text/wxtag-template">
              <div style="display:block;border:none;background:#FFFFFF;text-align:center;border-radius:3px;
              color:#28ca7e;font-size:14px;font-weight:400;line-height:44px;width:250px;height: 44px;">
              打开小程序
            </div>
            </script>
          </wx-open-launch-weapp>
        </div>
      </div>
      <!-- PC浏览器页面 -->
      <div id="desktop-web-container" class="hidden">
        <div id="qrcode"></div>
        <p class="">请在手机打开网页链接</p>
      </div>
    </div>
  </div>
  <!-- </section> -->
</template>
<script>
import wx from "weixin-js-sdk";
import QRCode from "../../../static/js/qrcode.min.js"
export default {
  components: {},
  name: "openminiprogram",
  data () {
    return {
      randomCode: '',
      pagePath: '/pages/home/home'
    };
  },
  created () {
    // const oScript = document.createElement('script');
    // oScript.type = 'text/javascript';
    // oScript.src = 'https://res2.wx.qq.com/open/js/jweixin-1.6.0.js';
    // oScript.onload = this.wxmini
    // document.body.appendChild(oScript);
  },
  mounted () {
    this.$nextTick(() => {
      this.randomCode = this.getQueryVariable('code')
      this.startHandle()
    })
  },
  methods: {
    /**
     *  微信版本要求为:7.0.12及以上。 系统版本要求为:iOS 10.3及以上、Android 5.0及以上。
        参考文档
        https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_Open_Tag.html#%E5%BC%80%E6%94%BE%E6%A0%87%E7%AD%BE%E8%AF%B4%E6%98%8E%E6%96%87%E6%A1%A3
        https://developers.weixin.qq.com/miniprogram/dev/wxcloud/guide/staticstorage/jump-miniprogram.html
     */
    getURLScheme () {
      // 获取URLScheme,这里是固定死的,需要后端开发人员为你准备个接口或云函数返回URLScheme
      // (每个独立的链接被用户访问后,仅此用户可以再次访问并打开对应小程序,其他用户无法再次通过相同链接打开该小程序;)
      return new Promise((resolve, reject) => {
        this.$http({
          method: 'get',
          url: `xxx/shortUrl/getByRandom?random=${this.randomCode}`,
        }).then(response => {
          const resData = response.data.mobBaseRes
          if (resData.code === 100) {
            resolve(resData.result)
          } else {
            resolve()
          }
        }).catch(error => {
          // handle error
          resolve()
        }).then(() => {
          // always executed
          resolve()
        });
      })
    },
    // 外部手机浏览器打开URL Scheme,一般会有提示,接受打开即可
    async openWeapp (onBeforeJump) {
      const res = await this.getURLScheme()
      //获取url scheme
      const openlink = res.wxScheme
      if (onBeforeJump) {
        onBeforeJump()
      }
      if (openlink) {
        location.href = openlink
      }
      setTimeout(() => {
        window.location.href = 'xxx'
      }, 3000);
    },
    // 使用开放标签打开小程序时调用,注入wx.config的配置信息,使用小程序云开发静态网站托管的网页可以绕过鉴权,公众号需要后端接口配合返回鉴权参数
    getWXConfig () {
      return new Promise((resolve, reject) => {
        let url = window.location.href.split("#")[0]
        let arg = encodeURIComponent(url)
        this.$http({
          //调用接口
          method: "GET",
          url: `xxx/getticket?url=${arg}`,
        }).then(res => {
          if (res && res.data && res.data.mobBaseRes && res.data.mobBaseRes.result) {
            const { noncestr, timestamp, signature } = res.data.mobBaseRes.result
            const config = {
              appId: 'wxxxx', // 已认证的小程序appid或已认证的服务号appid
              timestamp: timestamp, // 必填,使用小程序云开发静态网站托管的网页填任意数字即可,无须鉴权
              nonceStr: noncestr, // 必填,使用小程序云开发静态网站托管的网页填任意非空字符串即可,无须鉴权
              signature: signature, // 必填,使用小程序云开发静态网站托管的网页填任意非空字符串即可,无须鉴权
              jsApiList: ['previewImage', 'chooseImage'],// 必填,随意一个接口即可
              openTagList: ["wx-open-launch-weapp"], // 填入打开小程序的开放标签名
            }
            resolve(config)
          } else {
            resolve()
          }
        }).catch(err => { resolve() })
      })
    },
    async startHandle () {
      const ua = navigator.userAgent.toLowerCase()
      // 企业微信
      const isWXWork = ua.match(/wxwork/i) == 'wxwork'
      // 微信浏览器
      const isWeixin = !isWXWork && ua.match(/MicroMessenger/i) == 'micromessenger'
      let isMobile = false
      let isDesktop = false
      if (navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|IEMobile)/i)) {
        isMobile = true
      } else {
        isDesktop = true
      }

      if (isDesktop) {
        // 在 pc 上则给提示引导到手机端打开
        const containerEl = document.getElementById('desktop-web-container')
        containerEl.classList.remove('hidden')
        containerEl.classList.add('full', 'desktop-web-container')
        // 生成当前页面二维码
        new QRCode('qrcode', {
          text: document.URL,
          width: 200,
          height: 200,
          colorDark: '#000000',
          colorLight: '#ffffff',
          correctLevel: QRCode.CorrectLevel.H
        });
      } else if (isWeixin) {
        //如果微信浏览器,通过开放标签打开小程序
        const containerEl = document.getElementById('wechat-web-container')
        containerEl.classList.remove('hidden')
        containerEl.classList.add('full', 'wechat-web-container')

        this.pagePath = `/pages/entryPage/entryPage?random=${this.randomCode}`
        const config = await this.getWXConfig()
        wx.config({
          ...config
        })
        wx.ready(() => {
        });
        // 通过error接口处理失败验证
        wx.error((res) => {
          console.log("wx.error", res);
          // window.location.reload();
        });
      } else {
        // 在非微信的外部手机浏览器使用URLScheme打开小程序
        const containerEl = document.getElementById('public-web-container')
        containerEl.classList.remove('hidden')
        containerEl.classList.add('full', 'public-web-container')

        var buttonEl = document.getElementById('public-web-jump-button')
        var buttonLoadingEl = document.getElementById('public-web-jump-button-loading-text')
        try {
          // 自动执行,打开URLScheme
          await openWeapp(() => {
            buttonEl.classList.remove('hidden')
            buttonLoadingEl.classList.add('hidden')
          })
        } catch (e) {
          buttonEl.classList.remove('hidden')
          buttonLoadingEl.classList.add('hidden')
          this.jumpToAppDownloadPage()
        }
      }
    },
    handleReadyFn () {
      console.log('handleReadyFn');
    },
    handleLaunchFn (e) {
      console.log('success', e);
    },
    handleErrorFn (e) {
      console.log('用户拒绝跳转或跳转异常', e.detail)
    },
    jumpToAppDownloadPage () {
      setTimeout(() => {
        window.location.href = 'xxx'
      }, 10);
    },
    getQueryVariable (variable) {
      var query = window.location.search.substring(1);
      var vars = query.split("&");
      for (var i = 0; i < vars.length; i++) {
        var pair = vars[i].split("=");
        if (pair[0] == variable) { return pair[1]; }
      }
      return (false);
    }
  }
};
</script>

<style lang="less" scoped>
.jump-mini-program {
  .hidden {
    display: none;
  }
  .main-content {
    background: linear-gradient(
      180deg,
      #04606b 0%,
      #0c727c 65%,
      #177d87 65%,
      #75ced7 100%
    );
    height: 100vh;
  }

  .public-web-container {
    display: flex;
    flex-direction: column;
    align-items: center;
    position: relative;
    top: 50%;
    /*偏移*/
    transform: translateY(-50%);
  }

  .jump-bg {
    width: 100%;
  }

  .wechat-web-container {
    display: flex;
    flex-direction: column;
    align-items: center;
    position: relative;
    top: 50%;
    /*偏移*/
    transform: translateY(-50%);
    text-align: left;
  }

  .wechat-web-container p {
    position: absolute;
    top: 40%;
  }
  .open-tag-container {
    width: 250px;
    height: 44px;
    position: relative;
  }
  .wechat-web-container wx-open-launch-weapp {
    // display: flex;
    // flex-direction: column;
    // align-items: center;
    // text-align: center;
  }

  .desktop-web-container {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
  }

  .desktop-web-container p {
    margin-top: 30px;
  }

  .open_btn {
    width: 250px;
    height: 44px;
    background: #ffffff;
    border-radius: 3px;
    color: #28ca7e;
    font-size: 14px;
    line-height: 28px;
    font-weight: 400;
  }

  .open_tips {
    font-size: 14px;
    font-weight: 400;
    color: #ffffff;
    /* opacity: 0.8; */
  }

  .weui-primary-loading:after,
  .weui-primary-loading:before {
    opacity: 1;
  }
}
</style>

12、完整版html代码

<!DOCTYPE HTML>
<html>
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="maximum-scale=1.0, minimum-scale=1.0, user-scalable=0, initial-scale=1.0, width=device-width" />
		<meta name="format-detection" content="telephone=no, email=no, date=no, address=no">
		<title>打开小程序</title>
		<link rel="stylesheet" type="text/css" href="css.css" />
  	<!-- weui 样式 -->
  	<link rel="stylesheet" href="https://res.wx.qq.com/open/libs/weui/2.4.1/weui.min.css">
  	</link>
  	<style>
    .hidden {
      display: none;
    }

    .page {
      background: linear-gradient(180deg, #04606B 0%, #0C727C 65%, #177D87 65%, #75CED7 100%);
      height: 100vh;
    }

    .public-web-container {
      display: flex;
      flex-direction: column;
      align-items: center;
      position: relative;
      top: 50%;
      /*偏移*/
      transform: translateY(-50%);
    }

    .jump-bg {
      width: 100%;
    }

    .viomi-logo {
      width: 102px;
      text-align: center;
      margin-bottom: -20px;
    }

    .wechat-web-container {
      display: flex;
      flex-direction: column;
      align-items: center;
      position: relative;
      top: 50%;
      /*偏移*/
      transform: translateY(-50%);
      text-align: center;
    }

    .wechat-web-container p {
      position: absolute;
      top: 40%;
    }

    .wechat-web-container wx-open-launch-weapp {
      display: flex;
      flex-direction: column;
      align-items: center;
      text-align: center;
    }

    .desktop-web-container {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
    }

    .desktop-web-container p {
      margin-top: 30px;
    }

    .open_btn {
      width: 250px;
      height: 44px;
      background: #FFFFFF;
      border-radius: 3px;
      color: #28ca59;
      font-size: 14px;
      line-height: 28px;
      font-weight: 400;
    }

    .open_tips {
      font-size: 14px;
      font-weight: 400;
      color: #FFFFFF;
      /* opacity: 0.8; */
    }

    .weui-primary-loading:after,
    .weui-primary-loading:before {
      opacity: 1;
    }
  </style>
  <!-- 公众号 JSSDK -->
  <script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
  <!-- 生成二维码 -->
  <script type="text/javascript" src="./static/js/qrcode.min.js"></script>
  <script src="https://cdn.staticfile.org/axios/0.18.0/axios.min.js"></script>
	</head>
	<body>
  <div class="page">
    <!-- 外部手机浏览器页面 -->
    <div id="public-web-container" class="hidden">
      <img class="jump-bg" src="xxx.png" alt="" />
      <p id="public-web-jump-button-loading-text" class="open_tips">
        <span id="public-web-jump-button-loading-icon" class="weui-primary-loading weui-primary-loading_transparent">
          <i class="weui-primary-loading__dot"></i>
        </span> 正在打开小程序…
      </p>
      <a id="public-web-jump-button" href="javascript:" class="weui-btn open_btn hidden" onclick="openWeapp()">打开小程序</a>
    </div>
    <!-- 微信手机浏览器页面 -->
    <div id="wechat-web-container" class="hidden">
      <img class="jump-bg" src="xxx.png" alt="" />
      <wx-open-launch-weapp id="launch-btn" username="gh_xxx" path="/pages/home/home">
        <template>
          <style>
            button {
              border: none;
              display: block;
              width: 250px;
              height: 44px;
              background: #FFFFFF;
              border-radius: 3px;
              color: #28ca59;
              font-size: 14px;
              line-height: 28px;
              font-weight: 400;
            }
          </style>
          <button>打开小程序</button>
        </template>
      </wx-open-launch-weapp>
    </div>
    <!-- PC浏览器页面 -->
    <div id="desktop-web-container" class="hidden">
      <div id="qrcode"></div>
      <p class="">请在手机打开网页链接</p>
    </div>
  </div>

  <script>
    /*
        微信版本要求为:7.0.12及以上。 系统版本要求为:iOS 10.3及以上、Android 5.0及以上。
        参考文档
        https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_Open_Tag.html#%E5%BC%80%E6%94%BE%E6%A0%87%E7%AD%BE%E8%AF%B4%E6%98%8E%E6%96%87%E6%A1%A3
        https://developers.weixin.qq.com/miniprogram/dev/wxcloud/guide/staticstorage/jump-miniprogram.html
    */
    const getURLScheme = (path, query) => {
      // 获取URLScheme,这里是固定死的,需要后端开发人员为你准备个接口或云函数返回URLScheme
      // (每个独立的链接被用户访问后,仅此用户可以再次访问并打开对应小程序,其他用户无法再次通过相同链接打开该小程序;)
      return new Promise((resolve, reject) => {
        axios({
          method: 'get',
          url: `xxx/shortUrl/getByRandom?random=${getQueryVariable("code")}`,
        }).then(response => {
          if (response.data.mobBaseRes.code === 100) {
            resolve(response.data.mobBaseRes.result.wxScheme)
          } else {
            resolve()
          }
        }).catch(error => {
          // handle error
          resolve()
        }).then(() => {
          // always executed
          resolve()
        });
      })
    }
    // 外部手机浏览器打开URL Scheme,一般会有提示,接受打开即可
    async function openWeapp (onBeforeJump) {
      //获取url scheme
      const openlink = await getURLScheme()
      if (onBeforeJump) {
        onBeforeJump()
      }
      if (openlink) {
        location.href = openlink
      }
      setTimeout(() => {
        window.location.href = 'xxx'
      }, 3000);
    }
    // 使用开放标签打开小程序时调用,注入wx.config的配置信息,使用小程序云开发静态网站托管的网页可以绕过鉴权,公众号需要后端接口配合返回鉴权参数
    const getWXConfig = async () => {
      return new Promise((resolve, reject) => {
        let url = window.location.href;
        let ut = url.split("#");
        let data = {
          url: ut[0]
        };
        axios({
          //调用接口
          method: "GET",
          url: `xxx/getticket?url=${data.url}`,
        }).then(res => {
          if (res && res.data && res.data.mobBaseRes && res.data.mobBaseRes.result) {
            const { noncestr, timestamp, signature } = res.data.mobBaseRes.result
            const config = {
              appId: 'wxxxx', // 已认证的小程序appid或已认证的服务号appid
              timestamp: timestamp, // 必填,使用小程序云开发静态网站托管的网页填任意数字即可,无须鉴权
              nonceStr: noncestr, // 必填,使用小程序云开发静态网站托管的网页填任意非空字符串即可,无须鉴权
              signature: signature, // 必填,使用小程序云开发静态网站托管的网页填任意非空字符串即可,无须鉴权
              jsApiList: ['previewImage', 'chooseImage'],// 必填,随意一个接口即可
              openTagList: ["wx-open-launch-weapp"], // 填入打开小程序的开放标签名
            }
            resolve(config)
          } else {
            resolve()
          }
        }).catch(err => { resolve() })
      })
    }
    const start = async () => {
      const ua = navigator.userAgent.toLowerCase()
      // 企业微信
      const isWXWork = ua.match(/wxwork/i) == 'wxwork'
      // 微信浏览器
      const isWeixin = !isWXWork && ua.match(/MicroMessenger/i) == 'micromessenger'
      let isMobile = false
      let isDesktop = false
      if (navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|IEMobile)/i)) {
        isMobile = true
      } else {
        isDesktop = true
      }

      if (isDesktop) {
        // 在 pc 上则给提示引导到手机端打开
        const containerEl = document.getElementById('desktop-web-container')
        containerEl.classList.remove('hidden')
        containerEl.classList.add('full', 'desktop-web-container')
        // 生成当前页面二维码
        new QRCode('qrcode', {
          text: document.URL,
          width: 200,
          height: 200,
          colorDark: '#000000',
          colorLight: '#ffffff',
          correctLevel: QRCode.CorrectLevel.H
        });
      } else if (isWeixin) {
        //如果微信浏览器,通过开放标签打开小程序
        const containerEl = document.getElementById('wechat-web-container')
        containerEl.classList.remove('hidden')
        containerEl.classList.add('full', 'wechat-web-container')

        const launchBtn = document.getElementById('launch-btn')
        launchBtn.addEventListener('error', function (e) {
          console.log('用户拒绝跳转或跳转异常', e.detail)
        })
        const config = await getWXConfig()
        wx.config({
          ...config
        })
      } else {
        // 在非微信的外部手机浏览器使用URLScheme打开小程序
        const containerEl = document.getElementById('public-web-container')
        containerEl.classList.add('full', 'public-web-container')

        var buttonEl = document.getElementById('public-web-jump-button')
        var buttonLoadingEl = document.getElementById('public-web-jump-button-loading-text')
        try {
          // 自动执行,打开URLScheme
          await openWeapp(() => {
            buttonEl.classList.remove('hidden')
            buttonLoadingEl.classList.add('hidden')
          })
        } catch (e) {
          buttonEl.classList.remove('hidden')
          buttonLoadingEl.classList.add('hidden')
          setTimeout(() => {
            window.location.href = 'xxx'
          }, 1000);
        }
      }
    }
    start()
    function getQueryVariable (variable) {
      var query = window.location.search.substring(1);
      var vars = query.split("&");
      for (var i = 0; i < vars.length; i++) {
        var pair = vars[i].split("=");
        if (pair[0] == variable) { return pair[1]; }
      }
      return (false);
    }
  </script>
</body>
</html>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

H5 静态页面跳转微信小程序 的相关文章

  • 节点异步循环 - 如何使该代码按顺序运行?

    我知道有几个关于此的帖子 但根据我发现的那些帖子 这应该可以正常工作 我想在循环中发出 http 请求 并且不希望循环迭代 直到触发请求回调 我正在使用异步库 如下所示 const async require async const req
  • 如何限制 Chrome 中的最大文本区域宽度和高度或如何禁用文本区域调整大小

    Chrome 允许通过在右下角添加文本区域来调整文本区域的大小 但有时这种移动可能会破坏页面的设计 所以我想知道如何限制该操作的最大和最小宽度 即如何完全禁用该功能和thml javascript css在页面上 您可以使用 resize
  • 使用ajax发送表单数据

    我想用 ajax 以表单形式发送所有输入 我有一个这样的表单
  • 添加选中的单选按钮的总数

    UPDATE 如果您尝试此链接上的表格http jsfiddle net Matt KP BwmzQ http jsfiddle net Matt KP BwmzQ 按下小提琴并选择右上角的 40 英镑单选按钮 然后在底部看到订单总额 上面
  • React 无法识别 DOM 元素上的 `isActive` 属性 - styled-components

    我有以下内容svg我传递道具的组件 import React from react export default props gt
  • 在 d3 中应用转换时出现错误

    我正在尝试对我在 d3 中设计的条形图应用一些过渡效果 这是我的代码 svg selectAll bar data data enter append g attr class bar append rect attr rx barRadi
  • 从本地 html/javascript 网站插入 mySQL 数据库

    我正在尝试做什么 我的程序的目的是插入数据local HTML JS网站变成online 非本地 mySQL数据库 到目前为止我尝试过的 我试图用来实现此目的的原始方法是让我的本地网站使用 javascript 通过在线发布数据PHP文件
  • 如何在没有 jQuery 或延迟加载的情况下推迟背景图像

    根据帕特里克 塞克斯顿tutorial https varvy com pagespeed defer images html 我想以与这里相同的方式推迟背景图像img img src data image png base64 R0lGO
  • axios 如何将 blob 与 arraybuffer 作为响应类型处理?

    我正在下载一个 zip 文件axios https www npmjs com package axios 为了进一步处理 我需要获取已下载的 原始 数据 据我所知 Javascript 有两种类型 Blob 和 Arraybuffers
  • Lodash _.hasIntersection?

    我想知道两个或多个数组是否有共同的项目 但我不在乎这些项目是什么 我知道 lodash 有一个 intersection方法 但我不需要它来遍历每个数组的每个项目 相反 我需要类似的东西 hasIntersection一旦找到第一个常见的出
  • 使标签充当输入按钮

    我怎样才能做一个 a href http test com tag test Test a 就像表单按钮一样 通过充当表单按钮 我的意思是 当单击链接执行操作时method get 或 post 以便能够通过 get 或 post 捕获它
  • 如何在 Node.js 中打开 Windows-1255 编码文件?

    我有一个 Windows 1255 希伯来语 编码的文件 我希望能够在 Node js 中访问它 我尝试使用打开文件fs readFile 它给了我一个Buffer我无能为力 我尝试将编码设置为Windows 1255 但这没有被识别 我还
  • JavaScript 中的安全数据

    我必须为 Web 测试创建生成器 使用 HTML 和 JavaScript 测试必须离线和在线进行 正确答案和分数评估必须是生成的测试的一部分 最终用户的分数仅发送到服务器 无法在服务器上进行评估 并且服务器对问题一无所知 它只保存最终分数
  • 跟踪预防阻止了对 https://appsforoffice.microsoft.com/lib/1.1/hosted/office.js 存储的访问

    大约一年半前 我使用 OfficeJS API 编写了一个 Excel 加载项 它一直工作到大约两周前 Excel 似乎已经进行了更新 现在我可以右键单击任务窗格并查看开发工具 而以前我无法做到这一点 并且必须运行外部 MS Edge 开发
  • 使用 NodeJS 创建 YouTube 播放列表

    我正在尝试使用 NodeJS 服务器创建 YouTube 播放列表 我已按照 Oauth 的 NodeJS 快速入门说明进行操作 如以下链接所示 https github com youtube api samples blob maste
  • 单击 html 中的按钮后如何从 javascript 函数写入文件

    我正在尝试编写真正基本的代码 在 html 文件上按下按钮后 通过 JavaScript 函数在本地写入 txt 文件 这不可能吗 我可以仅使用 javascript 文件写入文件 但在尝试同时使用两者时则不能
  • 使用 jQuery 的 ajax 方法以 blob 形式检索图像

    我最近问了另一个 相关 问题 这导致了这个后续问题 提交数据而不是输入表单的文件 https stackoverflow com questions 17643142 submitting data instead of a file fo
  • 如何加载Jquery Tiny滚动条

    所以我想自定义一个滚动条 我发现了一个很小的滚动条 这是一个jquery插件 http baijs nl tinyscrollbar http baijs nl tinyscrollbar 问题是 无论如何我都无法让它工作 我将 Jquer
  • 如何将函数导入到Vue组件中?

    我正在尝试将单个函数导入到我的 Vue 组件中 我为我的函数创建了一个单独的 js 文件 randomId js exports randomId gt My function 在我的 Vue 组件中 我导入了 Random js let
  • 如何向 SvelteKit/Vite 应用添加版本号?

    我正在尝试在我的 SvelteKit 应用程序中创建一个系统 它会在某个页面上向您显示有关当前应用程序版本的信息 最好是 Git 提交哈希和描述 我尝试使用Vite的定义功能 https vitejs dev config define在构

随机推荐

  • 学校与工作(献于在校大学生及入职不久的工作者)

    学校与工作 每个人都把自己眼界的局限当成世界的局限 学校是非常不同于职业工作的 有些人在其早期职业生涯中栽跟头 就是因为未能从已经生活了近20年的学校环境过渡到软件行业的美丽新世界 学生的活动具有高度约束性 工作量都是规定好了的 虽然当你是
  • IEEE-754标准浮点数,十六进制与十进制转换方法(附C代码)

    十进制数与IEEE 754 32 位转换实例讲解 https blog csdn net qq 41629142 article details 83692106 https blog csdn net a627088424 article
  • springboot集成kafka实战项目,kafka生产者、消费者、创建topic,指定消费分区

    springboot集成kafka实战项目 kafka生产者 消费者 创建topic 指定消费分区 前言 本项目代码可直接集成到你现有的springboot项目中 功能包括 1 kafka生产者配置 2 kafka消费者配置 指定分区消费
  • eigen与opencv矩阵转换,eigen与matlab函数比照

    近期 项目需要 学习使用eigen矩阵库 链接时eigen的主页 发现相关中文资料比较少 今天写下使用心得 eigen配置 windows vs系列 eigen的配置很简单 下载解压后 在VC 目录下的包含目录中 将eigen的路径包含进去
  • java多线程使用教程

    文章目录 如何使用多线程 继承Thread类 实现Runnable接口 线程的生命周期 线程同步 线程间通信 shutdown 方法的重要性 如何使用多线程 在Java中 创建多线程的方式有两种 一种是继承Thread类 另一种是实现Run
  • docker中mysql初始化及启动失败解决办法

    在docker中有一个mysql服务 其数据文件是挂在在主机外面的文件 在docker中的root有访问该数据文件的权限 但是docker中mysql访问数据文件的时候提示权限不足 于是只有以root用户来启动mysql了 数据初始化 my
  • 从零开始Vue3+Element Plus后台管理系统(十)——自定义水印指令与全局注册

    在实际项目开发中 自定义指令用得还是比较多的 比如 复制粘贴 输入框防抖 输入框禁止特殊字符 权限校验 背景水印 拖拽等等 指令确实是个优雅的存在 Vue3中定义一个普通的自定义指令的详细说明参见官网 https cn vuejs org
  • Ubuntu 安装 anaconda

    文章目录 写在前面 一 官网下载安装包 二 安装 参考链接 写在前面 Ubuntu安装 anaconda 比较简单 去官网下载 anaconda 安装包 然后安装即可 自己的安装环境 Ubuntu18 04 anaconda3 博客撰写日期
  • MySQL-图形化界面工具 (下)

    作者 小刘在C站 个人主页 小刘主页 每天分享云计算网络运维课堂笔记 努力不一定有收获 但一定会有收获加油 一起努力 共赴美好人生 树高千尺 落叶归根人生不易 人间真情 目录 MySQL 修改数据 删除数据 DQL 基本语法 MySQL M
  • MySQL导出和导入SQL脚本

    首先 使用mysqldump命令的前提是 在Cmd中进入mysql安装目录下的bin目录下 才可以使用该命令 我的mysql安装在E 盘 所以 首先进入bin目录下 E Program Files MySQL MySQL Server 5
  • SLAM常用最小二乘最优化方法学习、分析和总结

    SLAM中二维视觉的定位问题被最终归为一个最小二乘问题 那么紧随其后的就是对最小二乘的最优化求解 对其求解析解显然是不太合适的 所以就需要一些数值的最优化方法对最小二乘问题进行求解 在SLAM中 常用的算法有 梯度下降法 牛顿法 以及牛顿法
  • 数字后端——布局

    由于I O单元和模块的布放已经在布图规划时完成 因此布局的剩余任务主要是对标准单元的布局 布局方案在布图规划时就已经做了决定 要么选择展平式布局 要么就是层次化布局 一 布局目标 布局的目标也即布局内容实施之后所要达到的预期值 可以归纳为以
  • 【网络基础】路由表,分组转发算法

    前提 IP数据报的首部中没有地方可以用来指明 下一跳路由器的 IP 地址 那么 当路由器接受到一个待转发的报文时 是如何确定将该报文的传向呢 在此 我们引入 路由表 概念 路由表如图所示 当一个IP报文传到路由器R2时 则会通过查询R2所维
  • js基础--获取浏览器当前页面的滚动条高度的兼容写法

    前言 在开发中 兼容性问题是最常见的 今天就来介绍一下关于获取滚动条高度的兼容性写法 宽度同理 我在这里就不一一解释了 各浏览器的写法 IE6 7 8 document documentElement scrollTop IE9以上 win
  • 3D图形渲染技术

    如何用2D平面展现3D图形 2D图形 在一个平面中有了两个点 知道了他们的XY坐标 就可以把它们链接起来画成一条线 通过控制A和B点的XY坐标可以控制一条线 在3D图像中 点的坐标多了一个Z轴的坐标系 但是在2D的屏幕坐标上不可能有XYZ立
  • linux上mysql整库完全备份命令(包括函数和存储过程)

    mysqldump E R triggers single transaction master data 2 default character set utf8 u root p 库名 gt tmp 库名 sql R表示导出functi
  • 【毕业设计】基于SSM实现酒店管理系统(论文+源码+ppt+视频)

    技术架构SSM 1 Spring是一个开源的Java Java EE全功能栈的应用程序框架 以Apache许可证形式发布 也有 NET平台上的移植版本 当需要用到某一对象时不需要程序员在代码中增加一个新对象而是在可扩展标记语言 extens
  • php中流行的rpc框架详解(修改版)

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 什么是RPC框架 如果用一句话概括RPC就是 远程调用框架 Remote Procedure Call 那什么是远程调用 通常我们调用一个php中的方法 比如这样一个函数方
  • Windows 文件共享功能使用教程,局域网多台电脑之间传送文件

    设想一下 家里或者公司有多台电脑 连接同一个Wifi 也就是处于同一个局域网中 在不能使用微信 网盘的文件传输功能的情况下 这多台电脑之间 就只能用U盘传送数据吗 不 Windows系统中已经提供了文件共享功能 比如一些公司或者学校机房经常
  • H5 静态页面跳转微信小程序

    官方文档指引 开放标签说明文档 静态网站 H5 跳小程序 H5 静态页面跳转微信小程序 准备工作 开放标签 开放对象 版本要求 使用步骤 1 绑定域名 2 引入 jweixin js 需要 1 6 0 版本 3 设置 wx config 4