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


Posted in Javascript onMay 12, 2019

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

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

Javascript 相关文章推荐
关于文本限制字数的js代码
Apr 02 Javascript
JavaScript asp.net 获取当前超链接中的文本
Apr 14 Javascript
js弹出模式对话框,并接收回传值的方法
Mar 12 Javascript
js抽奖实现随机抽奖代码效果
Dec 02 Javascript
js实现select下拉框菜单
Dec 08 Javascript
JS组件Bootstrap Select2使用方法详解
Apr 17 Javascript
JS控制弹出悬浮窗口(一览画面)的实例代码
May 30 Javascript
Node.js 异步异常的处理与domain模块解析
May 10 Javascript
微信小程序实现横向增长表格的方法
Jul 24 Javascript
axios使用拦截器统一处理所有的http请求的方法
Nov 02 Javascript
Vue使用v-viewer实现图片预览
Oct 21 Javascript
利用uni-app生成微信小程序的踩坑记录
Apr 05 Javascript
用js简单提供增删改查接口
May 12 #Javascript
electron-vue利用webpack打包实现多页面的入口文件问题
May 12 #Javascript
vue中axios实现数据交互与跨域问题
May 12 #Javascript
jquery3和layui冲突导致使用layui.layer.full弹出全屏iframe窗口时高度152px问题
May 12 #jQuery
JS块级作用域和私有变量实例分析
May 11 #Javascript
微信小程序封装的HTTP请求示例【附升级版】
May 11 #Javascript
微信小程序自定义toast组件的方法详解【含动画】
May 11 #Javascript
You might like
德劲1107的电路分析与打磨
2021/03/02 无线电
《PHP编程最快明白》第六讲:Mysql数据库操作
2010/11/01 PHP
ThinkPHP写数组插入与获取最新插入数据ID实例
2014/11/03 PHP
简单实现PHP留言板功能
2016/12/21 PHP
详解PHP中的序列化、反序列化操作
2017/03/21 PHP
PHP实现基于状态的责任链审批模式详解
2019/05/31 PHP
PHP实现chrome表单请求数据转换为接口使用的json数据
2021/03/04 PHP
基于jQuery的获取标签名的代码
2012/07/16 Javascript
javascript中如何处理引号编码&amp;#034;
2013/08/15 Javascript
jQuery实现单击按钮遮罩弹出对话框(仿天猫的删除对话框)
2014/04/10 Javascript
在JavaScript中处理数组之reverse()方法的使用
2015/06/09 Javascript
JS实现从连接中获取youtube的key实例
2015/07/02 Javascript
基于MVC+EasyUI的web开发框架之使用云打印控件C-Lodop打印页面或套打报关运单信息
2016/08/29 Javascript
Node.js 实现简单的接口服务器的实例代码
2017/05/23 Javascript
vue时间格式化实例代码
2017/06/13 Javascript
JavaScript使用享元模式实现文件上传优化操作示例
2018/08/07 Javascript
使用Javascript简单计算器
2018/11/17 Javascript
浅谈Fetch 数据交互方式
2018/12/20 Javascript
layui prompt 设置允许空白提交的方法
2019/09/24 Javascript
深入了解Vue.js 混入(mixins)
2020/07/23 Javascript
Python中for循环控制语句用法实例
2015/06/02 Python
详解JavaScript编程中的window与window.screen对象
2015/10/26 Python
在Python中调用Ping命令,批量IP的方法
2019/01/26 Python
python调用支付宝支付接口流程
2019/08/15 Python
在服务器上安装python3.8.2环境的教程详解
2020/04/26 Python
Pytorch转keras的有效方法,以FlowNet为例讲解
2020/05/26 Python
让IE支持HTML5的方法
2012/12/11 HTML / CSS
经济实惠的名牌太阳镜和眼镜:Privé Revaux
2021/02/07 全球购物
一个J2EE项目团队的主要人员组成是什么
2012/06/04 面试题
行政管理专业推荐信
2013/11/02 职场文书
医科大学生毕业的自我评价分享
2013/11/12 职场文书
生产部厂长助理职位说明书
2014/03/03 职场文书
机械机修工岗位职责
2014/08/03 职场文书
暑期培训班策划方案
2014/08/26 职场文书
Nginx配置Https安全认证的实现
2021/05/26 Servers
django 认证类配置实现
2021/11/11 Python