Skip to content

事件系统

RayChart 提供了两种事件监听方式:Vue 声明式事件和命令式 API。

Vue 声明式事件(推荐)

使用 Vue 的 @ 语法监听事件,这是最符合 Vue 使用习惯的方式。

可用事件

事件名触发时机参数
click点击图表元素{ seriesIndex, dataIndex, data, event }
dblclick双击图表元素{ seriesIndex, dataIndex, data, event }
mouseover鼠标移入图表元素{ seriesIndex, dataIndex, data, event }
mouseout鼠标移出图表元素{ seriesIndex, dataIndex, data, event }
mousemove鼠标在图表上移动{ seriesIndex, dataIndex, data, event }
mousedown鼠标按下{ seriesIndex, dataIndex, data, event }
mouseup鼠标释放{ seriesIndex, dataIndex, data, event }

基础用法

vue
<template>
  <RayBar 
    :option="chartOption"
    @click="handleClick"
    @mouseover="handleMouseOver"
    @mouseout="handleMouseOut"
  />
</template>

<script setup>
import { ref } from 'vue'
import { RayBar } from 'raychart'

const chartOption = ref({
  series: [{
    data: [120, 200, 150, 80, 70, 110, 130]
  }],
  xAxis3D: {
    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  }
})

const handleClick = (params) => {
  console.log('Clicked:', params)
  console.log('Series Index:', params.seriesIndex)
  console.log('Data Index:', params.dataIndex)
  console.log('Value:', params.data)
}

const handleMouseOver = (params) => {
  console.log('Mouse over:', params)
}

const handleMouseOut = () => {
  console.log('Mouse out')
}
</script>

事件参数

所有鼠标事件都会传递以下参数:

typescript
interface EventParams {
  seriesIndex: number    // 系列索引
  dataIndex: number      // 数据点索引
  data: any             // 数据值
  event: MouseEvent     // 原始 DOM 事件
  name?: string         // 数据点名称(如果有)
  value?: number        // 数据点值(如果有)
}

实际应用示例

点击高亮

vue
<template>
  <RayBar :option="chartOption" @click="handleClick" />
</template>

<script setup>
import { ref } from 'vue'
import { RayBar } from 'raychart'

const selectedIndex = ref(-1)

const chartOption = ref({
  series: [{
    data: [120, 200, 150, 80, 70, 110, 130]
  }],
  xAxis3D: {
    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  }
})

const handleClick = (params) => {
  selectedIndex.value = params.dataIndex
  console.log(`Selected: ${params.name} = ${params.value}`)
  
  // 可以更新图表配置来高亮选中项
  // chartOption.value = { ...chartOption.value, ... }
}
</script>

悬停提示

vue
<template>
  <div class="chart-wrapper">
    <RayBar 
      :option="chartOption"
      @mouseover="handleMouseOver"
      @mouseout="handleMouseOut"
    />
    <div v-if="tooltip.visible" class="custom-tooltip" :style="tooltipStyle">
      <strong>{{ tooltip.name }}</strong>
      <div>值: {{ tooltip.value }}</div>
    </div>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'
import { RayBar } from 'raychart'

const tooltip = ref({
  visible: false,
  name: '',
  value: 0,
  x: 0,
  y: 0
})

const tooltipStyle = computed(() => ({
  left: `${tooltip.value.x + 10}px`,
  top: `${tooltip.value.y + 10}px`
}))

const chartOption = ref({
  series: [{
    data: [120, 200, 150, 80, 70, 110, 130]
  }],
  xAxis3D: {
    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  }
})

const handleMouseOver = (params) => {
  tooltip.value = {
    visible: true,
    name: params.name || `Item ${params.dataIndex}`,
    value: params.value || params.data,
    x: params.event.clientX,
    y: params.event.clientY
  }
}

const handleMouseOut = () => {
  tooltip.value.visible = false
}
</script>

<style scoped>
.chart-wrapper {
  position: relative;
}

.custom-tooltip {
  position: fixed;
  background: rgba(0, 0, 0, 0.8);
  color: white;
  padding: 8px 12px;
  border-radius: 4px;
  font-size: 14px;
  pointer-events: none;
  z-index: 1000;
}
</style>

命令式 API(高级用法)

对于需要动态添加/移除监听器的场景,可以使用命令式 API。

方法

方法说明参数
on(event, handler)添加事件监听器event: 事件名, handler: 回调函数
once(event, handler)添加一次性事件监听器event: 事件名, handler: 回调函数
off(event, handler)移除事件监听器event: 事件名, handler: 回调函数
dispatch(event, payload)触发自定义事件event: 事件名, payload: 事件数据

基础用法

vue
<template>
  <RayBar ref="chartRef" :option="chartOption" />
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import { RayBar } from 'raychart'

const chartRef = ref()
let unsubscribe: (() => void) | undefined

const chartOption = ref({
  series: [{
    data: [120, 200, 150]
  }],
  xAxis3D: {
    data: ['A', 'B', 'C']
  }
})

onMounted(() => {
  // 添加监听器
  unsubscribe = chartRef.value?.on('click', (payload) => {
    console.log('Clicked:', payload)
  })
})

onUnmounted(() => {
  // 清理监听器
  unsubscribe?.()
})
</script>

一次性监听

javascript
// 只监听一次
chartRef.value?.once('click', (payload) => {
  console.log('First click:', payload)
})

移除监听器

javascript
const handler = (payload) => {
  console.log('Clicked:', payload)
}

// 添加监听器
chartRef.value?.on('click', handler)

// 移除监听器
chartRef.value?.off('click', handler)

自定义事件

javascript
// 触发自定义事件
chartRef.value?.dispatch('custom:event', {
  data: 'custom data'
})

// 监听自定义事件
chartRef.value?.on('custom:event', (payload) => {
  console.log('Custom event:', payload)
})

事件冒泡

图表事件不会冒泡到 DOM 树,它们只在图表内部传播。

性能建议

1. 使用防抖

对于高频事件(如 mousemove),建议使用防抖:

vue
<script setup>
import { ref } from 'vue'
import { useDebounceFn } from '@vueuse/core'

const handleMouseMove = useDebounceFn((params) => {
  console.log('Mouse move:', params)
}, 100)
</script>

<template>
  <RayBar :option="chartOption" @mousemove="handleMouseMove" />
</template>

2. 避免在事件处理中更新图表

javascript
// ❌ 不推荐:在事件中频繁更新图表
const handleMouseMove = (params) => {
  chartOption.value = { ...chartOption.value, ... }
}

// ✅ 推荐:只更新必要的状态
const handleMouseMove = (params) => {
  hoveredIndex.value = params.dataIndex
}

3. 及时清理监听器

使用命令式 API 时,记得在组件卸载时清理监听器:

javascript
onUnmounted(() => {
  unsubscribe?.()
})

常见问题

Q: 为什么事件没有触发?

A: 检查以下几点:

  1. 确保图表已经渲染完成
  2. 确保事件名称正确(区分大小写)
  3. 确保图表元素可交互(没有被其他元素遮挡)

Q: 如何区分点击图表元素和点击空白区域?

A: 检查事件参数中的 seriesIndexdataIndex

javascript
const handleClick = (params) => {
  if (params.seriesIndex >= 0 && params.dataIndex >= 0) {
    console.log('Clicked on data point')
  } else {
    console.log('Clicked on empty area')
  }
}

Q: 声明式事件和命令式 API 可以混用吗?

A: 可以,但建议优先使用声明式事件,只在需要动态管理监听器时使用命令式 API。

相关文档