在 nuxt.js 项目中重新渲染 vue-chart

Rerender vue-chart in a nuxt.js project

我正在做一个nuxt项目,需要画一些图表。为此,我使用 vue-chartjs 作为插件。不幸的是,图表数据是在图表绘制后获取的,这导致图表为空。当数据准备好时,我找不到访问插件和重新呈现图表的方法。这是插件的代码:

// plugins/vue-chart.js

import Vue from 'vue'
import { Bar, Doughnut, Line, Pie } from 'vue-chartjs'

const registerComponent = function (name, originalComponent) {
  Vue.component(
    name,
    {
      extends: originalComponent,
      props: ['data', 'options'],
      mounted () {
        this.renderChart(this.data, this.options)
      },
      updated () {
        this.renderChart(this.data, this.options)
      }
    }
  )
}

registerComponent('BarChart', Bar)
registerComponent('DoughnutChart', Doughnut)
registerComponent('LineChart', Line)
registerComponent('PieChart', Pie)

下面是我如何使用插件绘制折线图:

components/Charts.vue

<template>
  <client-only>
    <LineChart :data="lineData" :options="options" />
  </client-only>
</template>

<script>
export default {
  data() {
    return {
      loading: true,
      lineData: {
        labels: [],
        datasets: [
          {
            label: 'Close',
            data: [],
          },
          {
            label: 'High',
            data: [],
          },
        ],
      },
      options: {
        responsive: true,
        scales: {
          x: {
            display: true,
            title: {
              display: true,
            },
          },
          y: {
            display: true,
            title: {
              display: true,
              text: 'Value',
            },
          },
        },
      },
    }
  },
  async mounted() {
    try {
      const response = await this.$axios.get('/api/entries')
      if (response.status === 200) {
        for (let i = 0; i < response.data.length; i++) {
          this.lineData.labels.push(response.data[i].date)
          this.lineData.datasets[0].data.push(response.data[i].close)
          this.lineData.datasets[1].data.push(response.data[i].high)
        }
      }
    } catch (e) {
      console.log(e)
    }
  },
}
</script>

我很高兴收到有关如何解决此问题的任何建议!

编辑 我不得不降级 chart.jsvue-chartjs 的版本,以便项目编译。

这是我的package.json

{
  "name": "xyz",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "dev-fe": "nuxt",
    "build": "nuxt build",
    "start": "nuxt start",
    "generate": "nuxt generate",
    "lint:js": "eslint --ext \".js,.vue\" --ignore-path .gitignore .",
    "lint": "npm run lint:js"
  },
  "dependencies":
    "@nuxtjs/axios": "^5.13.6",
    "chart.js": "^2.7.1",
    "core-js": "^3.15.1",
    "nuxt": "^2.15.7",
    "vue": "^2.6.14",
    "vue-chartjs": "^3.4.0"
  },
  "devDependencies": {
    "@babel/eslint-parser": "^7.14.7",
    "@nuxtjs/eslint-config": "^6.0.1",
    "@nuxtjs/eslint-module": "^3.0.2",
    "@nuxtjs/tailwindcss": "^4.2.0",
    "eslint": "^7.29.0",
    "eslint-plugin-nuxt": "^2.0.0",
    "eslint-plugin-vue": "^7.12.1",
    "postcss": "^8.3.5"
  }
}

我在 nuxt.config.js 中几乎使用默认值,除了我添加了

{ src: '~/plugins/vue-chart.js', mode: 'client' }

到插件。

好的,我得到了一个工作示例,如下所示。

这是我的 vue-chartjs.js 插件

import Vue from 'vue'
import { Bar, Doughnut, Line, Pie, mixins } from 'vue-chartjs'

const registerComponent = function (name, originalComponent) {
  Vue.component(name, {
    extends: originalComponent,
    mixins: [mixins.reactiveProp],
    props: {
      chartData: {
        type: Object,
        default: () => {},
      },
      chartOptions: {
        type: Object,
        default: () => {},
      },
    },
    mounted() {
      this.renderChart(this.chartData, this.chartOptions)
    },
  })
}

registerComponent('BarChart', Bar)
registerComponent('DoughnutChart', Doughnut)
registerComponent('LineChart', Line)
registerComponent('PieChart', Pie)

/pages/index.vue

<template>
  <div>
    <line-chart
      :key="updated"
      :chart-data="lineData"
      :chart-options="options"
    />
  </div>
</template>

<script>
import FakeData from '@/fake.json'

export default {
  data() {
    return {
      updated: 0,
      lineData: {
        labels: [],
        datasets: [
          {
            label: 'Data One',
            backgroundColor: '',
            data: [],
          },
          {
            label: 'Data Two',
            backgroundColor: '',
            data: [],
          },
        ],
      },
      options: {
        responsive: true,
        scales: {
          x: {
            display: true,
            title: {
              display: true,
            },
          },
          y: {
            display: true,
            title: {
              display: true,
              text: 'Value',
            },
          },
        },
      },
    }
  },
  async fetch() {
    const response = await fetch('https://jsonplaceholder.typicode.com/todos/1')
    const data = await response.json()
    console.log('fake API title fetched:', data.title)

    const actualData = FakeData.data
    for (let i = 0; i < actualData.length; i++) {
      this.lineData.labels.push(actualData[i].date)
      this.lineData.datasets[0].backgroundColor = actualData[i].color1
      this.lineData.datasets[0].data.push(actualData[i].close)
      this.lineData.datasets[1].backgroundColor = actualData[i].color2
      this.lineData.datasets[1].data.push(actualData[i].high)
    }
    this.updated++
  },
}
</script>

和我的假 .json API 数据,因为我没有 API 来获取一些真实数据

{
  "data": [
    {
      "date": "Jan",
      "color1": "#EC368D",
      "color2": "#51E5FF",
      "close": "0.4",
      "high": "0.7"
    },
    {
      "date": "Feb",
      "color1": "#EC368D",
      "color2": "#51E5FF",
      "close": "0.2",
      "high": "0.5"
    },
    {
      "date": "Mar",
      "color1": "#EC368D",
      "color2": "#51E5FF",
      "close": "0.6",
      "high": "0.8"
    }
  ]
}

我仍然嘲笑了一个 API 调用,所以它应该可以很好地作为您的示例。

这背后的想法是使用 key hack,这并不是那么好,但是嗯,维护者并没有真正帮助人们正确地使用 IMO。

所以这仍然是最好的。

这是我的最终结果和相关的Github repo