一、问题描述
组件的层级关系如图所示,
期望是点击气象设备组件的解析按钮将文本框的数据解析为气象对象(包含经纬度信息),并将该值传递给地图子组件,地图组件根据其经纬度信息更新位置锚点。
数据传递的方式采用对象动态绑定,即将所有的属性值进行向下单向传递。
<DisplayMap v-bind:meteorologyVo="meteorologyVo"></DisplayMap>
地图子组件利用props进行引用:
props:{ meteorologyVo: Object, }
锚点的HTML代码为:
<bm-marker :position="{lng: meteorologyData.longitude, lat: meteorologyData.latitude}"></bm-marker>
绑定后,点击解析按钮,地图子组件的锚点跑到了经纬度同为0的地方。
二、问题分析
有两个层次的问题需要搞清楚:
- 对象是通过引用传递到子组件中,对象的属性值发生变化,引用未发生变化,导致Vue实例监听不到变化
- 组件的层次过深,地图子组件不是真实的子组件,图中还经历了行组件ARow
三、曲线解决问题
3.1 添加动态聚合标签
<bm-marker-clusterer :averageCenter="true"> <bm-marker v-for="marker of markers" :key="marker.code" :position="{lng: marker.lng, lat: marker.lat}" @click="lookDetail(marker)" animation="BMAP_ANIMATION_BOUNCE"></bm-marker> </bm-marker-clusterer>
3.2 添加数组对象markers
data(){ markers: [], }
3.3 添加对象监听函数
曲线救国,利用数组的操作更新视图,数组的多种方法都可以让Vue实例对DOM进行重新渲染。
watch:{ meteorologyVo:/* 监听该对象的变化进行回调 */{ handler(val, oldValue){ console.log(oldValue); let marker = { code: 2, lng: val.gpsVo.longitude, lat: val.gpsVo.latitude, } this.markers.pop(); this.markers.push(marker); }, deep: true }
四、结果展示
五、方案优化
由于初步接触Vue.js,对其父组件传值给子组件的规范不太熟悉,官方如是说:
我原来的子组件中动态绑定的属性名称如下:
<DisplayMap v-bind:meteorologyVo="meteorologyVo"></DisplayMap>
属性值引用如下:
props:{ meteorologyVo: Object, },
因此,将子组件中动态绑定的属性名称按照规范修改如下:
<DisplayMap1 v-bind:child-meteorology="meteorologyVo"></DisplayMap1>
属性值引用如下:
props:{ childMeteorology: { type: Object, default: function(){ return {}; }, required: true } },
但是watch函数仍旧因为需求要用,当父组件的对象值改变后,地图的居中需要以锚点的坐标。而且,我们还可以知道,Vue底层实现的原来,应该是实例化子组件时候监听了父组件的对象,逻辑使用对象代理来完成通知。