微信小程序和webview通信踩坑(表单篇)

3 篇文章 0 订阅
2 篇文章 0 订阅

背景

为了适配多端小程序,通用的功能一般采用webview的方式引入小程序,这次的移动管理端也不例外。

需求

h5表单的地图选择功能。如下所示:
webview地址选择需求
拉起地图

可行性分析

方案:

  1. 引入第三方地图
  2. 使用微信sdk的地图选择功能
  3. 采用跳转至小程序,使用小程序中的地图

分析:

  1. 方案一采用第三方地图在浏览器中没有问题,但是通过小程序的webview打开会出现提示无法打开该页面,大概率和小程序安全业务域名相关,先不考虑该做法。
  2. 方案二采用微信sdk直接拉起地图,但是经查询没有选择位置的方法,只有定位自身位置和打开地图的方法,也不考虑该做法。
  3. 方案三在小程序中单独写一个地图页面用来选择地图,选择完后进行和h5通信,实现该功能。(适合)

方案定为第三种,主要的难点在小程序和h5如何通信以及保留通信完成后原先填写的表单数据。

具体实现

  • webviewH5 --> miniProgram

通过js调用微信JSSDK的wx.miniProgram.navigateTo方法跳转到小程序的指定页面并且把参数当做query带给小程序原生页面。

  • miniProgram --> webviewH5

webview组件存在一个src属性, 用于展示指定的h5页面,通过操作当前src的hash值,当前组件上的页面是不会刷新的,webview的h5页面利用hashchange监听事件获取小程序传过来的值。

注意点:

  • webview 中的 console 并不会再微信开发者工具的控制台打印,alert才可以,打开了微信开发者工具中的 webview 的调试工具,那么 console和 alert 都不会执行。(大坑,开发效率特别低,建议不使用webview开发调试工具,只通过alert调试)
  • hash改变虽然当前组件上的页面是不会刷新的,但是js需要重新调用,也就是说useState会清空,form表单会清空。需要在跳转到小程序页面前保存当前的form所有的状态数据,可以保存在redux或者浏览器本地存储,在小程序跳转回h5的时候取出重新setState。
  • h5页面在跳转到小程序的时候将当前页面的完整url传递至小程序,实测获取当前h5页面完整url传递至小程序,query并不会成功,需要单独处理。

具体难点代码层面(Taro+react)

  • map页面具体实现
import Taro, { getCurrentPages, useRouter } from '@tarojs/taro';

const Map = () => {
  const { params } = useRouter();
  const { src, isParty, type, id } = useRouter().params; // 分别获取path以及所有的query
  Taro.getLocation({
    type: 'gcj02', //返回可以用于 Taro.openLocation的经纬度
    success: ({ latitude, longitude }) => {
      Taro.chooseLocation({
        latitude,
        longitude,
        success: (res) => {
          const pages = getCurrentPages();
          const prevPage = pages[pages.length - 2]; // 上一个页面,也就是页面A
          prevPage.setData({ ...res, src, isParty, type, id }); // 将信息set到上个页面也就是webview的Data中
        },
        fail: () => {},
        complete: () => {
          Taro.navigateBack(); // 确定取消按钮统一返回上个webview页面
        },
      });
    },
  });
};
export default Map;
  • webview具体实现
import { useRouter, useDidShow, getCurrentPages } from '@tarojs/taro';
import { View, WebView } from '@tarojs/components';
import { connect } from 'react-redux';
import { useState } from 'react';
import { setRegionId } from '@/store/actions/index';
import { formatQuery } from '@/utils/formatQuery'; // 将对象转换为query模板 如:{a=1,b=2} => '?a=1&b=2'

const mapStateToProps = (state) => ({
  token: state.token,
  regionId: state.regionInfo.regionId,
});
type WebviewProps = {
  token: string;
  regionId: number;
  setRegionId: Function;
};

const mapDispatchToProps = (dispatch: (params: any) => void) => ({
  setRegionId: (regionId: number) => {
    dispatch(setRegionId(regionId));
  },
});
const Webview = (props: WebviewProps) => {
  const router = useRouter();
  const [src, setSrc] = useState('');
  // 添加用户token和regionId
  const getSrc = (src: string) => {
    const url = `${src}pages/index/index?token=${props.token}&regionId=${props.regionId}`;
    updataUrl(url);
  };

  const updataUrl = (url: string) => {
    setSrc(url);
  };

  const handleMessage = (res) => {
    // 目前只处理regionId,保持webview的地域选择和小程序一致
    const messageArr = res.detail.data;
    const lastMessage = messageArr[messageArr.length - 1];
    props.setRegionId(lastMessage.regionId);
  };

  useDidShow(() => {
    const pages = getCurrentPages();
    let currPage = pages[pages.length - 1]; // 获取当前页面
    const { address, errMsg, latitude, longitude, name, src, isParty, type, id } = currPage.data;
    if (errMsg === 'chooseLocation:ok') {
      let newSrc = String(`${router.params.src}`); // 添加活动地址
      newSrc += src.substring(1);
      newSrc += `${formatQuery({ isParty, type, id })}`;
      newSrc +=
        '&__callback=1&addressData=' + JSON.stringify({ address, latitude, longitude, name });

      newSrc += '&' + Math.random(); // 当需要多次通信时,避免src没有变化导致hashchange失效

      updataUrl(encodeURI(newSrc));
    } else {
      getSrc(router.params.src as string); // 初始化的操作
    }
  });

  return (
    <View>
      <WebView src={src} onMessage={handleMessage} />
    </View>
  );
};

export default connect(mapStateToProps, mapDispatchToProps)(Webview);

总结

总的来说思路清晰实现不难,注意一些细节以及一些小坑,实现起来还是比较容易的。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值