Вычислите и отобразите процентную разницу для каждого объекта в массиве в таблице данных Vue Vuetify

#javascript #arrays #vue.js #vuetify.js

Вопрос:

Я получаю данные из файла JSON, который выглядит следующим образом:

 {"USD": {"7d": 32053.72, "30d": 33194.68, "24h": 31370.42}, "AUD": {"7d": 43134.11, "30d": 44219.00, "24h": 42701.11}, "RUB": {"7d": 2451451.45, "30d": 2465896.74, "24h": 2398589.80},  "JPY": {"7d": 3537735.55, "30d": 3664620.47, "24h": 3472632.46}, "BRL": {"7d": 167555.18, "30d": 169473.27, "24h": 163054.93}, "ILS": {"7d": 108658.72, "30d": 111663.67, "24h": 106988.58}, "GBP": {"7d": 23257.66, "30d": 23838.55, "24h": 22923.17}, "PLN": {"7d": 124869.61, "30d": 127872.57, "24h": 122668.16}, "CAD": {"7d": 40425.62, "30d": 41444.76, "24h": 39827.13}, "EUR": {"7d": 27187.74, "30d": 27955.81, "24h": 26659.79}}
 

Позже я отобразил эти данные в таблице Vuetify, и то, чего я хочу добиться, — это заполнить thirtyDaysDiff столбец своей логикой расчета процента. Моя логика работает, и поле заполняется, но я должен вручную записать его для каждого объекта в массиве, которого я хотел бы избежать.

Как я могу применить следующую логику для каждого объекта в моем массиве вместо того, чтобы делать это вручную для каждого из них?

Логические:

  calculateThirtyDayDifference() {
    let calculatedPercent = 100 * Math.abs( ( this.bitcoinInfo[0]['7d'] - this.bitcoinInfo[0]['30d'] ) / ( (this.bitcoinInfo[0]['7d'] this.bitcoinInfo[0]['30d'])/2 ) )
    let roundedCalculatedPercent = Math.max( Math.round(calculatedPercent  * 10) / 10, 2.8 ).toFixed(2)
    this.bitcoinInfo[0].thirtyDaysDiff = roundedCalculatedPercent

    let secondCalculatedPercent = 100 * Math.abs( ( this.bitcoinInfo[1]['7d'] - this.bitcoinInfo[1]['30d'] ) / ( (this.bitcoinInfo[1]['7d'] this.bitcoinInfo[0]['30d'])/2 ) )
    let secondRoundedCalculatedPercent = Math.max( Math.round(secondCalculatedPercent  * 10) / 10, 2.8 ).toFixed(2)
    this.bitcoinInfo[1].thirtyDaysDiff = secondRoundedCalculatedPercent
}
 

Я пытался сделать это с forEach помощью, но это не сработало. Вот весь мой компонент:

 <template>
<div>
  <v-data-table
    :headers="headers"
    :items="bitcoinInfo"
    :hide-default-footer="true"
    :class="{active: group amp;amp; item.id == group.id}"
  >

  </v-data-table>
</div>

</template>

<script>
import axios from 'axios';

  export default {
    data () {
      return {
        bitcoinInfo: [],
        headers: [
          {
            text: 'Currency',
            align: 'start',
            value: 'currency',
          },
          
          { text: '30 Days Ago', value: '30d' },
          { text: '30 Day Diff %', value: 'thirtyDaysDiff'},
          { text: '7 Days Ago', value: '7d' },
          { text: '7 Day Diff %', value: 'sevenDaysDifference' },
          { text: '24 Hours Ago', value: '24h' },
        ],
      }
    },

    methods: {
      getBitcoinData() {
        axios
      .get('data.json')
      .then((response => {

      var convertedCollection =  Object.keys(response.data).map(key => {
            return {currency: key, thirtyDaysDiff: 0, sevenDaysDifference: 0,  ...response.data[key]}
          })

          this.bitcoinInfo = convertedCollection
          
      }))
      .catch(err => console.log(err))
        },

        calculateThirtyDayDifference() {
            let calculatedPercent = 100 * Math.abs( ( this.bitcoinInfo[0]['7d']  - this.bitcoinInfo[0]['30d'] ) / ( (this.bitcoinInfo[0]['7d'] this.bitcoinInfo[0]['30d'])/2 ) )
            let roundedCalculatedPercent = Math.max( Math.round(calculatedPercent  * 10) / 10, 2.8 ).toFixed(2)
            this.bitcoinInfo[0].thirtyDaysDiff = roundedCalculatedPercent


            let secondCalculatedPercent = 100 * Math.abs( ( this.bitcoinInfo[1]['7d']  - this.bitcoinInfo[1]['30d'] ) / ( (this.bitcoinInfo[1]['7d'] this.bitcoinInfo[0]['30d'])/2 ) )
            let secondRoundedCalculatedPercent = Math.max( Math.round(secondCalculatedPercent  * 10) / 10, 2.8 ).toFixed(2)
            this.bitcoinInfo[1].thirtyDaysDiff = secondRoundedCalculatedPercent

           
        }
      },
           
      mounted() {
        this.getBitcoinData()
      },
      updated() {
         this.calculateThirtyDayDifference()
      }
  }

</script>
 

Ответ №1:

Я рекомендую использовать слот и вычислять значения для отображения на лету.

Vuetify позволяет настраивать отображение ячеек определенного столбца с помощью слота
item.<column-key-name> (Я предпочитаю использовать #slotName синтаксис, но вы можете использовать v-slot:slotName его с тем же успехом):

 <template #item.thirtyDaysDiff="{ item }">
  {{ calculateThirtyDayDifference(item) }}%
</template>
 

Это позволяет нам передавать данные каждой строки (через свойство слота item ) в функцию вычисления, а затем отображать вычисленное значение для каждой, просто вызывая функцию для каждой строки.

Недостатком такого использования функции является то, что она будет повторно вызываться и пересчитываться при каждом рендеринге, но для простых вычислений, которые не должны вызывать никаких проблем с производительностью.


Вот полностью функциональный пример использования ваших тестовых данных:

 new Vue({
  // ## Required for snippet only ##
  el: '#app', template: '#app-template', vuetify: new Vuetify(),
  // #########
  data() {
    return {
      bitcoinInfo: [],
      headers: [{text:"Currency",align:"start",value:"currency"},{text:"30 Days Ago",value:"30d"},{text:"30 Day Diff %",value:"thirtyDaysDiff"},{text:"7 Days Ago",value:"7d"},{text:"7 Day Diff %",value:"sevenDaysDifference"},{text:"24 Hours Ago",value:"24h"}],
    }
  },
  methods: {
    calculateThirtyDayDifference(item) {
      let calculatedPercent = 100 * Math.abs((item['7d'] - item['30d']) / ((item['7d']   item['30d']) / 2));
      return Math.max(Math.round(calculatedPercent * 10) / 10, 2.8).toFixed(2);
    }
  },
  computed: {
    thirtyDayDiffArray() {
      return 1;
    },
  },
  mounted() {
    // Load sample data
    let sampleData = JSON.parse('{"USD": {"7d": 32053.72, "30d": 33194.68, "24h": 31370.42}, "AUD": {"7d": 43134.11, "30d": 44219.00, "24h": 42701.11}, "RUB": {"7d": 2451451.45, "30d": 2465896.74, "24h": 2398589.80},  "JPY": {"7d": 3537735.55, "30d": 3664620.47, "24h": 3472632.46}, "BRL": {"7d": 167555.18, "30d": 169473.27, "24h": 163054.93}, "ILS": {"7d": 108658.72, "30d": 111663.67, "24h": 106988.58}, "GBP": {"7d": 23257.66, "30d": 23838.55, "24h": 22923.17}, "PLN": {"7d": 124869.61, "30d": 127872.57, "24h": 122668.16}, "CAD": {"7d": 40425.62, "30d": 41444.76, "24h": 39827.13}, "EUR": {"7d": 27187.74, "30d": 27955.81, "24h": 26659.79}}');
    this.bitcoinInfo = Object.keys(sampleData)
      .map(key => ({
        currency: key,
        sevenDaysDifference: 0,
        ...sampleData[key]
      })
    );
  },
}) 
 <!-- Import Vuetify and Vue for snippet -->
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet"><link href="https://cdn.jsdelivr.net/npm/@mdi/font@4.x/css/materialdesignicons.min.css" rel="stylesheet"><link href="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.min.css" rel="stylesheet"><script src="https://cdn.jsdelivr.net/npm/vue@2.x/dist/vue.min.js"></script><script src="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.js"></script>

<!-- Target container for Vue to render into -->
<div id="app"></div>

<!-- Template that Vue will use --> 
<script type="text/x-template" id="app-template">
  <v-app>
    <v-data-table
      :headers="headers"
      :items="bitcoinInfo"
      :hide-default-footer="true"
    >
      <template #item.thirtyDaysDiff="{ item }">
        {{ calculateThirtyDayDifference(item) }}%
      </template>
    </v-data-table>
  </v-app>
</script>