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

Vue中动态修改Timeline Chart步长报错:this.chart未定义

你遇到的问题核心有三点:

  • stepSize普通函数里的this不指向Vue实例,导致访问this.chart报错
  • 错误直接访问Deferred对象的resolve属性获取Chart实例,Deferred的正确用法是通过promise链获取实例
  • 直接操作DOM元素不符合Vue响应式思路,且图表更新方式错误

修复方案

1. 简化Chart实例存储,弃用Deferred

直接在Vue组件的data中声明chart变量,mounted时创建Chart实例并赋值,避免Deferred带来的复杂度。

2. 用Vue响应式数据绑定输入框

在data中添加yStepSize和xStepSize,通过v-model绑定到输入框,让数据变化自动触发响应。

3. 用watch监听步长变化,自动更新图表

通过Vue的watch属性监听步长数据,修改Chart配置后调用update()刷新图表。

修改后的完整代码

<template>
    <div class="chart chart-timeline">
        <ChartLegend
            :items="legend"
            :allowFilterCreation="allowFilterCreation"
            @highlight="highlighted = $event"
            @toggle="toggleDatasetVisibility($event)"
            @apply-filter="$emit('apply-filter', $event)"
            v-if="legend"/>

        <div class="chart-container" v-show="hasData">
            <canvas ref="chart"></canvas>
            <hr><hr><hr> Stepsize Y
            <!-- 用v-model绑定响应式数值 -->
            <input type="number" v-model.number="yStepSize">
            <hr> Stepsize X
            <input type="number" v-model.number="xStepSize">
        </div>

        <h2 class="subtitle is-5" v-if="!hasData">
            No data
        </h2>
    </div>
</template>

<script>
import _ from "lodash";
import Chart from "chart.js";
import Moment from "moment";

import ChartLegend from "@/components/charts/ChartLegend";
import ChartMixin from "@/components/charts/ChartMixin";

export default {
    props: ["data", "multiMode", "labelConverter", "valueConverter", "allowFilterCreation"],
    components: { ChartLegend },
    mixins: [ChartMixin],
    data() {
        return {
            chart: null, // 直接存储Chart实例
            highlighted: null,
            yStepSize: 1, // Y轴步长响应式数据
            xStepSize: null // X轴步长响应式数据
        };
    },
    computed: {
        timeline() {
            return this.data ? _.map(this.data.parameter, it => new Moment(it)) : [];
        },

        keys() {
            return this.data ? _.map(this.data.datasets, it => it.name) : [];
        },
        labels() {
            const converter = this.labelConverter || _.identity;
            return _.map(this.keys, converter);
        },
        datasets() {
            return this.data ? _.map(this.data.datasets, it => it.data) : [];
        },

        datasetCount() {
            return this.datasets.length;
        },

        legend() {
            if (!this.multiMode) {
                return null;
            }

            return _.zipWith(this.keys, this.labels, this.palette, (key, text, color) => ({
                id: key,
                text,
                color: color.normal,
                hidden: _.includes(this.hiddenDatasets, key)
            }));
        },

        chartColors() {
            const highlightIndex = this.highlighted !== null && !_.includes(this.hiddenDatasets, this.highlighted)
                ? _.indexOf(this.keys, this.highlighted)
                : null;

            const colors = [];
            for (const index of _.keys(this.datasets)) {
                const color = this.palette[index];
                if (highlightIndex !== null) {
                    if (index == highlightIndex) {
                        colors.push({ backgroundColor: color.strongMuted, borderColor: color.strong });
                    } else {
                        colors.push({ backgroundColor: color.weakMuted, borderColor: color.weak });
                    }
                } else {
                    colors.push({ backgroundColor: color.normalMuted, borderColor: color.normal });
                }
            }

            return colors;
        }
    },
    mounted() {
        // 创建Chart实例并赋值给data变量
        this.chart = new Chart(this.$refs.chart,  {
            type: "line",
            data: {
                datasets: [],
                labels: []
            },
            options: {
                maintainAspectRatio: false,
                legend: { display: false },
                scales: {
                    xAxes: [{
                        type: "time",
                        time: {
                            isoWeekday: true,
                            displayFormats: {
                                hour: "HH:mm",
                                day: "DD-MM",
                                week: "DD-MM",
                                month: "MM-YYYY"
                            }
                        },
                        ticks: { source: "labels" }
                    }],
                    yAxes: [{
                        ticks: { min: 0, precision: 0, stepSize: this.yStepSize }
                    }]
                },
                spanGaps: false,
                tooltips: {
                    callbacks: {
                        label: item => {
                            const converter = this.valueConverter || _.identity;
                            const label = this.multiMode ? (this.labels[item.datasetIndex] + ": ") : "";
                            return label + converter(this.datasets[item.datasetIndex][item.index]);
                        }
                    }
                }
            }
        });
    },
    watch: {
        data() {
            this.resetDatasetVisibility();
        },
        // 监听Y轴步长变化,更新图表配置
        yStepSize(newVal) {
            if (this.chart) {
                this.chart.options.scales.yAxes[0].ticks.stepSize = newVal;
                this.chart.update();
            }
        },
        // 监听X轴步长变化,更新图表配置
        xStepSize(newVal) {
            if (this.chart) {
                this.chart.options.scales.xAxes[0].ticks.stepSize = newVal;
                this.chart.update();
            }
        }
    }
}
</script>

关键修改说明

  • 移除Deferred,直接存储Chart实例,避免异步获取实例的错误
  • 输入框用v-model.number绑定,自动处理数值类型,无需手动查询DOM
  • 通过watch监听步长数据变化,自动触发图表更新,符合Vue响应式逻辑
  • 更新图表时直接修改chart.options配置,调用chart.update()是Chart.js官方推荐的刷新方式

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 02:30:40