前言
需求是这样的,我要在当前组件生成一个柱状图来渲染我的数据,点击柱状图上的某一列作为查询条件对表格内的数据更改。
我将Echarts作为子组件放在当前组件中,这就涉及到了父子组件传值,props被动更新,Echarts初始化,Echarts监听“空白处”事件。
干货知识点:
-
props如何取值
-
Echarts在什么位置初始化
-
Echarts通过$ref获取DOM节点
-
Echarts点击事件图表更新
-
子组件给父组件传值的两种emit方法
代码
<template>
<div ref="category" :style="{ height: height, width: width }" />
</template>
<script>
import * as echarts from 'echarts'
import { onBeforeMount, onMounted, onBeforeUpdate, toRefs, onUpdated, getCurrentInstance } from 'vue'
export default {
props: {
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: '350px'
},
data1: Object,
data2: Object,
chartSource: Object
},
setup (props, context) {
// TODO: write Code
}
}
</script>
Props如何取值
Vue3新增了setup后,我们可以在setup中访问到取过来的props携带的值。
官网文档中说setup的第一个参数是props,它是响应式的,当传入新的props时,它会被更新。
但是我们不能通过ES6解构props,这样会消除prop的响应性,官方给的方法使用toRefs函数来完成操作
import { toRefs } from 'vue'
setup (props, context) {
const { data1, data2, chartSource } = toRefs(props)
}
这样我们就能取到props中的所有的值,但是要注意的是我们需要加.value才等于他的值,因为传过来的值是proxy对象
Echarts在什么位置初始化
在什么位置初始化,取决于我们在哪个生命周期能获取到DOM节点和拿到props传过来的值。这就要对生命周期的过程十分了解!
在mount的过程中,在解析DOM节点,在此时我们是拿不到我们要的DOM节点的,在mounted后才可以获取到DOM节点,那我们就在mouted初始化Echarts?
不,不,不
此时我们的数据还没有传过来,data1、data2、chartSource的值还是空,我们还不能初始化Echarts
子组件的props的数据是父组件渲染结束后才更新的
我们来好好的理解下这句话的原理
首次渲染时,父组件内data1、data2、chartSource的数据是使用ref初始化的,当数据发生变化时,父组件的渲染函数会重新执行,父组件进行自更新。在更新过程中,渲染器发现父组件的subTree包含组件类型的虚拟节点,也就是子组件,调用patchCompnent函数完成子组件更新。
由父组件自更新引起子组件更新叫子组件的被动更新,当子组件发生被动更新时,会检测子组件是否真的需要更新,也就是数据是否变化,如果需要更新,更新子组件的props、slot等内容。
这个阶段就相当于
father mount -> son beforeUpdate -> son Update -> father beforeUpdate
props本质上是父组件的数据,当props发生变化时,会触发父组件的重新渲染。渲染完成后,父组件的数据更新完成,传给子组件,这是在子组件的beforeUpdate才能拿到更新后的props数据。
如果对上面的过程不是很清楚的,可以看 《Vue.js设计与实现》中12.4-props与组件的被动更新
所以,我们应该在子组件的beforeUpdate中进行Echarts初始化。
Echarts通过$ref获取DOM节点
Echarts初始化的第一步要获取DOM节点,那怎么获得呢?
在官方文档中,访问组件的property中表明:
执行setup时,只能访问
- props
- attrs
- slots
- emit
换句话说,你将无法访问一下组件选项:
- data
- computed
- methods
- refs(模版ref)
我们在Vue2中使用this.$refs获取DOM节点,但是在Vue3的setup() 内部的 this 的行为与其它选项中的 this 完全不同,无法在setup中使用this.$refs获取DOM节点
那我们要如何在setup中使用refs呢?
Vue3提供了一个getCurrentInstanceApi方法,它支持访问内部组件的实例。
所以在setup中创建一个getCurrentInstance的实例,使用里面的proxy属性带的$ref方法,来获取DOM节点
const { proxy } = getCurrentInstance() // 获取实例中的proxy
const myChart = proxy.$refs.category // 获取category的DOM节点
之后就可以进行Echarts初始化了。Echarts的options会使用到props的数据,在使用时记得加.value
Echarts点击事件图表更新
我们要实现在点击空白处的时候,下面的表格数据发生变化。
效果是这样的,其实就是获取到点击位置对应x轴的值。
Echarts官方文档中的概念篇-事件与行为-监听“空白处”的事件,提供了getZr()方法
这个方法要从初始化后的实例上调用,使用.on绑定事件。
const myChart = proxy.$refs.category
const thisChart = echarts.init(myChart)
// 绑定点击事件
thisChart.getZr().on('click', function(event) {
// TODO: write Code
})
接下来,我们通过什么方法来获取到点击处的X轴的值
thisChart.getZr().on('click', function(event) {
// 获取点击位置的X和Y坐标
let pointInPixel = [event.offsetX, event.offsetY]
// 判断坐标点是否在指定的坐标系或者系列上
if (thisChart.containPixel('grid', pointInPixel)) {
// 转换像素坐标值到逻辑坐标系上的点
let xIndex = thisChart.convertFromPixel({ seriesIndex: 0 }, pointInPixel)[0]
// 比对location的全名对应的id值,(这个地方可以忽略,因为我的xindex是地点全名不是locationid值)
let locationid = chartSource.value[xIndex].locationid
// emit传值给父组件,看下一部分
}
})
子组件给父组件传值的两种emit方法
我们通过emit方法实现子组件向父组件传值,emit是用来发送组件的自定义事件。
第一种方法
我们可以使用刚才实例的proxy中的$emit方法来发送自定义事件
proxy.$emit('getLocationid', locationid)
第二种方法
在上面中提到了setup可以访问emit
我们需要使用到setup的第二个参数 context 中有 emit 方法
setup (props, context) {
context.emit('getLocationid', locationid)
}
这样也能发送自定义事件。
结语
干货很多,感谢您耐心的看完了!
在写这篇文章的时候,学习了setup、props、emit、Echarts监听空白事件,实现这个需求需要的知识点真的挺多的,为了搞明白,为什么props在mounted后读不到数据的问题,特地去查了查底层实现的源码。
欢迎掘友在评论区留言
求大佬们评论您遇到这类问题的解决方法,或者还有什么坑点?
觉得我写的还不错的,可以给我个赞吗?求求了!