微信h5前端开发(微信授权、微信支付、跳转小程序、自定义分享等)

332 阅读5分钟

前言

笔者近期做了一个h5前端项目,需要用到微信相关的功能。因为是第一次做涉及到微信的功能,总是在踩坑和试错,故在此总结记录一下。

遇到的困难

  • 所有微信相关的功能不能在本地调试,好像是可以实现,但是很麻烦。所以我们采取了改了代码直接放到正式的服务器上,用正式的域名
  • 想用微信提供的接口必须先引入js,然后wx.config初始化配置
  • 跳转小程序的按钮样式难调

技术栈 比较简单,但是需要引入

  • jQuery
  • weui
  • jweixin

一、网页授权 获取code

想要获取当前用户的微信信息,必须拿到这个code。逻辑是前端打开一个链接,在回调页面里的url里(是这样的:redirect_uri/?code=CODE&state=STATE)可以获取code和携带的参数state。redirect_uri/?code=CODE&state=STATE。

我写了以下的方法:

  • 封装了openAuthorizePage方法打开回调页面
  • 封装了从url获取code的方法
  • 注意坑:调试的时候的code不显示到url中,所以用手机把链接发送到电脑上没用。但是打印可以出来
封装了openAuthorizePage方法
/**
 * 打开验证页的方法
 * @param {*} url 回调页面的路径
 * @param {*} state 携带的参数。自己规定的 传 '1' 则立即执行支付的方法
 */
function openAuthorizePage(url, state) {
  console.log("进入验证页", url, state)
  let response_type = "code" //就这样写
  state = state || "STATE" // 携带的参数
  let scope = "snsapi_base" // 两种情况,snsapi_base不跳页,snsapi_userinfo跳页
  var router = encodeURIComponent("这里是正式环境的域名" + url)// 记得encodeURIComponent
  const jumpPath = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appid}&redirect_uri=${router}&response_type=${response_type}&scope=${scope}&state=${state}#wechat_redirect`
  console.log("跳转url", jumpPath)
  window.location.href = jumpPath
}

//转码——
function getUrlCode(key) {
  let url = window.location.href
  console.log("当前url===", url)
  //如果有就直接截取code
  if (url.indexOf("?") != -1) {
    let obj = urlToObj(url)
    console.log("getUrlCode()---" + key, obj[key])
    if (obj[key]) {
      return obj[key]
    }
  }
  return ""
}

function urlToObj(str) {
  var obj = {}
  var arr1 = str.split("?")
  var arr2 = arr1[1].split("&")
  for (var i = 0; i < arr2.length; i++) {
    var res = arr2[i].split("=")
    obj[res[0]] = res[1]
  }
  return obj
}
调用方法获取code
// 回调页面这样获取code
var code = sessionStorage.getItem("code")// 从缓存里取有没有这个code
$(function () {
  let code1 = getUrlCode("code")// 从url取有没有code
  if (code1) {// 如果url里有code就把它放到缓存里。
    sessionStorage.setItem("code", code1)
    code = code1
  }
})

二、根据code获取openid和微信用户信息

  • 后台写了一个接口,若以前注册过此平台,则直接返回code和微信用户信息;若以前没有注册过,则只返回openid,前台需要把openid存到缓存,并跳到手机号验证码登录页
  • 此业务是选择商品点击支付的按钮就调用登录的方法,登录完就自动调用支付的方法。
  • 注意坑:code使用了一次以后就会失效,5分钟以后也会失效。所以本次开发中只使用一次code获取oppenid
  • openid用于登录和支付

封装了commonAdoptClick方法来决定是先去登录还是支付。


/**
 * 支付按钮点击事件
 * @param {*} page 当前页面url
 * @param {*} params 调支付接口需传参
 * @param {*} state 回调页面里的参数。自行判断 '1'的时候直接去调支付的接口
 */
function commonAdoptClick(page, params, state) {
  if (!wxUser || !openid) {
    // 如果没有user信息或者openid就去登录,否则就生成订单去支付
    weChatLogin(page, params, state)
  } else {
  // 处理支付业务的方法(第三部会展示)
    makeAdot(params, page)
  }
}

/**
 * 微信公众号登录
 * @param {*} page 回调页面的路径
 * @param {*} params 支付需要的参数
 * @param {*} state 携带的参数。自己规定的 传 '1' 则立即执行支付的方法
 */
function weChatLogin(page, params, state) {
  if (code) {
    if (openid && !wxUser) {
      // 拿到openid了去登录页注册
      window.location.href = "login.html"
    } else {
    // getApi是封装的请求后台的方法
      getApi("post", "后台登录接口", { code: code }).then((res) => {
        if (res.status) {
          // 之前注册过,拿code登录成功
          localStorage.setItem("wxUser", JSON.stringify(res.data))
          localStorage.setItem("openid", res.data.wechat_openid)
          openid = res.data.wechat_openid
          params.user_id = res.data.userId
          // 登录成功后直接就可以支付了
          // 处理支付业务的方法
          makeAdot(params, page)
        } else {
          // 之前没注册过,生成的openid 去登录页
          localStorage.setItem("openid", res.data.openid)
          window.location.href = "login.html"
        }
      })
    }
  } else {
    // 获取code(上文第一步的方法)
    openAuthorizePage(page, state)
  }
}

在页面调用

// 从缓存取oppenid,weUser,
var wxUser = localStorage.getItem("wxUser") 
var openid = localStorage.getItem("openid") || ""


// 写好支付需要的参数,和当前的url,调用commonAdoptClick
  let params = {
    // 支付业务需要的参数
  }
  const page = '当前页面的url'
  commonAdoptClick(page, params, "1")
  
  

三、支付功能

封装了生成订单、获取支付需要的传参、调微信支付的方法

// 生成订单
function makeAdot(params, page) {
  getApi("post", "生成订单的后台接口", params).then((res) => {
    console.log("res", res)
    if (res.status && res.data) {
      let data = res.data
      console.log("开始支付")
      payPet(data.order_no, page)
    } else {
      $.alert(res.msg || "操作失败")
    }
  })
}
// 订单支付
function payPet(order_no, url) {
  let param1 = {
    user_id: userId,
    order_no,
    type: 3, //类型 1-APP 2-小程序 3-公众号JSAPI 不传默认app
    openid: openid,
  }
  console.log("订单支付入参", param1)
  getApi("post", "获取微信支付需要的参数", param1).then((res) => {
    if (res.status) {
      // 调微信的支付
      const data = res.data
      sessionStorage.setItem("signPackage", JSON.stringify(data))
      onBridgeReady(data, order_no)
    } else {
      $.alert(res.msg || "查询失败")
    }
  })

}
function onBridgeReady(data, order_no) {
  WeixinJSBridge.invoke(
    "getBrandWCPayRequest",
    {
      appId: data.appId, //公众号ID,由商户传入appid, //
      timeStamp: data.timeStamp, //时间戳,自1970年以来的秒数
      nonceStr: data.nonceStr, //随机串
      package: data.package,
      signType: data.signType, //微信签名方式:
      paySign: data.paySign, //微信签名
    },
    function (res) {
      if (res.err_msg == "get_brand_wcpay_request:ok") {
        // 使用以上方式判断前端返回,微信团队郑重提示:
        //res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
        $.confirm({
          title: "提示",
          text: "恭喜您支付成功,您可以去小程序-“XXX"查看,
          onOK: function () {
            //点击确认
            //点击确认后的回调函数
            window.location.href = "jump_mp.html"// 此页面写了跳转小程序的方法
          },
          onCancel: function () {},
        })
      } else {
        $.alert("支付失败")
      }
    }
  )
}

四、跳转小程序

调用后台接口拿到wx.config需要的参数,然后wex.config初始化配置

     var myurl = location.href.split("#")[0]// 当前页面url
    getApi("post", "get-jssdk后台接口名", { url: myurl }).then((res) => {
      if (res.status) {
        console.log("微信初始化接口结果:", res)
        let datad = res.data 
        wx.config({
          debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来
          appId: datad.appId, // 必填,公众号的唯一标识
          timestamp: datad.timestamp, // 必填,生成签名的时间戳
          nonceStr: datad.nonceStr, // 必填,生成签名的随机串
          signature: datad.signature, // 必填,签名,见附录1
          jsApiList: ["updateAppMessageShareData", "updateTimelineShareData"], // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
          openTagList: ["wx-open-launch-weapp"],
        })
        wx.error(function (res) {
          $.alert(res.msg || "微信config失败")
        })
        // initShare(param)
        wx.ready(function () {
          console.info("ready")

          var btn = document.getElementById("launch-btn")
          btn.addEventListener("launch", function (e) {
            console.log("success")
          })
          btn.addEventListener("error", function (e) {
            console.log("fail", e.detail)
          })
        })
      }
    })

html代码

  • 注意坑:按钮的样式难调,默认就是原生的按钮样式很丑,写到style标签里或者行内样式才生效。而且有的属性不生效。所以最后没有用这一版跳转小程序的代码,而是放了二维码图片让用户扫。
 <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>

 <wx-open-launch-weapp id="launch-btn" username="gh_开头的小程序对应的名" path="">
      <script type="text/wxtag-template">
        <style>
          .btn{
            padding:12px;
            background-color: #1aad19;
            color: #fff;
          }
        </style>
        <button class="btn">打开小程序</button>
      </script>
</wx-open-launch-weapp>

五、自定义分享内容功能

// 判断是否是微信浏览器
function is_weixn() {
  var ua = navigator.userAgent.toLowerCase()
  if (ua.match(/MicroMessenger/i) == "micromessenger") {
    console.log("微信浏览器")
    return true
  } else {
    console.log("不是微信浏览器")
    return false
  }
}
function initWxConfig(param) {
  if (is_weixn()) {
    console.log("微信初始化")
  
    var myurl = location.href.split("#")[0]
    getApi("post", "后台获取wx.config所需的参数", { url: myurl }).then((res) => {
      if (res.status) {
        console.log("微信初始化接口结果:", res)
        let datad = res.data 
        wx.config({
          debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来
          appId: datad.appId, // 必填,公众号的唯一标识
          timestamp: datad.timestamp, // 必填,生成签名的时间戳
          nonceStr: datad.nonceStr, // 必填,生成签名的随机串
          signature: datad.signature, // 必填,签名,见附录1
          jsApiList: ["updateAppMessageShareData", "updateTimelineShareData"], // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
        })
        wx.error(function (res) {
          $.alert(res.msg || "微信config失败")
        })
        // initShare(param)
        wx.ready(function () {
          console.info("ready")
          //需在用户可能点击分享按钮前就先调用
          wx.updateAppMessageShareData(param)
          //需在用户可能点击分享按钮前就先调用
          wx.updateTimelineShareData(param)
        })
      }
    })
  }
}

在页面调用

  let param = {
    title: "分享标题", // 分享标题
    desc: "分享描述", // 分享描述
    link: window.location.href, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
    imgUrl: data.box_image, // 分享图标
    success: function () {
      // 设置成功
      console.log("分享设置成功")
    },
  }
  initWxConfig(param)

项目地址