最近在做一个需求,当用户放大地图到某个级别时,自动显示marker的callout标签,当小于这个缩放级别时,则隐藏callout。然而在我实现的过程中,却发现一个严重的问题:当我操作marker数据时,会导致地图的缩放级别发生变化(用户没有缩放的操作)。这TM是什么鬼??接下来就开始爬坑。

官方的避坑指南

在mpvue的文档中,官方是给出一些避坑指南的:

列表中没有的原生事件也可以使用例如 bindregionchange 事件直接在 dom 上将bind改为@,同时这个事件也非常特殊,它的 event type 有 begin 和 end 两个,导致我们无法在handleProxy 中区分到底是什么事件,所以你在监听此类事件的时候同时监听事件名和事件类型既 <map @regionchange="functionName" @end="functionName" @begin="functionName"><map>

如果你发现@regionchange没有触发,十有八九是掉到这个坑里面了。

map组件类似一个特殊的表单元素

然而上面的指南跟我遇到的问题没什么关系,我们还是要继续分析。map组件的操作很多,比如拖动,缩放,点击等。当用户进行拖动和缩放操作时,都会触发regionchange事件,如果我们绑定了scale,latitude或者longitude属性,像下面这样:

 <map
id="map"
:markers="markers"
:scale="scale"
:latitude="latitude"
:longitude="longitude"
@callouttap="goToClass"
@end="regionchange"
@begin="regionchange"
@regionchange="regionchange"
show-location
style="width: 100%; height: 100vh">

1.当我们绑定了这些属性(scale,latitude,longitude)等,2.用户进行了缩放操作,3.再去进行数据操作,就会出现上述bug。

将上诉三个条件合起来分析可以得出,这是由于mpvue和小程序的数据没有保持一致引起的。当用户进行了缩放和移动操作时,其实scale数据已经更新,然而vm中的数据并没有相应的更新,在再次进行数据操作时,会导致旧的scale数据覆盖小程序的scale,发生改动的是marker数据,缩放级别也被更新了的bug。

所以在用户缩放操作时,需要监听相应事件,手动更新vm中的相应的数据,来维持vm和小程序中的数据同步。不然会造成mpvue实例的数据和小程序的实际缩放数据不一致。换句话说,map组件可以类比<input>元素,在input元素中,通过:value来设置数据,通过@input来更新vm的数据,从而保证vm中的数据和DOM中元素数据的一致性。所以在map中也一样,也要在regionchange中更新vm的数据来保证数据的一致性:

methods: {
regionchange: (e) => {
this.ctx.getScale({// this.ctx是MapContext对象的引用 https://developers.weixin.qq.com/miniprogram/dev/api/map/MapContext.html
success: (res) => {
this.scale = res.scale
}
})
this.ctx.getCenterLocation({
success: (res) => {
this.latitude = res.latitude
this.longitude = res.longitude
}
})
}
}

通过上面的代码,保证了vm数据和小程序的数据同步,避免了操作marker数据时,将旧的longitude,scale,latitude数据传给小程序,造成在用户没有缩放操作的情况下地图被缩放。问题是解决了,但是为什么我改变的是markers的数据,mpvue会将longitude这个数据也一起传给小程序呢,咱们继续

mpvue的setData设计

Taro 1.0发布时,提到了小程序 setState 性能优化:

在 setData 之前进行了一次数据 Diff,找到数据的最小更新路径,然后再使用此路径来进行更新

这个其实也是mpvue的一大痛点,我们来看一下mpvue的相关源码:

export function updateDataToMP () {
const page = getPage(this)
if (!page) {
return
} const data = formatVmData(this)
throttleSetData(page.setData.bind(page), data)
}

上面的代码中,通过page.setData,更新vm的data数据,并用throttleSetData进行50ms一次的节流。然而,第二个参数data依然是将vm中的全部数据传给setData,而没有检测究竟data中的哪些字段真正发生了变化。

综合起来讲,vm和小程序数据没有保持统一,和mpvue setData前没有diff一次找出真正需要更新的数据,这两个因素共同造成了上面的bug。

另一种解决办法

在实践中发现,双向绑定虽然不会造成地图缩放级别重置,但是依然会造成抖动,所以另一种解决办法是不再对scale,latitude,longitude这3个参数进行响应式绑定,改为使用原生小程序的api来操作。代码如下:

            this.$mp.page.setData({
'$root[0].latitude': data[0].latitude,
'$root[0].longitude': data[0].longitude,
'$root[0].scale': INIT_SCALE
})

通过this.$mp.page来拿到小程序的page实例,自己在需要的时候手动进行setData。需要注意的地方时在模板中依然需要绑定,保证编译出来的wxml知道这里是可以setData的,但是在data中没有相关的值,从而使scale这些数据不是响应式的

  <map
id="map"
:scale="scale"
:latitude="latitude"
:longitude="longitude"> //在js中 <script>
export default{
data(){
return {
这里不写 scale,latitude,longitude这些属性
}
}
} </script>

(完)

在mpvue中使用map如何避坑的更多相关文章

  1. 双刃剑MongoDB的学习和避坑

    双刃剑MongoDB的学习和避坑 MongoDB 是一把双刃剑,它对数据结构的要求并不高.数据通过key-value的形式存储,而value的值可以是字符串,也可以是文档.所以我们在使用的过程中非常方 ...

  2. 15. Go 语言“避坑”与技巧

    Go 语言"避坑"与技巧 任何编程语言都不是完美的,Go 语言也是如此.Go 语言的某些特性在使用时如果不注意,也会造成一些错误,我们习惯上将这些造成错误的设计称为"坑& ...

  3. Guava中这些Map的骚操作,让我的代码量减少了50%

    原创:微信公众号 码农参上,欢迎分享,转载请保留出处. Guava是google公司开发的一款Java类库扩展工具包,内含了丰富的API,涵盖了集合.缓存.并发.I/O等多个方面.使用这些API一方面 ...

  4. 珍爱生命,远离JS=>JS避坑记

    JavaScript避坑记 转载请注明源地址: http://www.cnblogs.com/funnyzpc/p/8407952.html 上图=> 有意思的漫画,不知大家看懂了没,这里我想说 ...

  5. Windows环境下Anaconda安装TensorFlow的避坑指南

    最近群里聊天时经常会提到DL的东西,也有群友在学习mxnet,但听说坑比较多.为了赶上潮流顺便避坑,我果断选择了TensorFlow,然而谁知一上来就掉坑里了…… 我根据网上的安装教程,默认安装了最新 ...

  6. spring-boot-starter-thymeleaf 避坑指南

    第一步:pom配置环境 先不要管包是做什么的 总之必须要有 否则进坑 <!--避坑包--> <dependency> <groupId>net.sourceforg ...

  7. MyBatis 一级缓存避坑

    MyBatis 一级缓存(MyBaits 称其为 Local Cache)无法关闭,但是有两种级别可选: package org.apache.ibatis.session; /** * @autho ...

  8. electron 编译 sqlite3避坑指南---尾部链接有已经编译成功的sqlite3

    electron 编译 sqlite3避坑指南(尾部链接有已经编译成功的sqlite3) sqlite很好用,不需要安装,使用electron开发桌面程序,sqlite自然是存储数据的不二之选,奈何编 ...

  9. js避坑历险记

    代码改变世界,世界改变码农,码农改变代码! 我就是我,我就是一个码农的武林. 前方JS巨坑出没,请注意集中力! 巨坑1:js精度问题 前段时间去一家物流公司面试,做了一个js题,印象尤为深刻: var ...

随机推荐

  1. jq获取图片并转换为base64

    html代码: <input type="file" id="file1"/> jq代码: $('#file1').change(function( ...

  2. JavaSE基础知识(4)—数组的应用

    一.数组的特点.好处及使用步骤 1.数组的好处 特点:相当于用于保存一组元素的容器好处: 1.提高代码的简洁性和扩展性,且同时开辟多个空间,提高了效率 2.分类存储,且空间是连续的,容易查找 2.数组 ...

  3. SQL Server 2000使用链接服务器

    执行:安装盘\SQL2KSP4\install\instcat.sql 文件下载地址:http://download.csdn.net/detail/taomanman/5680765

  4. kubernetes namespace Terminating

    1.kubectl get namespace annoying-namespace-to-delete -o json > tmp.jsonthen edit tmp.json and rem ...

  5. trinitycore 魔兽服务器源码分析(一) 网络

    trinitycore是游戏服务器的开源代码 许多玩家使用魔兽的数据来进行测试 ,使用它来假设魔兽私服. 官方网址  https://www.trinitycore.org/ 类似的还有mangos ...

  6. C#当中的扩展方法

    先说有用的,c#扩展方法结论: 扩展方法能够向现有类型“添加”方法,而无需创建新的派生类型,重新编译或以其他方式修改原始类型.扩展方法必须是静态方法,可以像实例方法一样进行调用.且调用同名中实际定义的 ...

  7. centos7 go ENV 部署

    1.wget官网下载go 官网https://golang.org/dl/ 2.解压 tar -C /usr/local -xzf go$VERSION.$OS-$ARCH.tar.gz 3.配置环境 ...

  8. Maths | 为什么点积等价于投影后的乘积

    目录 1. 复习点积 2. 点积的对称性 3. 矩阵与变换的关系 4. 一维矩阵也是一种线性变换 5. 最终解释:为什么是投影 先上结论: \(\boldsymbol v\)和\(\boldsymbo ...

  9. 1119 Pre- and Post-order Traversals

    Suppose that all the keys in a binary tree are distinct positive integers. A unique binary tree can ...

  10. http响应头里没有或者有content-length的几种可能性

    对于http的请求返回结果要进行内容的长度校验主要有两种方式,二者互斥使用 1.客户端在http头(head)加Connection:keep-alive时,服务器的response是Transfer ...