#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>