组件中 watch props 根据 v-if 动态判断并挂载 DOM 的问题

栏目: Objective-C · 发布时间: 4年前

内容简介::star:️ 更多前端技术和知识点,搜索订阅号问题复现:父组件中通过名为 source 的 prop 向子组件 Chart 传入数据

组件中 watch props 根据 v-if 动态判断并挂载 DOM 的问题

组件中 watch props 根据 v-if 动态判断并挂载 DOM 的问题

:star:️ 更多前端技术和知识点,搜索订阅号 JS 菌 订阅

问题复现:父组件中通过名为 source 的 prop 向子组件 Chart 传入数据

<Chart :source="chartData"></Chart>
import Chart from '../components/Chart'

export default {
  name: 'Home',
  components: { Chart },
  data () {
    return {
      chartData: []
    }
  },
  mounted () {
    setTimeout(() => {
      this.chartData = [
        [89.3, 58212, 'Matcha Latte'],
        [57.1, 78254, 'Milk Tea'],
        [74.4, 41032, 'Cheese Cocoa'],
        [50.1, 12755, 'Cheese Brownie'],
        [89.7, 20145, 'Matcha Cocoa'],
        [68.1, 79146, 'Tea'],
        [19.6, 91852, 'Orange Juice'],
        [10.6, 101852, 'Lemon Juice'],
        [32.7, 20112, 'Walnut Brownie']
      ]
    }, 2000)
  }
}

子组件接收 source 数据当存在且至少有一条数据的时候,创建 id 为 main 的 div,用以初始化 echarts 实例

<div v-if="source && source.length" id="main" ref="main" style="width: 600px;height: 400px;"></div>
<div vi-else>none</div>

Chart 组件通过接收数据 watch prop 的变化动态的调用 echarts 的 setOptions 方法,最终渲染数据。

export default {
  // ...
  watch: {
    source (newVal, oldVal) {
      this.setOpts()
    }
  },
  props: ['source'],
  methods: {
    setOpts () {
      let myChart = this.$echarts.init(this.$refs.main)
      myChart.setOption({
        dataset: {
          // ...
          source: this.source
        },
        // ...
      })
    }
  }
}

如果直接这么写必定报错:

Error in callback for watcher "source": "TypeError: Cannot read property 'getAttribute' of undefined"

在代码中增加一行代码:

watch: {
    source (newVal, oldVal) {
      console.log(newVal, this.$refs.main) // [Array ...] undefined
      this.setOpts()
    }
  },

启示 source 数据虽然有了,但 div 还并未挂载,因此 echarts 无法完成初始化

那么想当然的我们就会去在 mounted 生命周期函数中调用 setOpts 方法:

mounted () {
    console.log(this.source, this.$refs.main) // [] undefined
    this.setOpts()
  },

这样也是错的,因为模板语法中使用了 v-if,那么当 source 并未满足条件的时候,div 当然也不会挂载。因此 div 仍然无法访问到。

Error in mounted hook: "TypeError: Cannot read property 'getAttribute' of undefined"

解决办法是要么去掉 v-if 要么换另一种写法

有时我们需要在没有数据的情况下增加一个占位标签用来展示一些额外的提醒信息,如“暂未获取到数据”等。那么去掉 v-if 肯定不行。

既然如此我们保留 v-if 但写法有所改变:

修改 Chart 组件:

<template>
  <div>
    <div id="main" ref="main" style="width: 600px;height: 400px;"></div>
  </div>
</template>

我们只需要一个 source 数据源,当 mounted 的时候调用 setOpts 方法,当 watch 数据变化的时候再次调用以更新数据

export default {
  name: 'Chart',
  props: ['source'],
  mounted () {
    this.setOpts()
  },
  watch: {
    source () {
      this.setOpts()
    }
  },
  methods: {
    setOpts () {
      let myChart = this.$echarts.init(this.$refs.main)
      myChart.setOption({
        dataset: {
          dimensions: ['score', 'amount', 'product'],
          source: this.source
        },
        xAxis: { type: 'category' },
        yAxis: {},
        series: [
          {
            type: 'bar',
            encode: {
              x: 'product',
              y: 'amount'
            }
          }
        ]
      })
    }
  }
}

v-if 的判断我们把他移出去了我们判断 chartData 是否获取到,一旦获取到数据,马上加载 Chart 组件,这样就可以避开在组件内部调用 v-if 带来的问题:

<template>
  <div>
    <Chart :source="chartData" v-if="flag"></Chart>
    <div v-else>none</div>
  </div>
</template>
import Chart from '../components/Chart'

export default {
  name: 'Home',
  components: { Chart },
  data () {
    return {
      chartData: [],
      flag: false
    }
  },
  methods: {
    getData () {
      setTimeout(() => {
        this.chartData = [
          [89.3, 58212, 'Matcha Latte'],
          [57.1, 78254, 'Milk Tea'],
          [74.4, 41032, 'Cheese Cocoa'],
          [50.1, 12755, 'Cheese Brownie'],
          [89.7, 20145, 'Matcha Cocoa'],
          [68.1, 79146, 'Tea'],
          [19.6, 91852, 'Orange Juice'],
          [10.6, 101852, 'Lemon Juice'],
          [32.7, 20112, 'Walnut Brownie']
        ]
        this.flag = true
      }, 2000)
    }
  },
  mounted () {
    this.getData()
  }
}

另外还可将 Chart 组件和站位标签一同封装成一个 ChartWrapper。

这样就不会因在组件内部调用 watch 监听 props 的变化动态 v-if 判断并挂载数据到 DOM 上出现的这种问题了。

组件中 watch props 根据 v-if 动态判断并挂载 DOM 的问题

请关注我的订阅号,不定期推送有关 JS 的技术文章,只谈技术不谈八卦 :blush:


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

500 Lines or Less

500 Lines or Less

Amy Brown、Michael DiBernardo / 2016-6-28 / USD 35.00

This book provides you with the chance to study how 26 experienced programmers think when they are building something new. The programs you will read about in this book were all written from scratch t......一起来看看 《500 Lines or Less》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器