应项目需求,需要将H5内嵌在小程序壳子里。通过小程序授权登录的方式进入H5商城(vue项目)

那么需要用到的就是微信小程序的webview组件啦~~说实话,看官网文档介绍的赶脚不是特别复杂,但实操过程中遇到各种小坑,有的时候开发者工具内可以实现的功能,真机上无法运行。

心累累滴~~本地改版的内容收益最大的是收货地址模块(小程序与H5地图交互功能)以及分享功能,所以,想分享下自己开发中遇到的问题希望对大家有帮助哦~~~


  1. 判断当前运行环境,不允许之前的H5商城在微信浏览器端打开,借鉴官网提供的方法:https://developers.weixin.qq.com/miniprogram/dev/component/web-view.html

在运用的时候,一开始用的是getEnv方法,但没有效果,不知道是什么原因。查了资料,和网友很分享的写法一样,后来没折腾了。换了第一种方法在WeixinJsBridgeReady回调,当浏览器打开是会提示当前不是小程序环境,在小程序中打开ok。

注意: 使用时要引入jssdk1.3.2~~~,项目中在main.js中引入的,当然如果你也是vue项目的话,可以npm install weixin-js-sdk,安装成功后在package.json文件中可以看到,再main.js中引入即可,两种方法都可以,该项目中选择的是后者。


下面上代码:

 

2.小程序授权登录将H5商城之前的微信登录授权改成从小程序入口登录授权。该功能不用多说,做过小程序的盆友都烂熟于心啦。既然是从小程序登录,逻辑就在小程序页面内实现,所以先把商城项目之前调微信登录的逻辑给干掉咯,哈哈哈~~

下面上代码:

首先是调取用户信息授权窗口,目前小程序只能用button触发,这个大家都知道的。。。

触发按钮后调起授权登录窗口,获取当前用户信息(昵称,头像,城市,省份,iv。。。),当用户点击授权确按钮时,

触发login方法

因接口需要,登录时把当前的userToken进行缓存。当然,每次登录都需要清除缓存哦~

进入首页使用webview组件实现,大家注意:跳转的网页地址需要加密,在商城首页接受时需要解密,这是webview的一个坑点!!!


3.webview实现分享功能,官网提供的方法了解下:

https://developers.weixin.qq.com/miniprogram/dev/component/web-view.html

介绍的很简洁,大致思路就是这样的。运用到项目中如下图所示:


4.webView与H5网页实现地图交互,敲黑板,,,,,,,

下面详细说下发生的一系列故事吧。一开始用的是腾讯地图组件,实现点击详细地址后,显示地图可以搜索定位选择某个地址带回到文本框内。方法很简单,之前在腾讯位置服务平台使用到的地图组件申请一个key,再结合提供的demo例子,几分钟解决。

下面上代码:

实现的页面风格就是以下这种:

没毛病,腾讯地图组件代码简洁,用的也很方便。。但是!在webview组件里使用地图组件(不管是腾讯,百度还是高德)都会受到一个限制阻碍。小程序后台管理需要添加业务域名,刚刚使用的腾讯组件域名为apis.map.qq.com,无法添加到开发小程序的业务域名中,查资料看社区,发现这个bug官方回复暂不支持。此路不通,需要找其他的方法去实现地图选址功能。

下面说说如何在webview中实现H5与小程序地图api的交互吧

 

1.H5页面中需要在触发选择地址按钮的时候跳转到小程序指定的map页面,唤起小程序地图

2.小程序内创建map文件,通过调用getLoction,chooseLocation调起地图组件并选择相关地址

<!--pages/map/map.wxml-->
<view>
    <web-view src="{{web_src}}"></web-view>
</view>
Page({

    /**
     * 页面的初始数据
     */
    data: {
        mapUrl: '',
        mapDataStr: ''
    },

    /**
     * 生命周期函数--监听页面加载
     */
    onLoad: function (options) {
        // 解析当前H5网页的url
        // 页面跳转过来时把收获地址的信息传递过来,以免H5跳转到小程序内选择完地址后,再次刷新页面,导致你填写的联系人,电话号码等信息被清空。
        mapUrl为收获地址的url(https://xxx.xxx.com/Addrress)
        mapDataStr打印出来为带过来的参数信息?addressId=10&name=hhhhhh&mobile=13023212132)

        var returnUrlArr = decodeURIComponent(options.returnUrl).split('?');
        this.setData({
            mapUrl: returnUrlArr[0],
            mapDataStr: returnUrlArr[1]
        })
    },
    
    onReady:function(e){
        this.mapCtx = wx.createMapContext('myMap');
        this.getCenterLocation();
    },

    getCenterLocation(){
        let that = this;
        wx.getLocation({
            type: 'wgs84', //返回可以用于wx.openLocation的经纬度
            success: function(res) {
                // 如果打开地图没有选择地址则跳转到原H5页面,否则选择地址后再进行跳转
                    let latitude = res.latitude
                    let longitude = res.longitude
                    wx.chooseLocation({
                        latitude: latitude,
                        longitude: longitude,
                        scale: 28,
                        success: function (res) {
                            var getUserInfos = wx.getStorageSync('userInfo')
                            var userToken = wx.getStorageSync('userToken')
                            var returnDataStr = that.data.mapDataStr + '&avatarUrl=' + encodeURIComponent(getUserInfos.avatarUrl) + '&nickName=' + getUserInfos.nickName + '&address=' +res.address + '&addNameInfo=' + res.name + '&userToken=' + userToken + '&longitude=' + res.longitude + '&latitude=' + res.latitude ;
                            var returnUrl = encodeURI(that.data.mapUrl +"?"+ returnDataStr);
                                that.setData({
                                    // 携带选择地址res.address返回到H5页面中
                                    web_src: returnUrl
                                })
                        },
                        fail: function(res) {
                            wx.navigateBack({
                                delta: 1
                            })
                        }
                    })  
            },
        })
    },
})

3.主要的逻辑在小程序中实现滴。大概思路就是这样的了。webview传参基本都是在跳转的url后紧跟着。如果像我这样传参较多的情况下,写成一个对象从url上来回传值,当然。需要把变成字符串对象传值哦。并且参数需要进行加密(encodeURIComponent),在接受页面的地方进行解密(decodeURIComponent)即可。webview的src需要加密一下哦。如上图代码所示(encodeURI),在H5页面中接受需要解密:

// 选择地址后返回页面保存地址信息,用户信息,userToken
    getQueryMapString() {
      var _this = this;
      let searchStr = decodeURI(window.location.search);
      searchStr = searchStr.substring(1, searchStr.length);
      let searchArr = searchStr.split("&"); // 分割成字符串数组 
      let searchData = {};
      searchArr.forEach(ele => {
        let eleArr = ele.split("=");
        // 此处是对当前的url中参数进行解密操作
        if (
          eleArr[1].indexOf("%E6") >= 0 ||
          eleArr.indexOf("%E5") >= 0 ||
          eleArr.indexOf("9B") > 0
        ) {
          searchData[eleArr[0]] = decodeURIComponent(eleArr[1]);
        } else {
          searchData[eleArr[0]] = eleArr[1];
        }

        // 小程序页面带过来的信息
        _this.newAddress.address = searchData.addNameInfo;
        _this.lat = searchData.latitude;
        _this.lng = searchData.longitude;
        _this.userToken = searchData.userToken;
      
        // 缓存UserToken
        if (_this.userToken) {
          axios.defaults.headers.common["User-Token"] = _this.userToken;
        }
      });
    },

在开发工具中因勾选了不校验合法域名那栏,导致真机上存在的问题,在开发者工具中无法复现。

所以在开发过程中,一定要多用手机测试。当然,webview的坑必须线上测才有真实体验。发现bug,体验版本不一定能测出来。


正如,在小程序中点击导航栏回退按钮,如果你尝试一下,地图点击取消的时候,会出现空白页,再次回退才能跳到进入小程序之前的H5新增收货地址页面。所以,在倒数第三张图中,加了一个fail方法:没有选择任何地址只是唤起地图的场景,点击小程序导航栏回退按钮,则回调到上级操作页面。很方便哦~~

目前上线版本也很实用,没有出现什么bug。只是觉得webview跳转到H5链接会有些许的延迟卡顿。不过正常浏览速度还是可以的,希望以上整理内容对大家有点帮助呢。后期将开发网页商城与小程序的支付交互功能,到时再更新~

Logo

前往低代码交流专区

更多推荐