父传子未触发watch事件

2020-09-02  本文已影响0人  成神之路_be73

场景: 地图组件页面中,偶尔间发现marker图标有时能看到, 有时看不到,造成了使用的显示问题,
定位问题: 原来是因为watch里面监听的地图数组集合未被触发,所以没有调用到addMarker函数
发现问题,那就得解决问题,先给大家捋一下解决步骤

逻辑
首先梳理下逻辑,父级页面中,调用地图组件的同时,并发送获取地址的接口。接下来,子组件的地图服务已经被调用了, 渲染了地图,当接口地址数据拿回后,会触发watch事件,调用里面的addMarker方法,显示marker

排查问题
打上了断点,发现是因为watch中监听的父传子变量未触发,这是为啥???
网速快的情况下,先渲染子组件,接口数据后拿回,拿回后传给子组件时,触发了变化,这个没有问题的。
网速慢的情况下,先拿到接口数据,再渲染子组件,这个时候,\color{red}{ 虽然我props中默认为空,并且父传子的数据是有值的,但是还是没有触发变化,所以没有调用addMarker事件}

尝试一
在父级页面给子组件加个v-if,拿到数据后才能调用组件
- 网速慢的话,子组件是一个地图控件,有背景什么的,接口不知道什么时候才能返回,总不能一直空着;
- 网速快的话,页面正常

尝试二
试着在mounted中先一步调用addMarker
- 网速慢的话,在mounted中已经到了地址数据,调用addMarker, watch未触发,所以不用调用addMarker;
- 网速快的话,在mounted中未拿到地址数据, addMarker被调用了一次(没有数据未渲染marker),拿到数据后,addMarker又被调用了一下(有数据渲染marker),感觉这个也不是特别符合逻辑,(假设在mounted中有数据的话,那就是addMarker被重复调用并渲染了两次)

尝试三
watch中使用immediate: true
- 网速慢的话,会强制调用addMarker,并且调用时有值,但是这个时候,地图控件还没有被创建出来,this.map为空,更别说给他添加marker了,地图使用时是有一个循序渐进的过程,所以又被卡在这里了
- 网速快的话,会强制调用addMarker,但是调用的时候是没有值的,然后有值的时候再调用addMarker,相当于又是两次调用;

尝试四(解决)
使用this.$set(),意思就是说会设置属性值,触发视图更新;
- 网速慢的话,在created中使用$set, 会在数据发生变化时,触发watch,形成跟网速快时一样的操作,
- 网速快的话,页面正常

props: { 
  gisInfo: {
    type: Object,
    default: function () {
      return {};
    }
  },
},
data: function () {
  return {
    gisInfoList: {}
  };
},
methods: {
  addMarker: function () {
    var keys = Object.keys(this.gisInfoList);
    if (keys.length) {
      // 执行内容
    }
  }
},
created: function () {
  this.$set(this.gisInfo); // 初始化设置下 不赋值他就是有个默认的undefined
  console.log(this.gisInfo); // {undefined: undefined} 
},
watch: {
  gisInfo: {
    handler: function (val) {
      let obj = {};
      let keys = Object.keys(val);
      if (keys.length) {
        keys.forEach(function (key) {
          if (key != 'undefined') {
            obj[key] = val[key];
          }
        })
      }
      this.gisInfoList = obj;   // 如果直接赋值给gisInfo,会再次触发watch,陷入循环
      this.addMarker();
    },
    deep: true
  },
}

至此,问题解决了,但是个人感觉那个判断undefined的方法不太好,如果大家有好的解决方法,可以推荐下,谢谢

上一篇 下一篇

猜你喜欢

热点阅读