VueJS + Chartjs - 图表仅在代码更改后呈现

VueJS + Chartjs - Chart only renders after code change

我正在使用以下教程(为 NPM 包拉取下载统计信息)为我绘制的 webapp 打下基础:

我从教程中提取了以下代码并对其进行了修改,因此它可以执行纯基础知识。获取数据并呈现数据。具体来自这些:

请注意: 代码执行 API 调用并检索数据没有问题。但是,如果我更改代码,它只会在图表中呈现该数据。例如,将线条的颜色更改为其他颜色。如果有意义的话,它似乎只适用于下一个 'cycle'。数据呈现后,如果我刷新该页面,它又是空白的。我怀疑这与页面时间有关。但是不确定从哪里开始或我在寻找什么。

App.Vue

<template>
  <v-app style="background-color: rgb(228, 228, 228);">
    <section class="One">    
      <v-card class="One" color="rgb(255, 255, 255)" >

            <LineChart :chart-data="downloads" :chart-labels="labels"/>

      </v-card>
    </section>    
   </v-app>
</template>



<script>
import axios from 'axios';
import LineChart from  './components/test3.vue';


export default {
  name: 'App',

  components: { 
    LineChart,

  },
    data () {
      return {
        package: '',
        packageName: '',
        loaded: false,
        loading: false,
        downloads: [],
        downloadsYear: [],
        downloadsMonth: [],
        downloadsWeek: [],
        labels: [],
        labelsYear: [],
        labelsMonth: [],
        labelsWeek: [],
        showError: false,
        showSettings: false,
        errorMessage: 'Please enter a package name',
        periodStart: '',
        periodEnd: new Date(),
        rawData: '',
        totalDownloads: '',
        dailyPng: null,
        weeklyPng: null,
        monthlyPng: null,
        yearlyPng: null
      }
    },

mounted(){

        this.loaded = false
        axios.get(`https://api.npmjs.org/downloads/range/2017-01-01:2017-04-19/vue`)
          .then(response => {
            this.rawData = response.data.downloads
            this.downloads = response.data.downloads.map(entry => entry.downloads)
            this.labels = response.data.downloads.map(entry => entry.day)
            this.packageName = response.data.package
            this.totalDownloads = this.downloads.reduce((total, download) => total + download)
            this.setURL()
            this.groupDataByDate()
            this.loaded = true
            this.loading = false
          })
          .catch(err => {
            this.errorMessage = err.response.data.error
            this.loading = false
          })
      },
};

</script>

图表组件:

<script>
  import { Line } from 'vue-chartjs'

  export default {
    extends: Line,

    props: {
      chartData: {
        type: Array,
        required: false
      },
      chartLabels: {
        type: Array,
        required: true
      }
    },
    data () {
      return {
        gradient: null,
        options: {
          showScale: true,
          scales: {
            yAxes: [{
              ticks: {
                beginAtZero: false,

              },
              gridLines: {
                display: true,
                color: '#EEF0F4',
                borderDash: [5, 15]
              }
            }],
            xAxes: [ {
              gridLines: {
                display: true,
                color: '#EEF0F4',
                borderDash: [5, 15]
              }
            }]
          },
          tooltips: {
            backgroundColor: '#4F5565',
            titleFontStyle: 'normal',
            titleFontSize: 18,
            bodyFontFamily: "'Proxima Nova', sans-serif",
            cornerRadius: 3,
            bodyFontColor: '#20C4C8',
            bodyFontSize: 14,
            xPadding: 14,
            yPadding: 14,
            displayColors: false,
            mode: 'index',
            intersect: false,
            callbacks: {
              title: tooltipItem => {
                return ` ${tooltipItem[0].xLabel}`
              },
              label: (tooltipItem, data) => {
                let dataset = data.datasets[tooltipItem.datasetIndex]
                let currentValue = dataset.data[tooltipItem.index]
                return ` ${currentValue.toLocaleString()}`
              }
            }
          },
          legend: {
            display: false
          },
          responsive: true,
          maintainAspectRatio: false
        }
      }
    },
    mounted () {
      this.gradient = this.$refs.canvas
        .getContext('2d')
        .createLinearGradient(0, 0, 0, 450)
      this.gradient.addColorStop(0, 'rgba(52, 217, 221, 0.6)')
      this.gradient.addColorStop(0.5, 'rgba(52, 217, 221, 0.25)')
      this.gradient.addColorStop(1, 'rgba(52, 217, 221, 0)')
      this.renderChart({
        labels: this.chartLabels,
        datasets: [
          {
            label: 'downloads',
            borderColor: '#249EBF',
            pointBackgroundColor: 'rgba(0,0,0,0)',
            pointBorderColor: 'rgba(0,0,0,0)',
            pointHoverBorderColor: '#249EBF',
            pointHoverBackgroundColor: '#fff',
            pointHoverRadius: 4,
            pointHitRadius: 10,
            pointHoverBorderWidth: 1,
            borderWidth: 1,
            backgroundColor: this.gradient,
            data: this.chartData
          }
        ]
      }, this.options)
      setTimeout(() => {
        this.download()
      }, 500)
    },
    methods: {
      formatNumber (num) {
        let numString = Math.round(num).toString()
        let numberFormatMapping = [[6, 'm'], [3, 'k']]
        for (let [numberOfDigits, replacement] of numberFormatMapping) {
          if (numString.length > numberOfDigits) {
            let decimal = ''
            if (numString[numString.length - numberOfDigits] !== '0') {
              decimal = '.' + numString[numString.length - numberOfDigits]
            }
            numString = numString.substr(0, numString.length - numberOfDigits) + decimal + replacement
            break
          }
        }
        return numString
      }
    }
  }
</script>

您需要通知子组件重新渲染自己。 添加一个 watcher 是一种方法,观察数据变化并更新它。

另一种更简单的方法是,向其添加一个 key 道具。

在你的 App.vue 中,这样做:

 <LineChart :chart-data="downloads" :chart-labels="labels" :key="downloads.length"/>

这里我使用 downloads 的长度作为键值。这是向您展示如何使用 key 的简单临时解决方案。在您的应用中,您应该使用其他一些值作为键,以防不同的 api 调用 returns 相同长度的数据。

您还可以将键设置为另一个值,并在每次调用 api 时更改此值。