背景
- 由于第一版是基于端上 Windvane 做的跨页面选址工具,社区内有不少同学希望做个支持纯H5的版本
- 这也是我在一期时候的待完善计划之一 一期:基于 高德 + Windvane 的选址工具,对高德选址组件说:拜拜
一期端版本基础功能
整个选址工具做成一个单独维护的项目,通过端上能力,跨页面访问,通信并返回最终数据结果。
功能分析
其中借助端上的能力有:
- openPage 新开页面
- exitPage 退出容器
- getLocation 获取(火星坐标)经纬度
- nativePostMsgToJs 通信手段
替代方案思考
1. 原openPage、exitPage 的功能实现
- 先想到的是router新开路由、回退路由来模拟(N) 原因:页面进退会触发刷新,对表单场景不友好,页面需要缓存体验不好,通信繁琐可能出问题
- 放入弹框里,控制弹框开关渲染地图(N) 原因:有点死板,可定制程度不够,需要自己单独写完整调用流程
- 嵌入iframe ,控制iframe 的加载和移除(Y) 原因:避免了新开页面的弊端,可自定义iframe渲染位置,为后面通信做铺垫
2. 原getLocation 的功能实现
端版本做的时候,是为了尽量精确的获取到当前坐标,所以通过端获取实时的火星坐标
2.1 存在问题:
- 弱网情况下高德,回到当前位置的Api 会存在延迟
- 回到当前位置的logo对乡村老人而已不够明显,调用也存在延迟
- 坐标精度不够高
2.2 方案
- 页面刚渲染时候,通过Api先获取坐标,存起来后期只操作坐标保证后面的操作不卡顿
- 模拟返回当前位置,并给出明显提示,剔除了每次点击调用Api的延迟问题
- 获取坐标Api的参数进行精度参数配置
3. 原nativePostMsgToJs 通信手段的实现
因为这个选址工具我是作为单独项目维护,所以调用时参数都是通过url传递
- 使用本地缓存通信也是可以的,但存在局限性(菜鸟域名),不够灵活 在上面模拟端上容器渲染时采用了iframe进行加载,也是考虑到跨项目之间的通信问题 所以采用了postMessage 来进行通信,保障所以业务项目都能使用
// 动态创建或写死一个iframe 加载组件
const addIframe = useCallback(
(data) => {
let url = `${mapEnv}?h5=true&key=${data.key}&desc=${data.desc}&v=${data.v}&title=${data.title}&zoom=${data.zoom}&serverKey=${data.serverKey}&location=${data.location}#/`;
var iframe = document.createElement('iframe');
iframe.src = url;
document.body.append(iframe);
},
[]
);
const onCancle = () => { }
const onOk = () => { }
const cbMessage = useCallback(
(e: any) => {
console.log(e.data, 'eeeeecb---Message');
if (!e || !e.data) {
return;
}
if (e.data.cancle) {
onCancle();
} else {
onOk(e.data);
}
},
[onCancle, onOk]
);
useEffect(() => {
addIframe(data)
window.addEventListener('message', (e) => cbMessage(e), false);
return window.removeEventListener('message', (e) => cbMessage(e), false);
}, [data,cbMessage]);
深度优化封装
虽然整个地图被封装成了单独的模块,但对于使用纯H5版本的用户,使用起来还是有一丢丢麻烦。 考虑到--尽量让使用者开箱即用,不考虑多余的逻辑处理,所以为H5使用者单独封装了个组件包。
1. map-site
2. 该组件提供的能力
- 地图自定义渲染区域
- 端版本所有的能力参数配置
- 统一iframe的唤起和销毁
- 统一的通信方式和事件回调
// 调用方式
import H5Map from '@alife/map-site'
<H5Map
id="h5_iframe"
visible={visible}
showArea="my_map"
params={{
key: 'fb0cf7c70e6d139a2fe7d4b02af40a46',
desc: '11如未选中周边信息,最终以标记点坐标为准。',
v: '2.0',
title: '选址demo',
zoom: '15',
serverKey: '8e5a71262cda4c03862279b0b9849515',
location: result ? result.location : '120.154066,30.290777',
}}
onCancle={() => {
setVisibile(false);
console.log('on calcle');
}}
onOk={(e: any) => {
setResult(e);
setVisibile(false);
console.log(e, 'onOk cb');
}}
/>
这样大家就不需要关注多余的逻辑处理,全部交给这层中间组件进行统一处理
3. 效果图展示
整体的样式跟端版本是一样的,尽量抹平差异保持一致
3.1 局部自定义区域渲染(自定义渲染id)
3.2 全屏渲染(默认全屏渲染)
欢迎大家接入体验,提出宝贵意见
整体的样式跟端版本是一样的,尽量抹平差异保持一致
@alife/map-site
@alife/map-site:https://web.npm.alibaba-inc.com/package/@alife/map-site