问题描述
如何自动计算当前行和上一行之间的值差异。我在 Vue 和 Vuetify 中使用“数据表”。 在我的代码中,我添加了静态值来说明我想要做什么(“卡路里变化”列)。此列不应可用于添加和编辑。
如果以前的值大于当前值 - 我想显示具有差异值的“-”。
如果以前的值小于当前值 - 我想显示带有差异值的“+”。
如果值相同 - 我想显示“0”。
在这个例子中,重点是我想知道接下来几天我吃了多少(更多、更少或相同)卡路里。
有人可以帮忙处理这个案子吗?
演示: Codepen
HTML:
<div id="app">
<v-app id="inspire">
<v-data-table
:headers="headers"
:items="results"
sort-by="date"
sort-desc
class="elevation-1"
>
<template v-slot:top>
<v-toolbar
flat
>
<v-toolbar-title>Data</v-toolbar-title>
<v-divider
class="mx-4"
inset
vertical
></v-divider>
<v-spacer></v-spacer>
<v-dialog
v-model="dialog"
max-width="500px"
>
<template v-slot:activator="{ on,attrs }">
<v-btn
color="primary"
dark
class="mb-2"
v-bind="attrs"
v-on="on"
>
Add new
</v-btn>
</template>
<v-card>
<v-card-title>
<span class="headline">{{ formTitle }}</span>
</v-card-title>
<v-card-text>
<v-container>
<v-row>
<v-col
cols="12"
sm="6"
md="6"
>
<v-menu
ref="dateMenu"
v-model="dateMenu"
:close-on-content-click="false"
:return-value.sync="editedItem.date"
transition="scale-transition"
offset-y
min-width="auto"
>
<template v-slot:activator="{ on,attrs }">
<v-text-field
v-model="editedItem.date"
label="Select date"
prepend-icon="mdi-calendar"
readonly
v-bind="attrs"
v-on="on"
></v-text-field>
</template>
<v-date-picker
v-model="editedItem.date"
no-title
scrollable
>
<v-spacer></v-spacer>
<v-btn
text
color="primary"
@click="dateMenu = false"
>
Cancel
</v-btn>
<v-btn
text
color="primary"
@click="$refs.dateMenu.save(editedItem.date)"
>
OK
</v-btn>
</v-date-picker>
</v-menu>
</v-col>
<v-col
cols="12"
sm="6"
md="6"
>
<v-text-field
v-model="editedItem.calories"
label="Calories"
></v-text-field>
</v-col>
</v-row>
</v-container>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
color="blue darken-1"
text
@click="close"
>
Cancel
</v-btn>
<v-btn
color="blue darken-1"
text
@click="save"
>
Save
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<v-dialog v-model="dialogDelete" max-width="500px">
<v-card>
<v-card-title class="headline">Are you sure you want to delete this item?</v-card-title>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="blue darken-1" text @click="closeDelete">Cancel</v-btn>
<v-btn color="blue darken-1" text @click="deleteItemConfirm">OK</v-btn>
<v-spacer></v-spacer>
</v-card-actions>
</v-card>
</v-dialog>
</v-toolbar>
</template>
<template v-slot:item.actions="{ item }">
<v-icon
small
class="mr-2"
@click="editItem(item)"
>
mdi-pencil
</v-icon>
<v-icon
small
@click="deleteItem(item)"
>
mdi-delete
</v-icon>
</template>
<template v-slot:no-data>
No results
</template>
</v-data-table>
</v-app>
</div>
JS:
new Vue({
el: '#app',vuetify: new Vuetify(),data: () => ({
dateMenu: false,dialog: false,dialogDelete: false,headers: [
{
text: 'Date',align: 'start',sortable: true,value: 'date',},{ text: 'Calories (kcal)',value: 'calories' },{ text: 'Calories difference',value: 'caloriesChange',sortable: false },{ text: 'Actions',value: 'actions',],results: [],editedindex: -1,editedItem: {
date: new Date().toISOString().substr(0,10),calories: 0,// this should calculate automatically
caloriesChange: 0,defaultItem: {
date: new Date().toISOString().substr(0,}),computed: {
formTitle () {
return this.editedindex === -1 ? 'New Item' : 'Edit Item'
},watch: {
dialog (val) {
val || this.close()
},dialogDelete (val) {
val || this.closeDelete()
},created () {
this.initialize()
},methods: {
initialize () {
this.results = [
{
date: '2021-01-09',calories: 2905,// this should calculate automatically
caloriesChange: '+ ' + 55 + ' kcal',{
date: '2021-01-08',calories: 2850,// this should calculate automatically
caloriesChange: '+ ' + 150 + ' kcal',{
date: '2021-01-07',calories: 2700,// this should calculate automatically
caloriesChange: '- ' + 800 + ' kcal',{
date: '2021-01-06',calories: 3500,// this should calculate automatically
caloriesChange: '+ ' + 300 + ' kcal',{
date: '2021-01-05',calories: 3200,{
date: '2021-01-04',calories: 2900,// this should calculate automatically
caloriesChange: '' + 0 + ' kcal',{
date: '2021-01-03',// this should calculate automatically
caloriesChange: '- ' + 100 + ' kcal',{
date: '2021-01-02',calories: 3000,// this should calculate automatically
caloriesChange: '- ' + 10 + ' kcal',{
date: '2021-01-01',calories: 3010,// this should calculate automatically
caloriesChange: '+ ' + 10 + ' kcal',{
date: '2020-12-31',// this must be empty (first result)
caloriesChange: '',]
},editItem (item) {
this.editedindex = this.results.indexOf(item)
this.editedItem = Object.assign({},item)
this.dialog = true
},deleteItem (item) {
this.editedindex = this.results.indexOf(item)
this.editedItem = Object.assign({},item)
this.dialogDelete = true
},deleteItemConfirm () {
this.results.splice(this.editedindex,1)
this.closeDelete()
},close () {
this.dialog = false
this.$nextTick(() => {
this.editedItem = Object.assign({},this.defaultItem)
this.editedindex = -1
})
},closeDelete () {
this.dialogDelete = false
this.$nextTick(() => {
this.editedItem = Object.assign({},save () {
if (this.editedindex > -1) {
Object.assign(this.results[this.editedindex],this.editedItem)
} else {
this.results.push(this.editedItem)
}
this.close()
},})
解决方法
如何使用计算得到的 getter 根据结果映射一个新数组?
类似于:
computed: {
...,calcResults () {
let sortedResults = this.results.sort(function(a,b){
return new Date(b.date) - new Date(a.date);
}).reverse();
return sortedResults.map((result,index,results) => {
let caloriesChange = index > 0 ? results[index].calories - results[index - 1].calories + ' kCal': '';
return {
date: result.date,calories: result.calories,caloriesChange: caloriesChange
}
});
}
},
在你的 HTML 中:
<v-data-table
:headers="headers"
:items="calcResults"
sort-by="date"
sort-desc
class="elevation-1"
>
,
您可以在 computed
字段中创建方法:
computedResults() {
return this.results.map((e,i,arr) => {
let caloriesChange = i < arr.length - 1 ? arr[i + 1].calories - e.calories : '';
if(caloriesChange > 0) {
caloriesChange = `+${caloriesChange}`;
}
return {
...e,caloriesChange
}
});
}
而不是传递 results
,而是在 computedResults
中传递 <v-data-table />
:
<v-data-table
:headers="headers"
:items="computedResults"
sort-by="date"
sort-desc
class="elevation-1"
>
检查 codepen