数据表格
v-data-table
组件用于显示表格数据。功能包括排序、搜索、分页、内嵌式编辑和行选择。
用例
标准数据表格默认将您的数据作为简单行渲染。
template script
<template>
<v-data-table
:headers="headers"
:items="desserts"
:items-per-page="5"
class="elevation-1"
></v-data-table>
</template>
<script>
export default {
data () {
return {
headers: [
{
text: 'Dessert (100g serving)',
align: 'start',
sortable: false,
value: 'name',
},
{ text: 'Calories', value: 'calories' },
{ text: 'Fat (g)', value: 'fat' },
{ text: 'Carbs (g)', value: 'carbs' },
{ text: 'Protein (g)', value: 'protein' },
{ text: 'Iron (%)', value: 'iron' },
],
desserts: [
{
name: 'Frozen Yogurt',
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
iron: '1%',
},
{
name: 'Ice cream sandwich',
calories: 237,
fat: 9.0,
carbs: 37,
protein: 4.3,
iron: '1%',
},
{
name: 'Eclair',
calories: 262,
fat: 16.0,
carbs: 23,
protein: 6.0,
iron: '7%',
},
{
name: 'Cupcake',
calories: 305,
fat: 3.7,
carbs: 67,
protein: 4.3,
iron: '8%',
},
{
name: 'Gingerbread',
calories: 356,
fat: 16.0,
carbs: 49,
protein: 3.9,
iron: '16%',
},
{
name: 'Jelly bean',
calories: 375,
fat: 0.0,
carbs: 94,
protein: 0.0,
iron: '0%',
},
{
name: 'Lollipop',
calories: 392,
fat: 0.2,
carbs: 98,
protein: 0,
iron: '2%',
},
{
name: 'Honeycomb',
calories: 408,
fat: 3.2,
carbs: 87,
protein: 6.5,
iron: '45%',
},
{
name: 'Donut',
calories: 452,
fat: 25.0,
carbs: 51,
protein: 4.9,
iron: '22%',
},
{
name: 'KitKat',
calories: 518,
fat: 26.0,
carbs: 65,
protein: 7,
iron: '6%',
},
],
}
},
}
</script>
API
从下面选择您想要的组件,并查看可用的属性、插槽、事件和函数。
示例
下面是一些简单到复杂的例子。
行选择框
show-select
属性将在默认标题中呈现一个复选框来切换所有行,并为每个默认行呈现一个复选框。你可以自定义 header.data-table-select
和 item.data-table-select
这些插槽的标题。您也可以在一次允许多个选定行之间进行切换,也可以使用 single-select
属性仅允许一次进行切换。
template script
<template>
<v-data-table
v-model="selected"
:headers="headers"
:items="desserts"
:single-select="singleSelect"
item-key="name"
show-select
class="elevation-1"
>
<template v-slot:top>
<v-switch v-model="singleSelect" label="Single select" class="pa-3"></v-switch>
</template>
</v-data-table>
</template>
<script>
export default {
data () {
return {
singleSelect: false,
selected: [],
headers: [
{
text: 'Dessert (100g serving)',
align: 'start',
sortable: false,
value: 'name',
},
{ text: 'Calories', value: 'calories' },
{ text: 'Fat (g)', value: 'fat' },
{ text: 'Carbs (g)', value: 'carbs' },
{ text: 'Protein (g)', value: 'protein' },
{ text: 'Iron (%)', value: 'iron' },
],
desserts: [
{
name: 'Frozen Yogurt',
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
iron: '1%',
},
{
name: 'Ice cream sandwich',
calories: 237,
fat: 9.0,
carbs: 37,
protein: 4.3,
iron: '1%',
},
{
name: 'Eclair',
calories: 262,
fat: 16.0,
carbs: 23,
protein: 6.0,
iron: '7%',
},
{
name: 'Cupcake',
calories: 305,
fat: 3.7,
carbs: 67,
protein: 4.3,
iron: '8%',
},
{
name: 'Gingerbread',
calories: 356,
fat: 16.0,
carbs: 49,
protein: 3.9,
iron: '16%',
},
{
name: 'Jelly bean',
calories: 375,
fat: 0.0,
carbs: 94,
protein: 0.0,
iron: '0%',
},
{
name: 'Lollipop',
calories: 392,
fat: 0.2,
carbs: 98,
protein: 0,
iron: '2%',
},
{
name: 'Honeycomb',
calories: 408,
fat: 3.2,
carbs: 87,
protein: 6.5,
iron: '45%',
},
{
name: 'Donut',
calories: 452,
fat: 25.0,
carbs: 51,
protein: 4.9,
iron: '22%',
},
{
name: 'KitKat',
calories: 518,
fat: 26.0,
carbs: 65,
protein: 7,
iron: '6%',
},
],
}
},
}
</script>
分组行
使用 group-by
和 group-desc
属性可以将项目的属性的行进行分组。show-group-by
属性将在默认标题中显示一个组按钮。
template script
<template>
<v-data-table
:headers="headers"
:items="desserts"
item-key="name"
group-by="category"
class="elevation-1"
show-group-by
></v-data-table>
</template>
<script>
export default {
data () {
return {
headers: [
{
text: 'Dessert (100g serving)',
align: 'start',
value: 'name',
},
{ text: 'Category', value: 'category' },
],
desserts: [
{
name: 'Frozen Yogurt',
category: 'Ice cream',
},
{
name: 'Ice cream sandwich',
category: 'Ice cream',
},
{
name: 'Eclair',
category: 'Cookie',
},
{
name: 'Cupcake',
category: 'Pastry',
},
{
name: 'Gingerbread',
category: 'Cookie',
},
{
name: 'Jelly bean',
category: 'Candy',
},
{
name: 'Lollipop',
category: 'Candy',
},
{
name: 'Honeycomb',
category: 'Toffee',
},
{
name: 'Donut',
category: 'Pastry',
},
{
name: 'KitKat',
category: 'Candy',
},
],
}
},
}
</script>
按多列排序
使用 multi-sort
属性将使您可以同时对多个列进行排序。 启用后,您可以将数组传递给 sort-by
和 sort-desc
来以编程方式控制排序,而不是单个值。
template script
<template>
<v-data-table
:headers="headers"
:items="desserts"
:sort-by="['calories', 'fat']"
:sort-desc="[false, true]"
multi-sort
class="elevation-1"
></v-data-table>
</template>
<script>
export default {
data () {
return {
headers: [
{
text: 'Dessert (100g serving)',
align: 'start',
sortable: false,
value: 'name',
},
{ text: 'Calories', value: 'calories' },
{ text: 'Fat (g)', value: 'fat' },
{ text: 'Carbs (g)', value: 'carbs' },
{ text: 'Protein (g)', value: 'protein' },
{ text: 'Iron (%)', value: 'iron' },
],
desserts: [
{
name: 'Frozen Yogurt',
calories: 200,
fat: 6.0,
carbs: 24,
protein: 4.0,
iron: '1%',
},
{
name: 'Ice cream sandwich',
calories: 200,
fat: 9.0,
carbs: 37,
protein: 4.3,
iron: '1%',
},
{
name: 'Eclair',
calories: 300,
fat: 16.0,
carbs: 23,
protein: 6.0,
iron: '7%',
},
{
name: 'Cupcake',
calories: 300,
fat: 3.7,
carbs: 67,
protein: 4.3,
iron: '8%',
},
{
name: 'Gingerbread',
calories: 400,
fat: 16.0,
carbs: 49,
protein: 3.9,
iron: '16%',
},
{
name: 'Jelly bean',
calories: 400,
fat: 0.0,
carbs: 94,
protein: 0.0,
iron: '0%',
},
{
name: 'Lollipop',
calories: 400,
fat: 0.2,
carbs: 98,
protein: 0,
iron: '2%',
},
{
name: 'Honeycomb',
calories: 400,
fat: 3.2,
carbs: 87,
protein: 6.5,
iron: '45%',
},
{
name: 'Donut',
calories: 500,
fat: 25.0,
carbs: 51,
protein: 4.9,
iron: '22%',
},
{
name: 'KitKat',
calories: 500,
fat: 26.0,
carbs: 65,
protein: 7,
iron: '6%',
},
],
}
},
}
</script>
搜索
数据表格还提供了一个 search
属性,允许你进行数据筛选。
template script
<template>
<v-card>
<v-card-title>
Nutrition
<v-spacer></v-spacer>
<v-text-field
v-model="search"
append-icon="mdi-magnify"
label="Search"
single-line
hide-details
></v-text-field>
</v-card-title>
<v-data-table
:headers="headers"
:items="desserts"
:search="search"
></v-data-table>
</v-card>
</template>
<script>
export default {
data () {
return {
search: '',
headers: [
{
text: 'Dessert (100g serving)',
align: 'start',
sortable: false,
value: 'name',
},
{ text: 'Calories', value: 'calories' },
{ text: 'Fat (g)', value: 'fat' },
{ text: 'Carbs (g)', value: 'carbs' },
{ text: 'Protein (g)', value: 'protein' },
{ text: 'Iron (%)', value: 'iron' },
],
desserts: [
{
name: 'Frozen Yogurt',
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
iron: '1%',
},
{
name: 'Ice cream sandwich',
calories: 237,
fat: 9.0,
carbs: 37,
protein: 4.3,
iron: '1%',
},
{
name: 'Eclair',
calories: 262,
fat: 16.0,
carbs: 23,
protein: 6.0,
iron: '7%',
},
{
name: 'Cupcake',
calories: 305,
fat: 3.7,
carbs: 67,
protein: 4.3,
iron: '8%',
},
{
name: 'Gingerbread',
calories: 356,
fat: 16.0,
carbs: 49,
protein: 3.9,
iron: '16%',
},
{
name: 'Jelly bean',
calories: 375,
fat: 0.0,
carbs: 94,
protein: 0.0,
iron: '0%',
},
{
name: 'Lollipop',
calories: 392,
fat: 0.2,
carbs: 98,
protein: 0,
iron: '2%',
},
{
name: 'Honeycomb',
calories: 408,
fat: 3.2,
carbs: 87,
protein: 6.5,
iron: '45%',
},
{
name: 'Donut',
calories: 452,
fat: 25.0,
carbs: 51,
protein: 4.9,
iron: '22%',
},
{
name: 'KitKat',
calories: 518,
fat: 26.0,
carbs: 65,
protein: 7,
iron: '6%',
},
],
}
},
}
</script>
无头表格
您可以使用 hide-default-header
和 hide-default-footer
属性分别移除默认页眉和页脚。
template script
<template>
<v-data-table
:headers="headers"
:items="desserts"
hide-default-header
hide-default-footer
class="elevation-1"
></v-data-table>
</template>
<script>
export default {
data () {
return {
headers: [
{
text: 'Dessert (100g serving)',
align: 'start',
value: 'name',
},
{ text: 'Calories', value: 'calories' },
{ text: 'Fat (g)', value: 'fat' },
{ text: 'Carbs (g)', value: 'carbs' },
{ text: 'Protein (g)', value: 'protein' },
{ text: 'Iron (%)', value: 'iron' },
],
desserts: [
{
name: 'Frozen Yogurt',
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
iron: '1%',
},
{
name: 'Ice cream sandwich',
calories: 237,
fat: 9.0,
carbs: 37,
protein: 4.3,
iron: '1%',
},
{
name: 'Eclair',
calories: 262,
fat: 16.0,
carbs: 23,
protein: 6.0,
iron: '7%',
},
{
name: 'Cupcake',
calories: 305,
fat: 3.7,
carbs: 67,
protein: 4.3,
iron: '8%',
},
{
name: 'Gingerbread',
calories: 356,
fat: 16.0,
carbs: 49,
protein: 3.9,
iron: '16%',
},
{
name: 'Jelly bean',
calories: 375,
fat: 0.0,
carbs: 94,
protein: 0.0,
iron: '0%',
},
{
name: 'Lollipop',
calories: 392,
fat: 0.2,
carbs: 98,
protein: 0,
iron: '2%',
},
{
name: 'Honeycomb',
calories: 408,
fat: 3.2,
carbs: 87,
protein: 6.5,
iron: '45%',
},
{
name: 'Donut',
calories: 452,
fat: 25.0,
carbs: 51,
protein: 4.9,
iron: '22%',
},
{
name: 'KitKat',
calories: 518,
fat: 26.0,
carbs: 65,
protein: 7,
iron: '6%',
},
],
}
},
}
</script>
加载状态
您可以使用 loading
属性来表示表中的数据正在加载中。 如果表中没有数据,也会显示加载消息。 此消息可以使用 loading-text
属性或 loading
插槽自定义。
template
<template>
<v-data-table item-key="name" class="elevation-1" loading loading-text="Loading... Please wait"></v-data-table>
</template>
密集
使用 dense
属性,您可以为数据表提供其他样式。
template script
<template>
<v-data-table dense :headers="headers" :items="desserts" item-key="name" class="elevation-1"></v-data-table>
</template>
<script>
export default {
data: () => ({
desserts: [
{
name: 'Frozen Yogurt',
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
iron: '1%',
},
{
name: 'Ice cream sandwich',
calories: 237,
fat: 9.0,
carbs: 37,
protein: 4.3,
iron: '1%',
},
{
name: 'Eclair',
calories: 262,
fat: 16.0,
carbs: 23,
protein: 6.0,
iron: '7%',
},
{
name: 'Cupcake',
calories: 305,
fat: 3.7,
carbs: 67,
protein: 4.3,
iron: '8%',
},
{
name: 'Gingerbread',
calories: 356,
fat: 16.0,
carbs: 49,
protein: 3.9,
iron: '16%',
},
{
name: 'Jelly bean',
calories: 375,
fat: 0.0,
carbs: 94,
protein: 0.0,
iron: '0%',
},
{
name: 'Lollipop',
calories: 392,
fat: 0.2,
carbs: 98,
protein: 0,
iron: '2%',
},
{
name: 'Honeycomb',
calories: 408,
fat: 3.2,
carbs: 87,
protein: 6.5,
iron: '45%',
},
{
name: 'Donut',
calories: 452,
fat: 25.0,
carbs: 51,
protein: 4.9,
iron: '22%',
},
{
name: 'KitKat',
calories: 518,
fat: 26.0,
carbs: 65,
protein: 7,
iron: '6%',
},
],
headers: [
{
text: 'Dessert (100g serving)',
align: 'start',
sortable: false,
value: 'name',
},
{ text: 'Calories', value: 'calories' },
{ text: 'Fat (g)', value: 'fat' },
{ text: 'Carbs (g)', value: 'carbs' },
{ text: 'Protein (g)', value: 'protein' },
{ text: 'Iron (%)', value: 'iron' },
],
}),
}
</script>
页脚属性
v-data-table
使用 v-data-footer
组件渲染默认页脚。 您可以使用 footer-props
将属性传递到此组件。
template script
<template>
<v-data-table
:headers="headers"
:items="desserts"
:items-per-page="5"
item-key="name"
class="elevation-1"
:footer-props="{
showFirstLastPage: true,
firstIcon: 'mdi-arrow-collapse-left',
lastIcon: 'mdi-arrow-collapse-right',
prevIcon: 'mdi-minus',
nextIcon: 'mdi-plus'
}"
></v-data-table>
</template>
<script>
export default {
data () {
return {
headers: [
{
text: 'Dessert (100g serving)',
align: 'start',
value: 'name',
},
{ text: 'Category', value: 'category' },
],
desserts: [
{
name: 'Frozen Yogurt',
category: 'Ice cream',
},
{
name: 'Ice cream sandwich',
category: 'Ice cream',
},
{
name: 'Eclair',
category: 'Cookie',
},
{
name: 'Cupcake',
category: 'Pastry',
},
{
name: 'Gingerbread',
category: 'Cookie',
},
{
name: 'Jelly bean',
category: 'Candy',
},
{
name: 'Lollipop',
category: 'Candy',
},
{
name: 'Honeycomb',
category: 'Toffee',
},
{
name: 'Donut',
category: 'Pastry',
},
{
name: 'KitKat',
category: 'Candy',
},
],
}
},
}
</script>
过滤列
通过在标题项上将 filterable
的属性设置为 false,可以轻松地禁止在搜索表行时包括特定列。 在下面的示例中,甜点名称列不再可搜索。
template script
<template>
<v-card>
<v-card-title>
<v-text-field
v-model="search"
append-icon="search"
label="Search"
single-line
hide-details
></v-text-field>
</v-card-title>
<v-data-table
:headers="headers"
:items="desserts"
:search="search"
></v-data-table>
</v-card>
</template>
<script>
export default {
data () {
return {
search: '',
headers: [
{
text: 'Dessert (100g serving)',
align: 'start',
filterable: false,
value: 'name',
},
{ text: 'Calories', value: 'calories' },
{ text: 'Fat (g)', value: 'fat' },
{ text: 'Carbs (g)', value: 'carbs' },
{ text: 'Protein (g)', value: 'protein' },
{ text: 'Iron (%)', value: 'iron' },
],
desserts: [
{
name: 'Frozen Yogurt',
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
iron: '1%',
},
{
name: 'Ice cream sandwich',
calories: 237,
fat: 9.0,
carbs: 37,
protein: 4.3,
iron: '1%',
},
{
name: 'Eclair',
calories: 262,
fat: 16.0,
carbs: 23,
protein: 6.0,
iron: '7%',
},
{
name: 'Cupcake',
calories: 305,
fat: 3.7,
carbs: 67,
protein: 4.3,
iron: '8%',
},
{
name: 'Gingerbread',
calories: 356,
fat: 16.0,
carbs: 49,
protein: 3.9,
iron: '16%',
},
{
name: 'Jelly bean',
calories: 375,
fat: 0.0,
carbs: 94,
protein: 0.0,
iron: '0%',
},
{
name: 'Lollipop',
calories: 392,
fat: 0.2,
carbs: 98,
protein: 0,
iron: '2%',
},
{
name: 'Honeycomb',
calories: 408,
fat: 3.2,
carbs: 87,
protein: 6.5,
iron: '45%',
},
{
name: 'Donut',
calories: 452,
fat: 25.0,
carbs: 51,
protein: 4.9,
iron: '22%',
},
{
name: 'KitKat',
calories: 518,
fat: 26.0,
carbs: 65,
protein: 7,
iron: '6%',
},
],
}
},
}
</script>
插槽
v-data-table
提供了大量用于定制表的插槽。 此示例展示了其中一些插槽,以及每个插槽可以做什么。 重要的是要注意一些插槽(例如:item
/body
/header
)将完全代替组件的内部渲染,这将要求您重新实现选择和扩展之类的功能。 某些插槽会相互覆盖,例如:body
> item
> item.<name>
和 header
/header.<name>
。
template script
<template>
<div>
<v-select v-model="enabled" :items="slots" label="Slot" clearable></v-select>
<v-data-table
:headers="headers"
:items="items"
:search="search"
:hide-default-header="hideHeaders"
:show-select="showSelect"
:loading="isLoading"
hide-default-footer
item-key="name"
class="elevation-1"
>
<template v-if="isEnabled('top')" v-slot:top>
<div>This is content above the actual table</div>
</template>
<template v-if="isEnabled('header.data-table-select')" v-slot:header.data-table-select="{ on, props }">
<v-simple-checkbox color="purple" v-bind="props" v-on="on"></v-simple-checkbox>
</template>
<template v-if="isEnabled('header')" v-slot:header="{ props: { headers } }">
<thead>
<tr>
<th :colspan="headers.length">
This is a header
</th>
</tr>
</thead>
</template>
<template v-if="isEnabled('progress')" v-slot:progress>
<v-progress-linear color="purple" :height="10" indeterminate></v-progress-linear>
</template>
<template v-if="isEnabled('item.data-table-select')" v-slot:item.data-table-select="{ isSelected, select }">
<v-simple-checkbox color="green" :value="isSelected" @input="select($event)"></v-simple-checkbox>
</template>
<template v-if="isEnabled('item.<name>')" v-slot:item.name="{ item }">
{{ item.name.toUpperCase() }}
</template>
<template v-if="isEnabled('body.prepend')" v-slot:body.prepend="{ headers }">
<tr>
<td :colspan="headers.length">
This is a prepended row
</td>
</tr>
</template>
<template v-if="isEnabled('body')" v-slot:body="{ items }">
<tbody>
<tr v-for="item in items" :key="item.name">
<td>{{ item.name }}</td>
<td>CONTENT</td>
<td>CONTENT</td>
<td>CONTENT</td>
<td>CONTENT</td>
<td>CONTENT</td>
</tr>
</tbody>
</template>
<template v-if="isEnabled('no-data')" v-slot:no-data>
NO DATA HERE!
</template>
<template v-if="isEnabled('no-results')" v-slot:no-results>
NO RESULTS HERE!
</template>
<template v-if="isEnabled('body.append')" v-slot:body.append="{ headers }">
<tr>
<td :colspan="headers.length">
This is an appended row
</td>
</tr>
</template>
<template v-if="isEnabled('footer')" v-slot:footer>
<div>
This is a footer
</div>
</template>
</v-data-table>
</div>
</template>
<script>
const desserts = [
{
name: 'Frozen Yogurt',
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
iron: '1%',
},
{
name: 'Ice cream sandwich',
calories: 237,
fat: 9.0,
carbs: 37,
protein: 4.3,
iron: '1%',
},
{
name: 'Eclair',
calories: 262,
fat: 16.0,
carbs: 23,
protein: 6.0,
iron: '7%',
},
{
name: 'Cupcake',
calories: 305,
fat: 3.7,
carbs: 67,
protein: 4.3,
iron: '8%',
},
{
name: 'Gingerbread',
calories: 356,
fat: 16.0,
carbs: 49,
protein: 3.9,
iron: '16%',
},
{
name: 'Jelly bean',
calories: 375,
fat: 0.0,
carbs: 94,
protein: 0.0,
iron: '0%',
},
{
name: 'Lollipop',
calories: 392,
fat: 0.2,
carbs: 98,
protein: 0,
iron: '2%',
},
{
name: 'Honeycomb',
calories: 408,
fat: 3.2,
carbs: 87,
protein: 6.5,
iron: '45%',
},
{
name: 'Donut',
calories: 452,
fat: 25.0,
carbs: 51,
protein: 4.9,
iron: '22%',
},
{
name: 'KitKat',
calories: 518,
fat: 26.0,
carbs: 65,
protein: 7,
iron: '6%',
},
]
export default {
data () {
return {
enabled: null,
items: desserts,
search: null,
slots: [
'body',
'body.append',
'body.prepend',
'footer',
'header.data-table-select',
'header',
'progress',
'item.data-table-select',
'item.<name>',
'no-data',
'no-results',
'top',
],
headers: [
{
text: 'Dessert (100g serving)',
align: 'start',
sortable: false,
value: 'name',
},
{ text: 'Calories', value: 'calories' },
{ text: 'Fat (g)', value: 'fat' },
{ text: 'Carbs (g)', value: 'carbs' },
{ text: 'Protein (g)', value: 'protein' },
{ text: 'Iron (%)', value: 'iron' },
],
}
},
computed: {
showSelect () {
return this.isEnabled('header.data-table-select') || this.isEnabled('item.data-table-select')
},
hideHeaders () {
return !this.showSelect
},
isLoading () {
return this.isEnabled('progress')
},
},
watch: {
enabled (slot) {
if (slot === 'no-data') {
this.items = []
} else if (slot === 'no-results') {
this.search = '...'
} else {
this.search = null
this.items = desserts
}
},
},
methods: {
isEnabled (slot) {
return this.enabled === slot
},
},
}
</script>
Vue Jobs
Sign up and post a job or create your personalized developer profile at vuejobs.com.
ads by Vuetify
](https://vuejobs.com/?ref=vuetifyjs.com&ref=vuetify)
简单复选框
当想在你的数据表中的插槽模板中使用复选框组件时,请使用 v-simple-checkbox
组件,而不是 v-checkbox
组件。v-simple-checkbox
组件是内部使用的,并且会将表头对齐。
template script
<template>
<div>
<v-data-table
:headers="headers"
:items="desserts"
class="elevation-1"
>
<template v-slot:item.glutenfree="{ item }">
<v-simple-checkbox v-model="item.glutenfree" disabled></v-simple-checkbox>
</template>
</v-data-table>
</div>
</template>
<script>
export default {
data () {
return {
desserts: [
{
name: 'Frozen Yogurt',
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
iron: '1%',
glutenfree: true,
},
{
name: 'Ice cream sandwich',
calories: 237,
fat: 9.0,
carbs: 37,
protein: 4.3,
iron: '1%',
glutenfree: false,
},
{
name: 'Eclair',
calories: 262,
fat: 16.0,
carbs: 23,
protein: 6.0,
iron: '7%',
glutenfree: false,
},
{
name: 'Jelly bean',
calories: 375,
fat: 0.0,
carbs: 94,
protein: 0.0,
iron: '0%',
glutenfree: true,
},
{
name: 'Lollipop',
calories: 392,
fat: 0.2,
carbs: 98,
protein: 0,
iron: '2%',
glutenfree: true,
},
{
name: 'KitKat',
calories: 518,
fat: 26.0,
carbs: 65,
protein: 7,
iron: '6%',
glutenfree: false,
},
],
headers: [
{
text: 'Dessert (100g serving)',
align: 'start',
sortable: false,
value: 'name',
},
{ text: 'Calories', value: 'calories' },
{ text: 'Fat (g)', value: 'fat' },
{ text: 'Carbs (g)', value: 'carbs' },
{ text: 'Protein (g)', value: 'protein' },
{ text: 'Iron (%)', value: 'iron' },
{ text: 'Gluten-Free', value: 'glutenfree' },
],
}
},
}
</script>
可展开行
show-expand
属性将在每个默认行上呈现一个展开图标。 您可以使用 item.data-table-expand
插槽自定义。 可以通过在标题数组中添加一个带有 value: 'data-table-expand'
的列来定制该插槽的位置。 您也可以在一次允许多个扩展行之间切换,也可以使用 single-expand
属性只允许一个扩展行之间切换。 展开的行在同步属性 expanded.sync
上可用
template script
<template>
<v-data-table
:headers="headers"
:items="desserts"
:single-expand="singleExpand"
:expanded.sync="expanded"
item-key="name"
show-expand
class="elevation-1"
>
<template v-slot:top>
<v-toolbar flat>
<v-toolbar-title>Expandable Table</v-toolbar-title>
<v-spacer></v-spacer>
<v-switch v-model="singleExpand" label="Single expand" class="mt-2"></v-switch>
</v-toolbar>
</template>
<template v-slot:expanded-item="{ headers, item }">
<td :colspan="headers.length">More info about {{ item.name }}</td>
</template>
</v-data-table>
</template>
<script>
export default {
data () {
return {
expanded: [],
singleExpand: false,
headers: [
{
text: 'Dessert (100g serving)',
align: 'start',
sortable: false,
value: 'name',
},
{ text: 'Calories', value: 'calories' },
{ text: 'Fat (g)', value: 'fat' },
{ text: 'Carbs (g)', value: 'carbs' },
{ text: 'Protein (g)', value: 'protein' },
{ text: 'Iron (%)', value: 'iron' },
{ text: '', value: 'data-table-expand' },
],
desserts: [
{
name: 'Frozen Yogurt',
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
iron: '1%',
},
{
name: 'Ice cream sandwich',
calories: 237,
fat: 9.0,
carbs: 37,
protein: 4.3,
iron: '1%',
},
{
name: 'Eclair',
calories: 262,
fat: 16.0,
carbs: 23,
protein: 6.0,
iron: '7%',
},
{
name: 'Cupcake',
calories: 305,
fat: 3.7,
carbs: 67,
protein: 4.3,
iron: '8%',
},
{
name: 'Gingerbread',
calories: 356,
fat: 16.0,
carbs: 49,
protein: 3.9,
iron: '16%',
},
{
name: 'Jelly bean',
calories: 375,
fat: 0.0,
carbs: 94,
protein: 0.0,
iron: '0%',
},
{
name: 'Lollipop',
calories: 392,
fat: 0.2,
carbs: 98,
protein: 0,
iron: '2%',
},
{
name: 'Honeycomb',
calories: 408,
fat: 3.2,
carbs: 87,
protein: 6.5,
iron: '45%',
},
{
name: 'Donut',
calories: 452,
fat: 25.0,
carbs: 51,
protein: 4.9,
iron: '22%',
},
{
name: 'KitKat',
calories: 518,
fat: 26.0,
carbs: 65,
protein: 7,
iron: '6%',
},
],
}
},
}
</script>
自定义过滤
您可以通过为 custom-filter
属性提供函数来覆盖 search
属性所使用的默认过滤。 如果您需要自定义特定列的过滤,则可以在标头项目的 filter
属性中提供函数。 标识是 (value: any, search: string | null, item: any) => boolean
。 即使未提供 search
属性,该功能也将始终运行。 因此,如果不应用过滤器,则需要确保以值 true
提前退出。
template script
<template>
<div>
<v-data-table
:headers="headers"
:items="desserts"
item-key="name"
class="elevation-1"
:search="search"
:custom-filter="filterOnlyCapsText"
>
<template v-slot:top>
<v-text-field v-model="search" label="Search (UPPER CASE ONLY)" class="mx-4"></v-text-field>
</template>
<template v-slot:body.append>
<tr>
<td></td>
<td>
<v-text-field v-model="calories" type="number" label="Less than"></v-text-field>
</td>
<td colspan="4"></td>
</tr>
</template>
</v-data-table>
</div>
</template>
<script>
export default {
data () {
return {
search: '',
calories: '',
desserts: [
{
name: 'Frozen Yogurt',
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
iron: '1%',
},
{
name: 'Ice cream sandwich',
calories: 237,
fat: 9.0,
carbs: 37,
protein: 4.3,
iron: '1%',
},
{
name: 'Eclair',
calories: 262,
fat: 16.0,
carbs: 23,
protein: 6.0,
iron: '7%',
},
{
name: 'Cupcake',
calories: 305,
fat: 3.7,
carbs: 67,
protein: 4.3,
iron: '8%',
},
{
name: 'Gingerbread',
calories: 356,
fat: 16.0,
carbs: 49,
protein: 3.9,
iron: '16%',
},
{
name: 'Jelly bean',
calories: 375,
fat: 0.0,
carbs: 94,
protein: 0.0,
iron: '0%',
},
{
name: 'Lollipop',
calories: 392,
fat: 0.2,
carbs: 98,
protein: 0,
iron: '2%',
},
{
name: 'Honeycomb',
calories: 408,
fat: 3.2,
carbs: 87,
protein: 6.5,
iron: '45%',
},
{
name: 'Donut',
calories: 452,
fat: 25.0,
carbs: 51,
protein: 4.9,
iron: '22%',
},
{
name: 'KitKat',
calories: 518,
fat: 26.0,
carbs: 65,
protein: 7,
iron: '6%',
},
],
}
},
computed: {
headers () {
return [
{
text: 'Dessert (100g serving)',
align: 'start',
sortable: false,
value: 'name',
},
{
text: 'Calories',
value: 'calories',
filter: value => {
if (!this.calories) return true
return value < parseInt(this.calories)
},
},
{ text: 'Fat (g)', value: 'fat' },
{ text: 'Carbs (g)', value: 'carbs' },
{ text: 'Protein (g)', value: 'protein' },
{ text: 'Iron (%)', value: 'iron' },
]
},
},
methods: {
filterOnlyCapsText (value, search, item) {
return value != null &&
search != null &&
typeof value === 'string' &&
value.toString().toLocaleUpperCase().indexOf(search) !== -1
},
},
}
</script>
自定义默认头部
您可以使用 header.<name>
的动态插槽来仅自定义某些列。 <name>
是发送到 headers
的相应标题项中 value
属性的名称。
template script
<template>
<v-data-table
:headers="headers"
:items="desserts"
class="elevation-1"
>
<template v-slot:header.name="{ header }">
{{ header.text.toUpperCase() }}
</template>
</v-data-table>
</template>
<script>
export default {
data: () => ({
headers: [
{
text: 'Dessert (100g serving)',
align: 'start',
value: 'name',
},
{ text: 'Calories', value: 'calories' },
{ text: 'Fat (g)', value: 'fat' },
{ text: 'Carbs (g)', value: 'carbs' },
{ text: 'Protein (g)', value: 'protein' },
{ text: 'Iron (%)', value: 'iron' },
],
desserts: [
{
name: 'Frozen Yogurt',
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
iron: '1%',
},
{
name: 'Ice cream sandwich',
calories: 237,
fat: 9.0,
carbs: 37,
protein: 4.3,
iron: '1%',
},
{
name: 'Eclair',
calories: 262,
fat: 16.0,
carbs: 23,
protein: 6.0,
iron: '7%',
},
{
name: 'Cupcake',
calories: 305,
fat: 3.7,
carbs: 67,
protein: 4.3,
iron: '8%',
},
{
name: 'Gingerbread',
calories: 356,
fat: 16.0,
carbs: 49,
protein: 3.9,
iron: '16%',
},
{
name: 'Jelly bean',
calories: 375,
fat: 0.0,
carbs: 94,
protein: 0.0,
iron: '0%',
},
{
name: 'Lollipop',
calories: 392,
fat: 0.2,
carbs: 98,
protein: 0,
iron: '2%',
},
{
name: 'Honeycomb',
calories: 408,
fat: 3.2,
carbs: 87,
protein: 6.5,
iron: '45%',
},
{
name: 'Donut',
calories: 452,
fat: 25.0,
carbs: 51,
protein: 4.9,
iron: '22%',
},
{
name: 'KitKat',
calories: 518,
fat: 26.0,
carbs: 65,
protein: 7,
iron: '6%',
},
],
}),
}
</script>
自定义默认行
您可以使用动态插槽 item.<name>
仅自定义某些列。<name>
是发送到 headers
的相应标题项中 value
属性的名称。 因此,要自定义 calories 列,我们使用 item.calories
插槽。
template script
<template>
<v-data-table
:headers="headers"
:items="desserts"
class="elevation-1"
>
<template v-slot:item.calories="{ item }">
<v-chip :color="getColor(item.calories)" dark>{{ item.calories }}</v-chip>
</template>
</v-data-table>
</template>
<script>
export default {
data () {
return {
headers: [
{
text: 'Dessert (100g serving)',
align: 'start',
sortable: false,
value: 'name',
},
{ text: 'Calories', value: 'calories' },
{ text: 'Fat (g)', value: 'fat' },
{ text: 'Carbs (g)', value: 'carbs' },
{ text: 'Protein (g)', value: 'protein' },
{ text: 'Iron (%)', value: 'iron' },
],
desserts: [
{
name: 'Frozen Yogurt',
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
iron: '1%',
},
{
name: 'Ice cream sandwich',
calories: 237,
fat: 9.0,
carbs: 37,
protein: 4.3,
iron: '1%',
},
{
name: 'Eclair',
calories: 262,
fat: 16.0,
carbs: 23,
protein: 6.0,
iron: '7%',
},
{
name: 'Cupcake',
calories: 305,
fat: 3.7,
carbs: 67,
protein: 4.3,
iron: '8%',
},
{
name: 'Gingerbread',
calories: 356,
fat: 16.0,
carbs: 49,
protein: 3.9,
iron: '16%',
},
{
name: 'Jelly bean',
calories: 375,
fat: 0.0,
carbs: 94,
protein: 0.0,
iron: '0%',
},
{
name: 'Lollipop',
calories: 392,
fat: 0.2,
carbs: 98,
protein: 0,
iron: '2%',
},
{
name: 'Honeycomb',
calories: 408,
fat: 3.2,
carbs: 87,
protein: 6.5,
iron: '45%',
},
{
name: 'Donut',
calories: 452,
fat: 25.0,
carbs: 51,
protein: 4.9,
iron: '22%',
},
{
name: 'KitKat',
calories: 518,
fat: 26.0,
carbs: 65,
protein: 7,
iron: '6%',
},
],
}
},
methods: {
getColor (calories) {
if (calories > 400) return 'red'
else if (calories > 200) return 'orange'
else return 'green'
},
},
}
</script>
外部分页
分页可以通过 pagination
属性在外部控制,切记使用时必须应用 .sync
修饰符。
template script
<template>
<div>
<v-data-table
:headers="headers"
:items="desserts"
:page.sync="page"
:items-per-page="itemsPerPage"
hide-default-footer
class="elevation-1"
@page-count="pageCount = $event"
></v-data-table>
<div class="text-center pt-2">
<v-pagination v-model="page" :length="pageCount"></v-pagination>
<v-text-field
:value="itemsPerPage"
label="Items per page"
type="number"
min="-1"
max="15"
@input="itemsPerPage = parseInt($event, 10)"
></v-text-field>
</div>
</div>
</template>
<script>
export default {
data () {
return {
page: 1,
pageCount: 0,
itemsPerPage: 10,
headers: [
{
text: 'Dessert (100g serving)',
align: 'start',
sortable: false,
value: 'name',
},
{ text: 'Calories', value: 'calories' },
{ text: 'Fat (g)', value: 'fat' },
{ text: 'Carbs (g)', value: 'carbs' },
{ text: 'Protein (g)', value: 'protein' },
{ text: 'Iron (%)', value: 'iron' },
],
desserts: [
{
name: 'Frozen Yogurt',
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
iron: '1%',
},
{
name: 'Ice cream sandwich',
calories: 237,
fat: 9.0,
carbs: 37,
protein: 4.3,
iron: '1%',
},
{
name: 'Eclair',
calories: 262,
fat: 16.0,
carbs: 23,
protein: 6.0,
iron: '7%',
},
{
name: 'Cupcake',
calories: 305,
fat: 3.7,
carbs: 67,
protein: 4.3,
iron: '8%',
},
{
name: 'Gingerbread',
calories: 356,
fat: 16.0,
carbs: 49,
protein: 3.9,
iron: '16%',
},
{
name: 'Jelly bean',
calories: 375,
fat: 0.0,
carbs: 94,
protein: 0.0,
iron: '0%',
},
{
name: 'Lollipop',
calories: 392,
fat: 0.2,
carbs: 98,
protein: 0,
iron: '2%',
},
{
name: 'Honeycomb',
calories: 408,
fat: 3.2,
carbs: 87,
protein: 6.5,
iron: '45%',
},
{
name: 'Donut',
calories: 452,
fat: 25.0,
carbs: 51,
protein: 4.9,
iron: '22%',
},
{
name: 'KitKat',
calories: 518,
fat: 26.0,
carbs: 65,
protein: 7,
iron: '6%',
},
],
}
},
}
</script>
外部排序
排序也同样可以通过 pagination
属性在外部控制,也必须使用 .sync
修饰符。你也可以使用该属性设置默认的排序序列。
template script
<template>
<div>
<v-data-table
:headers="headers"
:items="desserts"
:sort-by.sync="sortBy"
:sort-desc.sync="sortDesc"
class="elevation-1"
></v-data-table>
<div class="text-center pt-2">
<v-btn color="primary" class="mr-2" @click="toggleOrder">Toggle sort order</v-btn>
<v-btn color="primary" @click="nextSort">Sort next column</v-btn>
</div>
</div>
</template>
<script>
export default {
data () {
return {
sortBy: 'fat',
sortDesc: false,
headers: [
{
text: 'Dessert (100g serving)',
align: 'start',
value: 'name',
},
{ text: 'Calories', value: 'calories' },
{ text: 'Fat (g)', value: 'fat' },
{ text: 'Carbs (g)', value: 'carbs' },
{ text: 'Protein (g)', value: 'protein' },
{ text: 'Iron (%)', value: 'iron' },
],
desserts: [
{
name: 'Frozen Yogurt',
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
iron: '1%',
},
{
name: 'Ice cream sandwich',
calories: 237,
fat: 9.0,
carbs: 37,
protein: 4.3,
iron: '1%',
},
{
name: 'Eclair',
calories: 262,
fat: 16.0,
carbs: 23,
protein: 6.0,
iron: '7%',
},
{
name: 'Cupcake',
calories: 305,
fat: 3.7,
carbs: 67,
protein: 4.3,
iron: '8%',
},
{
name: 'Gingerbread',
calories: 356,
fat: 16.0,
carbs: 49,
protein: 3.9,
iron: '16%',
},
{
name: 'Jelly bean',
calories: 375,
fat: 0.0,
carbs: 94,
protein: 0.0,
iron: '0%',
},
{
name: 'Lollipop',
calories: 392,
fat: 0.2,
carbs: 98,
protein: 0,
iron: '2%',
},
{
name: 'Honeycomb',
calories: 408,
fat: 3.2,
carbs: 87,
protein: 6.5,
iron: '45%',
},
{
name: 'Donut',
calories: 452,
fat: 25.0,
carbs: 51,
protein: 4.9,
iron: '22%',
},
{
name: 'KitKat',
calories: 518,
fat: 26.0,
carbs: 65,
protein: 7,
iron: '6%',
},
],
}
},
methods: {
toggleOrder () {
this.sortDesc = !this.sortDesc
},
nextSort () {
let index = this.headers.findIndex(h => h.value === this.sortBy)
index = (index + 1) % this.headers.length
this.sortBy = this.headers[index].value
},
},
}
</script>
服务端分页和排序
如果要加载已经从后端进行分页和排序的数据,则可以使用 server-items-length
属性。 定义此属性将禁用内置的排序和分页功能,而您需要使用可用的事件(update:page
, update:sortBy
, update:options
, 等)来知道何时请求新的后端的页面。 在获取数据时,使用 loading
属性显示进度条。
template script
<template>
<div>
<v-data-table
:headers="headers"
:items="desserts"
:options.sync="options"
:server-items-length="totalDesserts"
:loading="loading"
class="elevation-1"
></v-data-table>
</div>
</template>
<script>
export default {
data () {
return {
totalDesserts: 0,
desserts: [],
loading: true,
options: {},
headers: [
{
text: 'Dessert (100g serving)',
align: 'start',
sortable: false,
value: 'name',
},
{ text: 'Calories', value: 'calories' },
{ text: 'Fat (g)', value: 'fat' },
{ text: 'Carbs (g)', value: 'carbs' },
{ text: 'Protein (g)', value: 'protein' },
{ text: 'Iron (%)', value: 'iron' },
],
}
},
watch: {
options: {
handler () {
this.getDataFromApi()
.then(data => {
this.desserts = data.items
this.totalDesserts = data.total
})
},
deep: true,
},
},
mounted () {
this.getDataFromApi()
.then(data => {
this.desserts = data.items
this.totalDesserts = data.total
})
},
methods: {
getDataFromApi () {
this.loading = true
return new Promise((resolve, reject) => {
const { sortBy, sortDesc, page, itemsPerPage } = this.options
let items = this.getDesserts()
const total = items.length
if (sortBy.length === 1 && sortDesc.length === 1) {
items = items.sort((a, b) => {
const sortA = a[sortBy[0]]
const sortB = b[sortBy[0]]
if (sortDesc[0]) {
if (sortA < sortB) return 1
if (sortA > sortB) return -1
return 0
} else {
if (sortA < sortB) return -1
if (sortA > sortB) return 1
return 0
}
})
}
if (itemsPerPage > 0) {
items = items.slice((page - 1) * itemsPerPage, page * itemsPerPage)
}
setTimeout(() => {
this.loading = false
resolve({
items,
total,
})
}, 1000)
})
},
getDesserts () {
return [
{
name: 'Frozen Yogurt',
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
iron: '1%',
},
{
name: 'Ice cream sandwich',
calories: 237,
fat: 9.0,
carbs: 37,
protein: 4.3,
iron: '1%',
},
{
name: 'Eclair',
calories: 262,
fat: 16.0,
carbs: 23,
protein: 6.0,
iron: '7%',
},
{
name: 'Cupcake',
calories: 305,
fat: 3.7,
carbs: 67,
protein: 4.3,
iron: '8%',
},
{
name: 'Gingerbread',
calories: 356,
fat: 16.0,
carbs: 49,
protein: 3.9,
iron: '16%',
},
{
name: 'Jelly bean',
calories: 375,
fat: 0.0,
carbs: 94,
protein: 0.0,
iron: '0%',
},
{
name: 'Lollipop',
calories: 392,
fat: 0.2,
carbs: 98,
protein: 0,
iron: '2%',
},
{
name: 'Honeycomb',
calories: 408,
fat: 3.2,
carbs: 87,
protein: 6.5,
iron: '45%',
},
{
name: 'Donut',
calories: 452,
fat: 25.0,
carbs: 51,
protein: 4.9,
iron: '22%',
},
{
name: 'KitKat',
calories: 518,
fat: 26.0,
carbs: 65,
protein: 7,
iron: '6%',
},
]
},
},
}
</script>
内容编辑
v-edit-dialog
组件可用于直接在 v-data-table
中编辑数据。 您可以通过添加 persistent 属性来阻止在外部点击 v-edit-dialog
时关闭。
template script
<template>
<div>
<v-data-table
:headers="headers"
:items="desserts"
>
<template v-slot:item.name="props">
<v-edit-dialog
:return-value.sync="props.item.name"
@save="save"
@cancel="cancel"
@open="open"
@close="close"
> {{ props.item.name }}
<template v-slot:input>
<v-text-field
v-model="props.item.name"
:rules="[max25chars]"
label="Edit"
single-line
counter
></v-text-field>
</template>
</v-edit-dialog>
</template>
<template v-slot:item.iron="props">
<v-edit-dialog
:return-value.sync="props.item.iron"
large
persistent
@save="save"
@cancel="cancel"
@open="open"
@close="close"
>
<div>{{ props.item.iron }}</div>
<template v-slot:input>
<div class="mt-4 title">Update Iron</div>
</template>
<template v-slot:input>
<v-text-field
v-model="props.item.iron"
:rules="[max25chars]"
label="Edit"
single-line
counter
autofocus
></v-text-field>
</template>
</v-edit-dialog>
</template>
</v-data-table>
<v-snackbar v-model="snack" :timeout="3000" :color="snackColor">
{{ snackText }}
<v-btn text @click="snack = false">Close</v-btn>
</v-snackbar>
</div>
</template>
<script>
export default {
data () {
return {
snack: false,
snackColor: '',
snackText: '',
max25chars: v => v.length <= 25 || 'Input too long!',
pagination: {},
headers: [
{
text: 'Dessert (100g serving)',
align: 'start',
sortable: false,
value: 'name',
},
{ text: 'Calories', value: 'calories' },
{ text: 'Fat (g)', value: 'fat' },
{ text: 'Carbs (g)', value: 'carbs' },
{ text: 'Protein (g)', value: 'protein' },
{ text: 'Iron (%)', value: 'iron' },
],
desserts: [
{
name: 'Frozen Yogurt',
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
iron: '1%',
},
{
name: 'Ice cream sandwich',
calories: 237,
fat: 9.0,
carbs: 37,
protein: 4.3,
iron: '1%',
},
{
name: 'Eclair',
calories: 262,
fat: 16.0,
carbs: 23,
protein: 6.0,
iron: '7%',
},
{
name: 'Cupcake',
calories: 305,
fat: 3.7,
carbs: 67,
protein: 4.3,
iron: '8%',
},
{
name: 'Gingerbread',
calories: 356,
fat: 16.0,
carbs: 49,
protein: 3.9,
iron: '16%',
},
{
name: 'Jelly bean',
calories: 375,
fat: 0.0,
carbs: 94,
protein: 0.0,
iron: '0%',
},
{
name: 'Lollipop',
calories: 392,
fat: 0.2,
carbs: 98,
protein: 0,
iron: '2%',
},
{
name: 'Honeycomb',
calories: 408,
fat: 3.2,
carbs: 87,
protein: 6.5,
iron: '45%',
},
{
name: 'Donut',
calories: 452,
fat: 25.0,
carbs: 51,
protein: 4.9,
iron: '22%',
},
{
name: 'KitKat',
calories: 518,
fat: 26.0,
carbs: 65,
protein: 7,
iron: '6%',
},
],
}
},
methods: {
save () {
this.snack = true
this.snackColor = 'success'
this.snackText = 'Data saved'
},
cancel () {
this.snack = true
this.snackColor = 'error'
this.snackText = 'Canceled'
},
open () {
this.snack = true
this.snackColor = 'info'
this.snackText = 'Dialog opened'
},
close () {
console.log('Dialog closed')
},
},
}
</script>
CRUD 操作
数据表格使用 v-dialog
组件来进行每行的 CRUD 操作。
template script
<template>
<v-data-table
:headers="headers"
:items="desserts"
sort-by="calories"
class="elevation-1"
>
<template v-slot:top>
<v-toolbar flat color="white">
<v-toolbar-title>My CRUD</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 }">
<v-btn color="primary" dark class="mb-2" v-on="on">New Item</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="4">
<v-text-field v-model="editedItem.name" label="Dessert name"></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-text-field v-model="editedItem.calories" label="Calories"></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-text-field v-model="editedItem.fat" label="Fat (g)"></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-text-field v-model="editedItem.carbs" label="Carbs (g)"></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-text-field v-model="editedItem.protein" label="Protein (g)"></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-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>
<v-btn color="primary" @click="initialize">Reset</v-btn>
</template>
</v-data-table>
</template>
<script>
export default {
data: () => ({
dialog: false,
headers: [
{
text: 'Dessert (100g serving)',
align: 'start',
sortable: false,
value: 'name',
},
{ text: 'Calories', value: 'calories' },
{ text: 'Fat (g)', value: 'fat' },
{ text: 'Carbs (g)', value: 'carbs' },
{ text: 'Protein (g)', value: 'protein' },
{ text: 'Actions', value: 'actions', sortable: false },
],
desserts: [],
editedIndex: -1,
editedItem: {
name: '',
calories: 0,
fat: 0,
carbs: 0,
protein: 0,
},
defaultItem: {
name: '',
calories: 0,
fat: 0,
carbs: 0,
protein: 0,
},
}),
computed: {
formTitle () {
return this.editedIndex === -1 ? 'New Item' : 'Edit Item'
},
},
watch: {
dialog (val) {
val || this.close()
},
},
created () {
this.initialize()
},
methods: {
initialize () {
this.desserts = [
{
name: 'Frozen Yogurt',
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
},
{
name: 'Ice cream sandwich',
calories: 237,
fat: 9.0,
carbs: 37,
protein: 4.3,
},
{
name: 'Eclair',
calories: 262,
fat: 16.0,
carbs: 23,
protein: 6.0,
},
{
name: 'Cupcake',
calories: 305,
fat: 3.7,
carbs: 67,
protein: 4.3,
},
{
name: 'Gingerbread',
calories: 356,
fat: 16.0,
carbs: 49,
protein: 3.9,
},
{
name: 'Jelly bean',
calories: 375,
fat: 0.0,
carbs: 94,
protein: 0.0,
},
{
name: 'Lollipop',
calories: 392,
fat: 0.2,
carbs: 98,
protein: 0,
},
{
name: 'Honeycomb',
calories: 408,
fat: 3.2,
carbs: 87,
protein: 6.5,
},
{
name: 'Donut',
calories: 452,
fat: 25.0,
carbs: 51,
protein: 4.9,
},
{
name: 'KitKat',
calories: 518,
fat: 26.0,
carbs: 65,
protein: 7,
},
]
},
editItem (item) {
this.editedIndex = this.desserts.indexOf(item)
this.editedItem = Object.assign({}, item)
this.dialog = true
},
deleteItem (item) {
const index = this.desserts.indexOf(item)
confirm('Are you sure you want to delete this item?') && this.desserts.splice(index, 1)
},
close () {
this.dialog = false
this.$nextTick(() => {
this.editedItem = Object.assign({}, this.defaultItem)
this.editedIndex = -1
})
},
save () {
if (this.editedIndex > -1) {
Object.assign(this.desserts[this.editedIndex], this.editedItem)
} else {
this.desserts.push(this.editedItem)
}
this.close()
},
},
}
</script>