我正在使用VueJs 3创建一个动态表组件,这涉及到向插槽内的所有子组件发送向下循环索引变量
组件的使用情况如下
<template>
<h1>my table</h1>
<MyTable
:source="[
{ fname: 'Jhon', lname: 'Smith' },
{ fname: 'Arthur', lname: 'Cromer' },
]"
>
<MyTableColumn cellTitle="First Name" cellValue="fname"></MyTableColumn>
<MyTableColumn cellTitle="Last Name" cellValue="lname"></MyTableColumn>
</MyTable>
</template>
上面展示了我试图实现的目标,您可以在其中设置表数据源(数组)和任意数量的列,其中每个列接受一个标题和单元格值。
我不知道如何将迭代索引(v-for索引)向下发送到槽内的所有组件。
这里是MyTable.vue模板
<template>
<table>
<tr v-for="(row, index) in $props.source" :key="index">
{{
(currentRow = index)
}}
<slot></slot>
</tr>
</table>
</template>
我试过范围槽,但没有帮助。并尝试了提供/注入技术,方法是从MyTable.vue提供索引,并在每个MyTableColumn.vue实例中注入索引,但这并没有像预期的那样工作,因为注入的变量总是有最后一个索引。不确定它是否需要使用呈现函数。
在过去的几天里,我一直试图在没有运气的情况下找到解决方案。
发布于 2022-07-15 14:09:26
使用作用域槽和相关样板代码的替代方法是在呈现函数中向子节点添加支持,这是通过修改code对象来完成的,类似于这个答案。
MyTable
可以有一组有限的组件,这些组件可以作为其子组件使用,并且可以得到特殊的处理,例如MyTableColumn
。
() => {
const tableChildren = slots.default?.() || [];
const tableColumns = tableChildren.filter(vnode => vnode.type === MyTableColumn);
const tableHeaders = tableColumns.map(vnode => vnode.props.cellTitle);
return h('table', {}, [
h('tr', {}, [
...tableHeaders.map(header => h('td', {}, header)),
]),
...props.source.map((row, index) => {
return h('tr', {}, [
...tableColumns.map(vnode => {
const name = vnode.props.cellValue
return {
...vnode,
props: {
...vnode.props,
index,
value: row[name]
}
};
})
])
})
...
这里,在呈现之前,额外的index
和value
支持被添加到MyTableColumn
vnodes中。
这可以通过完全不呈现MyTableColumn
来改变,只需向MyTable
提供关于列的必要信息,并为它们提供可选的自定义布局。这种方法在React生态系统中比较流行,但在Primevue DataTable中也可以看到。可以看出,Column
组件没有模板,因此没有呈现。
发布于 2022-07-12 12:00:24
渲染行
您可以使用作用域槽将数据从MyTable.vue
传递给它的插槽子节点:
MyTable.vue
中,将index
和row
的值绑定到<slot>
<tr v-for="(row, index) in $props.source" :key="index">
<slot :index="index" :row="row"></slot>
</tr>
App.vue
中,通过<template>
上的v-slot
访问MyTable.vue
的插槽道具,并将它们绑定到MyTableColumn
的道具上:<MyTable
:source="[
{ fname: 'Jhon', lname: 'Smith' },
{ fname: 'Arthur', lname: 'Cromer' },
]"
>
<template v-slot="{ index, row }">
<MyTableColumn cellTitle="First Name" :index="index" :cellValue="row.fname"></MyTableColumn>
<MyTableColumn cellTitle="Last Name" :index="index" :cellValue="row.lname"></MyTableColumn>
</template>
</MyTable>
呈现标头
MyTable.vue
中,添加一个headers
支柱以包含列标题数组,并将它们呈现在表主体之上:defineProps({
headers: Array,
})
<table>
<tr>
<td v-for="header in headers">{{ header }}</td>
</tr>
<!-- table body... -->
</table>
App.vue
中,将所需的列标题绑定到<MyTable>.headers
<MyTable :headers="['First Name', 'Last Name']" ⋯>
发布于 2022-07-12 13:24:47
让我们从一个简单的插槽示例开始:
<template>
content which always renders
<slot name="slotName" :foo="'bar'">
content to be rendered if slot is not present
</slot>
some more content which always renders
</template>
考虑到上面的时隙组件,以下标记:
<Slotted>
<template #slotName="{foo}">
replacement content for slot - {{ foo }}
</template>
</Slotted>
会产生
content which always renders
replacement content for slot - bar
some more content which always renders
,而<Slotted />
将产生:
content which always renders
content to be rendered if slot is not present
some more content which always renders
将上述内容实现到一个表中,我们将呈现的列定义为字段,并为每个字段的单元格定义一个槽,为每个字段的标头定义一个槽。它们是动态的。
若要替换任何列单元格或列标题,请为该列的单元格提供模板。在默认内容中,为所有单元格(#cell
)嵌套一个通用槽,为所有标头(#header
)嵌套一个。如果提供,将用于没有指定模板的任何单元格(或标头)。如果未提供,则默认内容。
代码:
Table.vue
<template>
<table>
<thead>
<tr>
<th v-for="{label, key} in fields" :key="key">
<slot :name="`header(${key})`"
v-bind="{ label, propName: key }">
<slot name="header">
{{ label }}
</slot>
</slot>
</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in rows" :key="index">
<td v-for="field in fields" :key="field.key">
<slot :name="`cell(${field.key})`"
v-bind="{
item,
index,
value: item[field.key],
field
}">
<slot name="cell"
v-bind="{
item,
index,
value: item[field.key],
field
}">
{{ item[field.key] }}
</slot>
</slot>
</td>
</tr>
</tbody>
</table>
</template>
将其用作:
<Table :rows="rows" :fields="fields">
<template #cell(fname)="{ value, index }">
<span style="color: red" v-text="`${index} - ${value}" />
</template>
<template #header(fname)="{ label }">
<span style="color: blue" v-text="label" />
</template>
<template #header="{ label }">
<!-- applies to all header cells which don't have
a #header({key}) template provided.
The ones which do (eg: `#header(fname)`) override this. -->
<span :style="{fontStyle: 'italic'}" v-text="label" />
</template>
</Table>
工作实例。
这种方法的优点在于,现在您可以使用这个<Table />
来呈现任何项,而不必更改<Table />
组件。您只需提供应该呈现默认内容以外的内容的插槽。
注意:每个插槽内的,您可以访问绑定到插槽范围的任何内容。在本例中,{ item, index, value, field }
表示单元格,{ label, key }
表示标头单元格。很明显,你不局限于这些。你可以把你想要的东西绑在他们身上。
https://stackoverflow.com/questions/72956962
复制相似问题