2019-04-09 21:34:20 u011184307 阅读数 106
  • 德国Vue.js2终极开发教程(含Vue路由和Vuex)

    新手入门现代前端开发的不二选择 课程目标: * 学会从简单到复杂企业级应用的VueJS程序编写方法 * 能在单页和多页应用中自如使用VueJS * 真正理解VueJS的背后原理,并在真实项目中应用它们 授课计划: 23章节,21小时,341个视频,11个练习,3个工程实践;新VueJS 2.x版本,课程随版本升级。

    1924 人正在学习 去看看 Max

Vue单页在微信公众号支付里遇到的坑

微信公众平台注册地址与目标地址不准确

1、由于VUE是单页应用,并且我们用的是nuxt框架,nuxt的mode模式是history模式,并不是hash模式。所以,地址是单一的。
2、当微信链接已进入页面的时候,只会记住当前页面的地址,例如:进如页面的路径是:商城首页=>商品详情页=>填写订单页(订单页是在商户平台注册的地址即目标地址)。
3、当所有的准备都没有问题的时候,在微信支付的时候,微信支付怎么都调不起来,并且页面会报一个错误提示: 商城首页链接 未注册,我在想,当前页面是填写订单页,为什么提示商城首页链接未注册呢?后来,猜测,微信在第一次进入的时候,页面只记住了商城首页的地址,商品详情页的地址微信根本不认识,于是,在商品详情页手动刷新,再支付,就能顺利的调起支付了。如何解决,微信不认识当前地址的问题呢?
4、后来试了一些办法,最后选定location.href来强制跳转到填写订单页,这是能达到我们的预期,但是~~~
5、后来在做测试的时候,测试提了一个很蛋疼的bug。点击微信返回的时候,我们的预期返回地址是:填写订单页=>商品详情页=>商城首页,但是真实的返回地址是:填写订单页=>商城首页,这不是我们想要的。为什么会出现这种问题呢?
6、因为我们在用location.href做跳转的时候,会将nuxt的数据全部清除掉,所以在返回的时候只能记住第一次进来的商城首页。
7、最后到项目上线也没能改掉这个bug

nuxt微信支付项目学到的知识点

1、window.history.pushState() 记录页面的history
2、this.$nextTick(()=>{}),(1)、在Vue生命周期的created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中,(2)、在数据变化后要执行的某个操作,而这个操作需要使用随数据改变而改变的DOM结构的时候,这个操作都应该放进Vue.nextTick()的回调函数中
3、async和await,异步操作,

微信公众号支付,两种支付api

1、第一种是WeixinJSBridge.invoke,是在微信浏览器里面打开H5网页中执行JS调起支付。接口输入输出数据格式为JSON。具体的开发文档如下链接:
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6
2、第二种是wx.chooseWXPay,https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115
3、二者的比较,WeixinJSBridge.invoke不需要引入jssdk,wx.chooseWXPay需要引入,当前这两者都可以用,但是在实际的开发过程中用哪一个比较好呢,下面我们来做一个比较。
(1)、在做公众号支付的时候,一般用ios手机做调试,因为Android的微信版本不会有报错,
(2)、还在开发调研阶段,最好用WeixinJSBridge.invoke做调试,因为wx.chooseWXPay不会报错,例如,如果当前地址未注册,wx.chooseWXPay的表现形式是调不起微信支付,并且不会有任何反应,WeixinJSBridge.invoke则会直接显示错误的类型。
(3)、当各个环节都正确的时候,还是可以用回wx.chooseWXPay,因为wx.chooseWXPay里面封装了WeixinJSBridge.invoke,并且有成功和失败的回调,更加适合我们程序做处理。
(4)、具体的区别可以见如下链接:https://www.2cto.com/weixin/201507/412752.html

2019-01-15 18:29:42 guxuehua 阅读数 202
  • 德国Vue.js2终极开发教程(含Vue路由和Vuex)

    新手入门现代前端开发的不二选择 课程目标: * 学会从简单到复杂企业级应用的VueJS程序编写方法 * 能在单页和多页应用中自如使用VueJS * 真正理解VueJS的背后原理,并在真实项目中应用它们 授课计划: 23章节,21小时,341个视频,11个练习,3个工程实践;新VueJS 2.x版本,课程随版本升级。

    1924 人正在学习 去看看 Max

最近一年开发的项目都是微信公众号相关的,遇到了很多坑,没有发现一个相对来说完整的文档,因此自己记录一下,欢迎大家补充。

获取用户的唯一标识

    在用户与公众号产生消息交互后,公众号可获得用户的openid(加密后的微信号,每个用户对每个公众号的openid是唯一的,不同公众号,同一用户的openid不同)

    如果开发者想要把多个公众号、移动应用、小程序之前做账号的统一,则需要UnionID机制

    不管是获取openid还是unionid,前端和微信的交互流程都是一样的, 前端就直接在router.beforeEach中去判断就可以

      

1. 静默授权

       即用户无需关注 ,无需手动点击授权进入页面自动跳转到回调页,即可拿到用户的openid,用户的感知就是直接进入了回调页,scope 为 snsapi_base

2. 用户手动授权

     获取openid是需要用户手动授权方可获取,拿到openid可以换取unionid,scope为snsapi_userinfo

     注意:对于已关注公众号的用户,如果用户从公众号的会话或者自定义菜单进入本公众号的网页授权页,即使是scope为snsapi_userinfo,也是静默授权,用户无感知

 // appid 公众号的appid
 // redirect_uri 指的是在微信公众号后台 公众号设置-网页授权域名的回调中配置的
 // url 后端获取到openid后, 需要重定向到前端的url地址,如果地址是hash模式,则"#"需要用特殊字符代替,后端拼接后回跳
// scope snsapi_base为静默授权,即用户进入接口拿到openid   snsapi_userinfo需要用户手动授权才可以,不仅可以拿到openid,可以拿到用户的Unionid
 window.location.href = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${redirect_uri}&response_type=code&scope=snsapi_base&state=${url}#/wechat_redirect`

前端获取openid的方法:

  1. 将openid作为参数拼接到重定向的url中,尽管前端可以拿到,但是也有一定的问题

         弊端:但是url中拼接用户的openid有一个弊端,就是当用户把带openid的链接分享给别人,当别人进来是不会重新获取的           openid的

        解决办法:在带有openid的页面,隐藏微信的分享和复制链接的功能,但是如果用户有企业微信,依旧可以拿到该链接

    2. 将openid作为参数拼接到重定向的url中,尽管前端可以拿到,但是也有一定的问题

         后端获取到openid后直接打在cookie,然后重定向

        前提:前后端需要同一个域或者是有同一个父域,前后端需要约定好openid的字段名

jssdk功能

      分享:如果需要每个页面都需要分享自定义的图片和标题,则需要每次都调用wx.config注入一下该页面的配置信息

      其他jssdk功能:需要在wx.config中注册

      

     

 

 

 

 

2018-07-29 22:20:11 qq_34794441 阅读数 4986
  • 德国Vue.js2终极开发教程(含Vue路由和Vuex)

    新手入门现代前端开发的不二选择 课程目标: * 学会从简单到复杂企业级应用的VueJS程序编写方法 * 能在单页和多页应用中自如使用VueJS * 真正理解VueJS的背后原理,并在真实项目中应用它们 授课计划: 23章节,21小时,341个视频,11个练习,3个工程实践;新VueJS 2.x版本,课程随版本升级。

    1924 人正在学习 去看看 Max

最近接手了一个vue单页面应用的售票商城,就不可避免的要用到支付,主要讲下微信支付做的过程中遇到的哪些坑。

首先微信支付分为2部分。一个是在微信环境下的支付可以直接调用微信方法。一个是微信浏览器外的H5支付。

第一步,到支付页时判断用户当前的环境是否在微信浏览器下(用户在商品下单跳到支付页时,在支付页组件created或mounted生命周期里判断)

let ua = navigator.userAgent.toLowerCase()
if (ua.match(/MicroMessenger/i) == 'micromessenger') {}

这2段代码就是用来判断微信环境的。
这2段代码也可以在用户点击的时候判断。我放在生命周期这里的原因是需要判断支付宝在微信环境中不能使用
所有业务需要,先在生命周期里判断,然后渲染dom。

第二步,区分环境之后,先说微信浏览器的支付。
调用微信WeixinJSBridge内置对象,详细可看微信官方文档https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6

  Pay (data) {
      let vm = this
      if (typeof WeixinJSBridge === 'undefined') {
        if (document.addEventListener) {
          document.addEventListener('WeixinJSBridgeReady', vm.onBridgeReady(data), false)
        } else if (document.attachEvent) {
          document.attachEvent('WeixinJSBridgeReady', vm.onBridgeReady(data))
          document.attachEvent('onWeixinJSBridgeReady', vm.onBridgeReady(data))
        }
      } else {
        vm.onBridgeReady(data)
      }
    },
    onBridgeReady (data) {
      let self = this
      WeixinJSBridge.invoke(
        'getBrandWCPayRequest', {
          'appId': data.appId,
          'timeStamp': String(data.timeStamp),    //这里必须要转换为字符串。ios跟android表现不同。后台返回的是数值,但是微信方面必须要json参数都是字符串形式,android会自动转换成字符串(当时我在这里也找了很久的博文才知道的)
          'nonceStr': data.nonceStr,
          'package': data.package,
          'signType': data.signType,
          'paySign': data.paySign
        },
        function (res) {
          if (res.err_msg === 'get_brand_wcpay_request:ok') {
            self.$router.replace({name: 'paymentend'})
          } else if (res.err_msg === 'get_brand_wcpay_request:cancel') {
            self.$vux.toast.text('支付取消!', 'default')
          } else {
            self.$vux.toast.text('支付失败!', 'default')
          }
        }
      )
    }

这个2个方法是调起支付。再调起之前需要做2件事。
首先你需要获取用户微信授权,获得openId,当然这个过程是后台处理的。前端需要获得到code传递给后台然后返回openId给你。

if (!this.GetQueryString('code')) {
  this.$vux.toast.text('微信授权中……', 'default')
  let currentUrl = encodeURIComponent(window.location.href)
  window.location.href = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx70fed7a16aebcd2e&redirect_uri=' + currentUrl + '&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect'
} else {
  this.code = this.GetQueryString('code')
  // localStorage.setItem('user_code', this.code)
  this.getWeixinOpenID({
    code: this.code
  })
}

GetQueryString (name) {
      let url = new RegExp('(^|&)' + name + '=([^&]*)(&|$)')
      let newUrl = window.location.search.substr(1).match(url)
      if (newUrl != null) {
        return unescape(newUrl[2])
      } else {
        return false
      }
    }

直接上代码。GetQueryString 这个方法是截取当前url上参数值(比如&code=123, GetQueryString (code)获得123)

那么什么时候获取这个code呢。我个人一开始是在支付页的时候授权获得code,后来因为业务需要。在用户登录之后进入路由跳中间页微信授权登录

router.beforeEach((to, from, next) => {
  if (checkLogined()) {
    let ua = navigator.userAgent.toLowerCase()
    let userinfos = JSON.parse(localStorage.getItem('jwt'))
    if (ua.match(/MicroMessenger/i) == 'micromessenger') {
      if (!userinfos.openId && to.path !== '/login' && to.path !== '/author') {
        localStorage.setItem('beforeLoginUrl', to.fullPath)
        next({path: '/author'})
        return false
      }
    }
  }
  if (to.meta.checkLogin) {
    if (checkLogined()) {
      next()
    } else {
      Vue.$vux.toast.text('您还没未登录', 'default')
      next({path: '/login', query: {Rurl: from.fullPath}})
    }
  } else {
    next()
  }
})

localStorage.setItem(‘beforeLoginUrl’, to.fullPath) 这个段主要保存登录之后前往的路由地址。当授权成功之后再接口跳转到这个路由下

      [GETWEIXINOPENID_SUCCESS] (state, openId) {
        state.openId = openId
        let userinfos = JSON.parse(localStorage.getItem('jwt'))
        userinfos.openId = openId
        localStorage.setItem('jwt', JSON.stringify(userinfos))
        router.push(localStorage.getItem('beforeLoginUrl'))
        localStorage.removeItem('beforeLoginUrl')
      }

我的接口都是写在vuex上的。这里获得的openId必须存到本地用户数据里。因为如果用户有授权过。登录之后有带openID的数据的。没有授权过的用户是没有的。
这样下次路由跳转的时候就不会再进行授权了

好了到了这里可以说成功了一半。接下来是支付提交,支付提交之前你需要获得微信签名,

    let ua = navigator.userAgent.toLowerCase()
    let orderId = JSON.parse(localStorage.getItem('orderId')).orderId
    if (ua.match(/MicroMessenger/i) == 'micromessenger') {
      this.weixinFlog = false
      let u = navigator.userAgent
      let isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)
      if (isiOS) {
        if (sessionStorage.getItem('flag')) {
          sessionStorage.removeItem('flag')
        } else {
          sessionStorage.setItem('flag', true)
          location.reload()
        }
      }
      this.$nextTick(() => {
        this.weixinjspay({
          orderId: orderId,
          openId: this.userinfos.openId
        })
      })
    }

直接在下单之后的支付页生命周期里调用接口获得签名数据,这里你需要对ios特别处理一下。 因为ios跟Android表现不同
https://blog.csdn.net/sky_beyond/article/details/54312433 具体哪里不同可以参考这里。我的处理方法是ios进入支付页时刷新一次。这里的处理方法我看到的有2种,一种是我这样的,另一种是#前加?,查了一些资料说#前加?的不太友好而且具体操作相关的没有找到。我就采取了刷新的方法。对用户而言没影响,感受不出来。,这样处理之后安卓跟ios的支付安全域名一样了。

到这里差不多就结束了,点击支付的时候调用pay方法,传入获得的签名参数就可以了。支付回调相信你们都明白的这里就不提了。如果有报什么错误。在回调里打alert(JSON.stringify(res))会弹出具体报错信息。报错信息处理可以到官方文档查阅。

然后微信浏览器外的h5支付。这里另外抱怨一下,我当初做的时候,因为接口有问题,找了很久的资料查没有成功的问题原因。结果是接口有问题。所以有时候多跟后台沟通很重要。(PS:这个项目因为是私活,所以沟通比较困难,一度奔溃)。

其实h5支付很简单。前端不需要做太多事情。

let url = '&redirect_url='+encodeURIComponent('http://wap.singlook.net/#/home/rushbuy/payment/paymentend')
window.location.href = data.mweb_url + url

这里直接贴上代码。 通过后台接口,后台会传回来一个mweb_url的地址你直接跳转就可以唤起微信并支付
https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=15_4具体看开发文档。我就不把文档里的摘出来了。

这2段代码 第一段是我的回调地址。支付成功或取消支付都会回跳这个地址。
这里回报2个常见错误。

一个是网络环境未能通过安全验证,请稍后再试,这个错误找后台就行了。后台处理,要么后台的代码问题要么是服务器代理问题。
第二个是商家参数格式有误,请联系商家解决,
这个问题是我最头疼的。官方文档的解释是:

  1. 当前调起H5支付的referer为空导致,一般是因为直接访问页面调起H5支付,请按正常流程进行页面跳转后发起支付,或自行抓包确认referer值是否为空

  2. 如果是APP里调起H5支付,需要在webview中手动设置referer,如(
    Map extraHeaders = new HashMap();
    extraHeaders.put(“Referer”, “商户申请H5时提交的授权域名”);//例如 http://www.baidu.com ))

因为我是手机浏览器里打开的网页,所以就看问题1,referer为空导致。当时真的是翻遍了所有的资料都没找出问题所在。最后是项目带头人在我的index.html上看到了这么一句, 我当时就是一张黑人问号脸。我什么时候写过这一句代码? 一直也没往这方面想,所以一直想不通为什么整个项目路由都没带上referer,本以为单页面应用的原因。所以大家如果碰到这个问题。首先先看下index.html上是否带有这句话,我深刻怀疑是脚手架vue-cli下过来的时候自带上的!!!!

2019-11-07 15:59:59 leafpanye 阅读数 12
  • 德国Vue.js2终极开发教程(含Vue路由和Vuex)

    新手入门现代前端开发的不二选择 课程目标: * 学会从简单到复杂企业级应用的VueJS程序编写方法 * 能在单页和多页应用中自如使用VueJS * 真正理解VueJS的背后原理,并在真实项目中应用它们 授课计划: 23章节,21小时,341个视频,11个练习,3个工程实践;新VueJS 2.x版本,课程随版本升级。

    1924 人正在学习 去看看 Max

Vue单页面开发的一个文章小应用,打开先跳转到授权页面,授权成功后跳转到文章列表页,然后再跳转到文章详情页,当通过微信自带分享功能分享文章出去后,别人点击链接会出现授权问题的坑,以及单页面哈希路由无法正确跳转详情页的坑。

 data() {
    return {
      configInfo: {},
      newDetailObj: {
        img_url: '',
        title: '',
        desc: '',
      },
      linkUrl:'',
    }
  },
wx.onMenuShareAppMessage({
   title: _this.newDetailObj.title, // 分享标题
   desc: _this.newDetailObj.desc, // 分享描述
   //link: window.location.href.split('#')[0], // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
   link: _this.linkUrl, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
   imgUrl: _this.newDetailObj.img_url, // 分享图标
   type: '', // 分享类型,music、video或link,不填默认为link
   dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
   success: function (res) {
   // 用户确认分享后执行的回调函数
   console.log("分享给朋友成功返回的信息为:",res);
   },
   cancel: function (res) {
   // 用户取消分享后执行的回调函数
   console.log("取消分享给朋友返回的信息为:",res);
   }
});

首先,分享的链接不能直接通过window.location获取,需要经过加工,因为“#”后面的内容会自动被屏蔽,所以可以通过某个标识名称,将参数传过去。例如:

var linkUrl = 'https://api.xxxxxxx.com/mp/message?path=messagedetailaaamessageId='+messageId
              
_this.linkUrl = linkUrl

然后,分享的页面中进行判断

var path = getUrlParam('path');

if (path != undefined || path != null) {

} else {

}

如果path不为空的话,对url进行重组,然后重定向到文章详情页。

注意:分享的页面也会先跳转到授权页面,授权的时候也要判断一下链接来源是通过正常途径还是分享途径,微信授权规则还是很严谨的,各个参数的顺序不要随意更换,注意"#",防止出现奇奇怪怪的BUG。。。

2017-05-03 17:32:33 baidu_31333625 阅读数 1893
  • 德国Vue.js2终极开发教程(含Vue路由和Vuex)

    新手入门现代前端开发的不二选择 课程目标: * 学会从简单到复杂企业级应用的VueJS程序编写方法 * 能在单页和多页应用中自如使用VueJS * 真正理解VueJS的背后原理,并在真实项目中应用它们 授课计划: 23章节,21小时,341个视频,11个练习,3个工程实践;新VueJS 2.x版本,课程随版本升级。

    1924 人正在学习 去看看 Max

项目中要在微信底下开发单页应用(SPA),前端技术选型用的vuejs+vue-router,vue-router使用hashbang模式(使用hashbang也是为了避免微信jssdk的wx.config签名的坑)。在调用微信支付的时候遇到提示“URL未注册”,这通常是因为没有在微信支付后台正确配置授权目录的问题,但我所遇到的并非如此。

我们的应用中有3个页面用到微信支付:

http://example.com/#!/cart/index
http://example.com/#!/order/orderlist
http://example.com/#!/order/orderinfo

微信支付允许配置3个目录为授权目录,另外允许配置一个测试环境目录,授权目录必须配置到最后一级目录,配置在根目录不行。到这里其实还都不是问题,问题是微信判断当前路径的方式。

我们先定义两个名词:首先把当前页面叫做“Current Page”;当我们从微信别的地方点击链接呼出微信浏览器时所落在的页面、或者点击微信浏览器的刷新按钮时所刷新的页面,我们叫做“Landing Page”。举个例子,我们从任何地方点击链接进入页面A,然后依次浏览到B、C、D,那么Current Page就是D,而Landing Page是A,如果此时我们在D页面点击一下浏览器的刷新按钮,那么Landing Page就变成了D(以上均是在单页应用的环境下,即以hashbang模式通过js更改浏览器路径,直接href跳转的不算)。

问题来了,在ios和安卓下呼出微信支付的时候,微信支付判断当前路径的规则分别是:

  • IOS:Landing Page
  • 安卓:Current Page

这个规则是我试了N次试出来的,非常的坑,这就意味着,在ios环境下,任何一个页面都有可能成为支付页面(因为我无法预知和控制用户在哪个页面点微信浏览器的刷新按钮,或是用户通过哪个连接从外部进入到系统)。我在网上用了各种方式搜索这个问题的解决方案,都没找到好的,有关这个问题的帖子都少之又少,都只有吐槽它而没有解决了的。

我把这个问题放了好几天,虽然有一个解决方案,就是进入到支付页面的时候使用href跳转的方式,会造成页面刷新,影响一些用户体验。就是因为这个方案不完美,我就一直搁着,今天呢就又把这个问题拿出来鼓捣。

今天不知道怎么来了灵感,寻思我靠这个不对啊,

http://example.com/#!/cart/index

这个页面的目录应该是

http://example.com/

井号“#”后面应该都忽略才对。于是乎,我想了想,反正入口文件就是个静态html,服务器端也不直接接收query,于是就把链接改成了

http://example.com/?#!/cart/index

就加了一个问号,于是微信浏览器妥妥的把井号“#”后面的内容给去掉了,(╯‵□′)╯︵┻━┻

这个困扰了好几天的问题,最后用一个问号解决了,这不禁让我想起小时候老师讲的斯坦梅茨的故事:

没有更多推荐了,返回首页