Как создать компонент для таблицы с двумя колонками в UI?
Требуется реализовать таблицу, в которую передается массив данных и две колонки. Колонки должны использовать слоты (для заголовка и тела), чтобы правильно отображать информацию в заголовке и теле таблицы.
Вот пример кода для реализации таблицы:
<pre><code class="javascript"><TableCustom :data="data">
<TableCol prop="age" label="Возраст" width="150">
<template #header>
<div>Это заголовок для возраста</div>
</template>
<template #body="scope">
<div>Возраст: {{ scope.row.name }}</div>
</template>
</TableCol>
<TableCol prop="name" label="Имя" width="200">
<template #header>
</template>
<template #body="scope">
<div>имя {{ scope.row.name }}</div>
</template>
</TableCol>
</TableCustom></code></pre>
Вопрос состоит в следующем: допустим, существует реализация компонента. Как правильно достать слоты из объекта children и отобразить их в нужных местах шаблона, чтобы данные корректно рендерились?
Чтобы правильно отобразить дочерние слоты в родительском компоненте, который, в вашем случае, будет таблицей с двумя колонками, вы можете воспользоваться функциональностью Vue.js для работы с слотами. Давайте рассмотрим, как можно реализовать компоненты `TableCustom` и `TableCol`, чтобы корректно отображать заголовки и тела в вашей таблице.
Вот пример реализации компонента `TableCustom` и `TableCol`, который использует слоты:
```vue
<!-- TableCustom.vue -->
<template>
<table>
<thead>
<tr>
<th v-for="(col, index) in columns" :key="index" :style="{ width: col.width }">
<slot :name="`header-${col.prop}`" />
</th>
</tr>
</thead>
<tbody>
<tr v-for="(row, rowIndex) in data" :key="rowIndex">
<td v-for="(col, colIndex) in columns" :key="colIndex">
<slot :name="`body-${col.prop}`" :scope="{ row }" />
</td>
</tr>
</tbody>
</table>
</template>
<script>
export default {
props: {
data: {
type: Array,
required: true
}
},
computed: {
columns() {
return this.$slots.default().map(slot => {
return { prop: slot.props.prop, width: slot.props.width };
});
}
}
}
</script>
```
```vue
<!-- TableCol.vue -->
<template>
<div style="display: none;">
<slot></slot>
</div>
</template>
<script>
export default {
props: {
prop: {
type: String,
required: true
},
label: {
type: String,
required: true
},
width: {
type: String,
required: false
}
}
}
</script>
```
Здесь `TableCustom` является родительским компонентом, который получает массив данных через пропс `data`. Он использует слоты, чтобы отобразить пользовательски определенные заголовки и тела ячеек. Мы определяем `header` и `body` слоты с помощью шаблонов с именами на основе `prop` из `TableCol`.
Теперь вы можете использовать компоненты `TableCustom` и `TableCol` следующим образом:
```vue
<template>
<TableCustom :data="data">
<TableCol prop="age" label="Возраст" width="150">
<template #header>
<div>Это заголовок для возраста</div>
</template>
<template #body="{ row }">
<div>Возраст: {{ row.age }}</div>
</template>
</TableCol>
<TableCol prop="name" label="Имя" width="200">
<template #header>
<div>Это заголовок для имени</div>
</template>
<template #body="{ row }">
<div>Имя: {{ row.name }}</div>
</template>
</TableCol>
</TableCustom>
</template>
<script>
export default {
data() {
return {
data: [
{ age: 25, name: 'John' },
{ age: 30, name: 'Jane' },
// больше данных...
]
};
}
}
</script>
```
Теперь, когда вы используете компонент `TableCustom`, он будет корректно отображать заголовки и тела в таблице, используя заданные слоты для каждого столбца. Каждый столбец будет захватывать свои слоты заголовков и тел, передавая нужные данные в соответствующие шаблоны.
<a href="https://play.vuejs.org/#eNq1VcFO20AQ/ZWROSRIwYEEVNUNoBZxaA8tKtwwB8feJAubXcu7DlRRpJYfQOqpP1EJtZWoSsU3OH/U2TXe2IEm9NBDFO/Om5k3zzPjsfMyjt1RShzP6cgwobECSVQa7/icDmORKBhDQnowgV4ihlBDaO2FtR0FXUb2UqnQlNvdZulOB36AFmwOKliB83kouFQQBSqAbZ23fuxzQAo08mCjATwYEg9qQRDUGhD08XmzDZPGDNOymG63W2BaWxVM22LCMCww8LyC2bSYKIoKzLOWwZysItVOM1cLdcKDIsOYBYrgCaBTVsXTtWz7jv7zHWO3CFQiTkSMVhr5DrCgSxgeVhDXsdqYBI86IaeSV/Y5u8tuph+z6+mn6SUazmmkBmjY2Fq3iTFKQRVWBiSISGItaIvoaCf7Or3M7iC7ya6z7xjyFn/f8PcLsh/Z7fQKzMkmyq47Te1m4zcrWsyl7IroA1KSoYiR+4PUlRI8GI/BIN1EnLtYLUwmS5I9RTb9Xsu6fcl+T69KerXW/6LXEvI/dZwqZ53qH0nPjqZ/8KaEdxqOwui8R/vuqRQch3asXXwnFMOYMpK8ixXFEfIdVC+Pjn3CmDh/Y+5UkhLT5cZnQMKzR+5P5YW+852DhEiSjLBYa1NB0icqN+8fviUX+GyNQxGlDNELjO+JFCzVHHPYq5RHSLuEM2xfm4VBef9I7l8owmVRlCaqkfms+g4ujr0Fpc/ott228fP5BFWc21GLll8qySETSs5vwGJX6a6SuKwi0qOcHOhT/RjXBs57DcyqyHEh1j3kGllErK+66BSkTO269WU7RWnGRcMoPbqlFq0MsRrAaK0nEmzVcc7Og7gB4YCyKCHcgxBLobwghJ3vnRHd2LGr0ZXOxnC6swQnXGFU2kNYuOvmm0N7UqlvZhfNqrMdntEaYZLs4HTErpk8MxYPVoWZjkF5VIrS9P2s6I7Sw1hWwNaMc6erq+zbHBP9d100qZIqxREp5cSeJBDijvOUJwtEKr3+ikhWF3y+b5lKCNv8+Vf3kc6fa2RNBD+ANfPW7ju61KjO5A+lrL9Q" rel="nofollow">Вот так</a> : <br/> <br/> <pre><code class="javascript">import { useSlots } from 'vue';
const columns = useSlots().default?.();</code></pre> <br/> <pre><code class="html"><table>
<thead>
<tr>
<th v-for="{ props: p, children: c } in columns" :key="p.prop">
<component v-if="c?.header" :is="c.header" />
<template v-else>{{ p.label }}</template>
</th>
</tr>
</thead>
<tbody>
<tr v-for="row in data">
<td v-for="{ props: p, children: c } in columns" :key="p.prop">
<component v-if="c?.body" :is="c.body" :row="row" />
<template v-else>{{ row[p.prop] }}</template>
</td>
</tr>
</tbody>
</table></code></pre>