我创建了BaseDataTable
组件:
<template>
<v-data-table
:class="{ clickable }"
:headers="reshapedHeaders"
:items="items"
:loading="loading"
:sort-by="sortBy"
sort-desc
:item-key="itemKey"
:expanded.sync="expanded"
:show-expand="showExpand"
:hide-default-footer="disablePagination"
:disable-pagination="disablePagination"
@click:row="handleClickRow"
@dblclick:row.stop="handleDblclickRow"
>
<!-- Translating headers
(translationPath is one of my header custom props) -->
<template
v-for="{ text, value, translationPath } in reshapedHeaders"
#[getHeaderSlotName(value)]
>
<!-- This component uses vue-i18n features under the cover -->
<ValueTranslator
:key="value"
:translation-path="translationPath
? translationPath
: commonTranslationPath"
:value="text"
/>
</template>
<!-- Overriding item slots -->
<template
v-for="{ value } in reshapedHeaders"
#[getItemSlotName(value)]="slotData"
>
<slot
:name="getItemSlotName(value)"
v-bind="slotData"
>
{{ slotData.value }}
</slot>
</template>
</v-data-table>
</template>
<script>
import ValueTranslator from '../ValueTranslator.vue
export default {
props: {
headers: Array,
items: Array,
loading: Boolean,
clickable: Boolean,
itemKey: {
type: String,
default: '_id'
}
showExpand: Boolean,
/* Defines pagination and footer visibility;
true = disable pagination and hide footer
false = paginate and show footer */
disablePagination: Boolean,
/* Value added before each translation */
commonTranslationPath: String,
/* Defines actions column visibility;
true = show actions column
false = hide actions column */
showActions: Boolean,
/* Defines table initial sorting;
true = sort (default sorting)
false = don't sort
string = sort by passed value */
sort: [Boolean, String]
},
components: {
ValueTranslator
},
data() {
return {
expanded: []
}
},
computed: {
reshapedHeaders() {
const reshapedHeaders = [...this.headers]
if (this.showActions) {
/* Pushing actions header */
this.reshapedHeaders.push({
text: 'actions',
value: 'actions',
translationPath: 'component.table'
sortable: false
})
}
return reshapedHeaders
},
sortBy() {
if (this.sort) {
return typeof this.sort === 'string'
? this.sort
: 'lastModifiedDate'
} else
return null
}
},
methods: {
handleClickRow(item, data) {
this.$emit('click:row', item, data)
},
handleDblclickRow(_, { item }) {
this.$emit('dblclick:row', item)
},
getHeaderSlotName(value) {
return 'header.' + value
},
getItemSlotName(value) {
return 'item.' + value
}
}
}
</script>
正如你所看到的,我这样做是因为我需要将一堆特性组合在一起。由于我无法在这里解释的原因,我基于前面创建的BaseDataTable
创建了一个DataTable
组件:
<template>
<v-container fluid>
<BaseDataTable
class="elevation-1"
:headers="headers"
:items="items"
:loading="loading"
:clickable="clickable"
:item-key="itemKey"
:show-expand="showExpand"
:disable-pagination="disablePagination"
:common-translation-path="commonTranslationPath"
show-actions
:sort="sort"
@click:row="handleClickRow"
@dblclick:row="handleDblclickRow"
>
<!-- code snippet I'll show you later -->
</BaseDataTable>
</v-container>
</template>
<script>
import BaseDataTable from '../../base/BaseDataTable.vue
props: {
headers: Array,
items: Array,
loading: Boolean,
clickable: Boolean,
itemKey: String,
showExpand: Boolean,
disablePagination: Boolean,
commonTranslationPath: String,
sort: [Boolean, String]
},
components: {
BaseDataTable
},
methods: {
handleClickRow(item) {
this.$emit('click:row', item)
},
handleDblclickRow(item) {
this.$emit('dblclick:row', item)
}
}
</script>
如果我停在这里,我将无法使用任何物品槽,但如果我继续,我将结束重复自己…
上面提到的代码片段:<!-- Overriding item slots -->
<template
v-for="{ value } in headers"
#[getItemSlotName(value)]="slotData"
>
<slot
:name="getItemSlotName(value)"
v-bind="slotData"
></slot>
</template>
加上我没有考虑到有行动列。上面的v-for
循环通过headers
,而不是reshapedHeaders
(位于BaseDataTable
内部)。有没有一种干净的方法来实现我想要实现的东西?
在v-data-table
中添加slot
可能会解决您的问题。
<v-data-table
:class="{ clickable }"
:headers="reshapedHeaders"
:items="items"
:loading="loading"
:sort-by="sortBy"
sort-desc
:item-key="itemKey"
:expanded.sync="expanded"
:show-expand="showExpand"
:hide-default-footer="disablePagination"
:disable-pagination="disablePagination"
@click:row="handleClickRow"
@dblclick:row.stop="handleDblclickRow"
>
<!-- Pass on all named slots -->
<slot
v-for="slot in Object.keys($slots)"
:name="slot"
:slot="slot"
/>
<!-- Pass on all scoped slots -->
<template
v-for="slot in Object.keys($scopedSlots)"
:slot="slot"
slot-scope="scope"
>
<slot :name="slot" v-bind="scope" />
</template>
</v-data-table>