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

 更新时间:2019年05月12日 09:20:46   作者:JS菌  
这篇文章主要介绍了vue组件中watch props根据v-if动态判断并挂载DOM的问题,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

问题复现:父组件中通过名为 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 上出现的这种问题了。

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

相关文章

  • readonly和disabled的区别

    readonly和disabled的区别

    要慎用readonly和disabled, 指定了disabled的表单,在submit时,不会把它的值传出去, 如下所示,有两个text,一个是readonly一个是disabled,submit后,只能发送那个不是disabled的,注意地址栏的值. 要保存到本地,因为submit了,不然,看不到效果.
    2008-04-04
  • JavaScript实现字符串截取的三个方法总结

    JavaScript实现字符串截取的三个方法总结

    在 JavaScript 中,可以使用 substr()、slice() 和 substring() 方法截取字符串。这篇文章就来通过一些示例和大家聊聊这些方法的具体操作,需要的可以参考一下
    2023-02-02
  • sogou地图API用法实例教程

    sogou地图API用法实例教程

    这篇文章主要介绍了C# sogou地图API用法,包括了各种常用属性的用法实例,需要的朋友可以参考下
    2014-09-09
  • 基于Phantomjs生成PDF的实现方法

    基于Phantomjs生成PDF的实现方法

    这篇文章主要介绍了基于Phantomjs生成PDF的实现方法,结合实例形式分析了Phantomjs结合nodejs生成pdf的操作步骤与相关技巧,需要的朋友可以参考下
    2016-11-11
  • JavaScript计算值然后把值嵌入到html中的实现方法

    JavaScript计算值然后把值嵌入到html中的实现方法

    下面小编就为大家带来一篇JavaScript计算值然后把值嵌入到html中的实现方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-10-10
  • JS触摸事件、手势事件详解

    JS触摸事件、手势事件详解

    本篇文章主要介绍了JS触摸事件、手势事件详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05
  • ES6扩展运算符的理解与使用场景

    ES6扩展运算符的理解与使用场景

    扩展运算符( spread )是三个点(...),它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列,这篇文章主要给大家介绍了关于ES6扩展运算符的理解与使用场景的相关资料,需要的朋友可以参考下
    2021-09-09
  • 浅析JS刷新框架中的其他页面 && JS刷新窗口方法汇总

    浅析JS刷新框架中的其他页面 && JS刷新窗口方法汇总

    本篇文章是对JS刷新框架中的其他页面以及JS刷新窗口的方法进行了汇总介绍,需要的朋友可以参考下
    2013-07-07
  • js创建子窗口并且回传值示例代码

    js创建子窗口并且回传值示例代码

    本文为大家详细介绍喜爱使用js创建子窗口并且实现回传值的示例,感兴趣的朋友可以参考下哈,希望对大家有所帮助
    2013-07-07
  • JavaScript ES6 Class类实现原理详解

    JavaScript ES6 Class类实现原理详解

    这篇文章主要介绍了JavaScript ES6 Class类实现原理详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-05-05

最新评论