You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue组合式API实现Chart.js柱状图单柱点击事件方案

解决Vue3 + vue-chartjs柱状图柱子点击事件的问题

要实现单个柱子的点击事件并正确调用getElementsAtEventForMode,核心是正确获取Chart.js的实例,而非直接操作DOM元素。以下是具体修改步骤:

1. 定义组件Ref引用

在<script setup>中添加ref,用于绑定Bar图表组件:

const barChartRef = ref<InstanceType<typeof Bar> | null>(null)

2. 绑定Ref到模板中的Bar组件

修改template里的Bar标签,添加ref属性:

<Bar 
  ref="barChartRef"
  :data="itemReactive" 
  id="barChart" 
  @click="clickHandler" 
  :options="options" 
  class="grafica" 
/>

3. 修改点击事件处理函数

通过ref获取Chart.js实例,再调用getElementsAtEventForMode获取点击的柱子数据:

function clickHandler(e: MouseEvent){
  // 确保图表实例已初始化
  if (!barChartRef.value?.chart) return;

  const chartInstance = barChartRef.value.chart;
  // 调用getElementsAtEventForMode获取点击元素
  // mode参数可选'nearest'/'index'等,这里用'index'适配堆叠柱状图
  const activeElements = chartInstance.getElementsAtEventForMode(
    e,
    'index',
    { intersect: true },
    false
  );

  if (activeElements.length > 0) {
    // 提取点击柱子的索引、数据集索引及对应数据
    const index = activeElements[0].index;
    const datasetIndex = activeElements[0].datasetIndex;
    const clickedData = chartInstance.data.datasets[datasetIndex].data[index];
    const clickedLabel = chartInstance.data.labels?.[index];

    // 这里添加你的业务逻辑,比如打印或处理数据
    console.log(`点击标签: ${clickedLabel},对应数据: ${clickedData}`);
  }
}

完整修改后的代码片段

<script setup lang="ts">
import type { IChartObject } from '@/interfaces/IChartObject'
import type { IGrafica } from '@/interfaces/IGrafica'
import axios from 'axios'
import {
  Chart as ChartJS,
  Title,
  Tooltip,
  Legend,
  BarElement,
  CategoryScale,
  LinearScale,
  type ChartData
} from 'chart.js'
import { onMounted, onUnmounted, ref, watch } from 'vue'
import { Bar } from 'vue-chartjs'
import Pivot from 'quick-pivot'

ChartJS.register(CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend)
ChartJS.defaults.color = 'white'
let initalDataSet: string[][] = [['cuando', 'quien', 'cuanto']]
let pivot: any
let itemReactive = ref<ChartData<'bar'>>({
  datasets: []
})
let temporizador: any = null
// 新增:定义图表组件的ref
const barChartRef = ref<InstanceType<typeof Bar> | null>(null)

const props = defineProps<{
  url: string
}>()

watch(
  () => props.url,
  async (newUrl) => {
    await getDataset(newUrl)
  },
  { immediate: true }
)

const options = {
  responsive: true,
  maintainAspectRatio: true,
  scales: {
    x: {
      stacked: true
    },
    y: {
      stacked: true
    }
  },
  plugins: {
    legend: {
      display: false,
    }
  },
}
let object: IChartObject = {
  labels: [''],
  datasets: [
    {
      label: '',
      backgroundColor: '',
      barThickness: 0,
      borderRadius: 0,
      data: [{}]
    }
  ]
}

onMounted(() => {
  getDataset(props.url)
  temporizador = setInterval(paintChart, 300000)
})

onUnmounted(() => {
  clearInterval(temporizador)
})

async function paintChart() {
  await getDataset(props.url)
}

async function getDataset(url: string): Promise<void> {
  const response = await axios.get<IGrafica[]>(url)
  readyChartDataSet(response.data, object)
  itemReactive = object as any
  emptyObject()
}

function emptyObject(): void {
  object = {
    labels: [''],
    datasets: [
      {
        label: '',
        backgroundColor: '',
        barThickness: 0,
        borderRadius: 0,
        data: [{}]
      }
    ]
  }
}

function dameColorAleatorio(): string {
  //method that give a color to the label...
}

function readyChartDataSet(data: any, chart: IChartObject): void {
  //method that fullfill the dataset...
}

// 修改后的点击事件处理函数
function clickHandler(e: MouseEvent){
  if (!barChartRef.value?.chart) return;

  const chartInstance = barChartRef.value.chart;
  const activeElements = chartInstance.getElementsAtEventForMode(
    e,
    'index',
    { intersect: true },
    false
  );

  if (activeElements.length > 0) {
    const index = activeElements[0].index;
    const datasetIndex = activeElements[0].datasetIndex;
    const clickedData = chartInstance.data.datasets[datasetIndex].data[index];
    const clickedLabel = chartInstance.data.labels?.[index];

    console.log(`点击标签: ${clickedLabel},对应数据: ${clickedData}`);
    // 这里添加你的业务逻辑
  }
}
</script>
<template>
  <Bar 
    ref="barChartRef"
    :data="itemReactive" 
    id="barChart" 
    @click="clickHandler" 
    :options="options" 
    class="grafica" 
  />
</template>

关键说明

  • vue-chartjs组件会通过.chart属性暴露底层的Chart.js实例,这是获取实例的正确方式,避免直接操作DOM元素。
  • getElementsAtEventForMode的mode参数可按需调整:
    • 'nearest':获取距离点击位置最近的元素
    • 'index':获取同一x轴索引下的所有元素(适合堆叠柱状图)
    • 'dataset':获取同一数据集下的所有元素

内容的提问来源于stack exchange,提问作者francesco14

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 08:57:16