ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

地图找岗一拖地图就疯狂请求?regionchange 视口搜索 + marker 分批渲染,我调了一周

地图找岗一拖地图就疯狂请求?regionchange 视口搜索 + marker 分批渲染,我调了一周 地图找岗一拖地图就疯狂请求regionchange 视口搜索 marker 分批渲染我调了一周导读招聘小程序里做了附近工作地图页第一版地图一拖动就咔咔发请求marker 一次画几百个直接卡死。后来重构成半径优先、无界则视口搜索配上防抖和分批渲染才稳住。这篇把地图页的几个关键设计拆开讲。先交代背景。我们的求职小程序有个地图找岗页用户在地图上拖动、缩放地图范围内的岗位实时刷新底部还有岗位卡片面板。需求听起来简单坑全在细节里。第一版上线当天就被吐槽地图每挪一下发 3 个请求marker 画 500 多个微信小程序直接掉帧。我看了下代码regionchange 没做节流fetch 一次拉全部数据markers 一次性 setData——全是反面教材。设计一半径优先无界才走视口地图搜索的请求参数不能只有一套逻辑。有半径的时候比如选了 3km以定位点为中心搜索半径内结果固定选了不限才用当前可视区域视口 bbox搜索拖动地图就重新拉buildParams(){constparams{...this.query};if(this.currentRadiusKm!null){// 半径搜索中心点 半径params.latitudethis.query.latitude;params.longitudethis.query.longitude;params.radiusKmthis.currentRadiusKm;params.minLatundefined;params.maxLatundefined;params.minLngundefined;params.maxLngundefined;}elseif(this.useBboxthis.bbox){// 视口搜索把可视区域的四个角传给后端params.radiusKmundefined;params.minLatthis.bbox.minLat;params.maxLatthis.bbox.maxLat;params.minLngthis.bbox.minLng;params.maxLngthis.bbox.maxLng;}returnparams;}视口 bbox 从 map 组件的getRegion()拿解析成西南/东北两个角的经纬度exportfunctionparseMapRegion(region){if(!region||!region.southwest||!region.northeast)returnnull;return{minLat:String(region.southwest.latitude),maxLat:String(region.northeast.latitude),minLng:String(region.southwest.longitude),maxLng:String(region.northeast.longitude),};}设计二regionchange 必须防抖 状态过滤地图拖动过程中regionchange会触发很多次begin 一次、end 一次缩放还会再触发。我只在type end时处理而且加了三个过滤条件onRegionChange(e){constdetaile.detail||e;if(detail.type!end)return;// 只关心拖动结束if(this.skipNextRegionFetch){// 代码主动挪图跳过本次this.skipNextRegionFetchfalse;return;}if(detail.causedByupdate)return;// 数据更新引起的跳过if(this.regionChangeDebounced){this.regionChangeDebounced();// 450ms 防抖}}skipNextRegionFetch这个标志很重要——代码里 includePoints 把地图拉到某个视野时也会触发 regionchange如果不跳过就会和刚才的请求互相打架。每次主动mapCtx.includePoints前都置 truefitMapToMarkers(){if(!this.mapCtx||!this.list.length)return;constpointsbuildIncludePoints(this.list);if(!points.length)return;this.skipNextRegionFetchtrue;this.mapCtx.includePoints({points,padding:[this.mapPaddingTop,36,this.mapPaddingBottom,36],});}防抖工具函数就 10 行exportfunctiondebounce(fn,delay450){lettimernull;returnfunctiondebounced(...args){if(timer)clearTimeout(timer);timersetTimeout(()fn.apply(this,args),delay);};}设计三marker 构建 微信端分批渲染marker 不是简单把岗位坐标填进去就行要控制数量、选中态、气泡样式。我们的构建函数把选中和未选中的 marker 视觉做了区分选中那个 zIndex 提到 99气泡常显exportfunctionbuildMarkersFromPosts(posts,selectedId,options{}){return(posts||[]).map((item,index){constlatparseFloat(item.latitude);constlngparseFloat(item.longitude);if(isNaN(lat)||isNaN(lng))returnnull;constselectedselectedId!nullString(selectedId)String(item.id);constmarker{id:Number(item.id)||index1,latitude:lat,longitude:lng,iconPath:/static/images/im/location.png,width:selected?36:30,height:selected?36:30,zIndex:selected?99:1,callout:{content:(item.salaryText?${(item.title||岗位).substring(0,14)}\n${item.salaryText}:item.title),display:selected?ALWAYS:BYCLICK,bgColor:selected?#007aff:#ffffff,color:selected?#ffffff:#333333,},};if(options.enableCluster!false)marker.joinClustertrue;returnmarker;}).filter(Boolean);}微信端还有个坑一次 setData 塞 500 个 marker 会卡死。小程序地图支持joinCluster聚合把 marker 丢给原生层去聚合几百个点也能流畅。设计四底部面板拖拽 定位按钮的细节地图页不只有地图底部还有个岗位列表面板支持收起/展开/拖动。这块看起来简单但面板高度和地图 padding 是联动的——面板展开多少地图可视区域就要让出多少不然 marker 会被面板挡住updateMapViewportPadding(){// 面板收起时地图底部留 240px展开时让更多this.mapPaddingBottomthis.panelExpanded?this.windowHeight*PANEL_EXPANDED_RATIOMAP_FLOAT_CARD_RPX:PANEL_COLLAPSED_RPXPANEL_COLLAPSED_EXTRA_PX;}面板拖拽用的是touchstart/touchmove/touchend三件套拖动时实时改panelHeightPx松手后吸附到最近的档位收起或展开不要做那种拖到哪停哪的自由面板手势结束没有吸附用户会觉得很飘。定位按钮也踩过坑。一开始点定位直接getLocation拿坐标就刷新后来发现用户在地图上手动拖到别处了点定位应该回到当前所在城市而不是上次的定位点。现在的逻辑是先判断有没有城市信息有就切回城市中心没有才重新定位并且skipNextRegionFetch true防止地图移动又触发一次拉取relocate(){loGetLocation((){if(this.locateInformationthis.locateInformation.location){this.applyUserLocation(this.locateInformation.location.lat,this.locateInformation.location.lng);this.skipNextRegionFetchtrue;this.fitMapAfterFetchfalse;this.fetchMarkers();}},()this.$u.toast(定位失败),true,false);}踩坑记录H5 端 cover-view 把地图盖死了问题现象radius 选择条和定位按钮在小程序端是cover-view浮在地图上一切正常切到 H5 调试浮层全部不见了地图整块白屏。排查过程查页面结构cover-view在 H5 端渲染成普通 view但样式还是按小程序写的定位和层级全乱。再看控制台map组件在 H5 走的是 div 高德 JS APIcover-view 组件直接不兼容。定位思路同一套页面跑多端地图浮层必须条件编译分开写。小程序用 cover-view 盖地图没问题H5 要用普通 view 绝对定位。最终解决模板里#ifdef MP-WEIXIN和#ifndef MP-WEIXIN各写一套浮层H5 版用 view 叠在地图上层样式单独调。从此多端一致再没出过浮层消失的问题。可复用清单半径优先、无界走视口请求参数两套逻辑别混着传regionchange 只在type end处理加skipNextRegionFetch防止自己挪图触发自己刷新防抖 450ms 是地图拖动的安全值太快浪费请求太慢体感卡marker 批量渲染优先joinCluster聚合别硬塞 setData跨端浮层用条件编译分开实现cover-view 只在微信端用。地图找岗是小蓝直聘移动端的核心页面之一。项目源码https://gitee.com/gzqkl/job-uniapp
返回列表