Постройте динамическое число слотов Vue в функции рендеринга
Я пытаюсь создать пользовательский компонент из функции рендеринга.
Этот визуализируемый компонент принимает любое количество слотов. В приведенном ниже примере доступны три слота (element_1
, element_2
, element_3
).
Ниже Array.reduce()
должен быть эквивалентен:
scopedSlots: {
"element_1": () => createElement('div', 'hello world'),
"element_2": () => createElement('div', 'hello world'),
"element_3": () => createElement('div', 'hello world'),
}
Это уменьшенный пример с Array.reduce()
:
const records = [
{
"index": 1,
},
{
"index": 2,
},
{
"index": 3,
}
]
render: function (createElement) {
return createElement("replicator-component", {
attrs: { elements: records.length},
scopedSlots: records.reduce((a,x) => ({...a,
['element_' + x.index]:
() => { createElement( 'div', 'hello world') }}), {})
});
},
Однако ничего не рендерится,и нет никаких ошибок, чтобы направлять меня. Есть идеи?
Ответы - Постройте динамическое число слотов Vue в функции рендеринга / Build a dynamic number of Vue slots within a Render function

02.12.2020 07:18:48
Этот метод reduce не работает, потому что в нем отсутствует возврат до createElement('div', 'hello world')
:
Полный пример
const ReplicatorComponent = {
template: `
<div>
<h1>replicator-component</h1>
<slot name='element_1'></slot>
<slot name='element_2'></slot>
<slot name='element_3'></slot>
</div>
`
}
const records = [{
"index": 1,
},
{
"index": 2,
},
{
"index": 3,
}
]
Vue.component('my-component', {
render: function(createElement) {
let slotContent = records.reduce((a, x) => ({ ...a,
['element_' + x.index]:
() => {
return createElement('div', 'hello world')
}
}), {})
return createElement(ReplicatorComponent, {
attrs: {
elements: records.length
},
scopedSlots: slotContent
});
},
})
var app = new Vue({
el: '#app',
data: () => ({})
})
<script src="https://cdn.jsdelivr.net/npm/vue@2.x/dist/vue.js"></script>
<div id="app">
test
<my-component></my-component>
</div>

02.12.2020 08:02:33
я думаю, что ограниченные слоты должны быть функциями, которые принимают props
в качестве своего параметра
в соответствии с Vue.js документы
export default {
render(createElement) {
// ...
// some other stuff
// ...
// Scoped slots in the form of
// { name: props => VNode | Array<VNode> }
scopedSlots: {
default: props => createElement('span', props.text)
},
}
}
так что, может быть, вам стоит попробовать
кроме того, вы можете сделать то же самое, используя новую унифицированную систему Vue v-slot
<!-- page component -->
<template>
<some-component>
<template v-for="slot in scopedSlots" v-slot:[slot]="props">
hello {{props}}
</template>
</some-component>
</template>
<!-- some-component.vue -->
<template>
<div>
<slot v-for="slot in Object.keys($slots)" :name="slot"></slot>
</div>
</template>

02.12.2020 08:44:27
Разница в том, что в вашем reduce
вы создаете функции как
() => { createElement( 'div', 'hello world') }
в то время как в вашей жестко закодированной версии (а также в цикле forEach
в anwer @Boussadjra) они создаются как
() => createElement('div', 'hello world')
который на самом деле return
созданный элемент. Это не имеет ничего общего с использованием reduce
, что прекрасно.
const ReplicatorComponent = {
template: `<div>
<h1>replicator-component</h1>
<slot name='element_1'></slot>
<slot name='element_2'></slot>
<slot name='element_3'></slot>
</div>`
};
const records = [
{ "index": 1 },
{ "index": 2 },
{ "index": 3 },
];
Vue.component('my-component', {
render: function(createElement) {
return createElement(ReplicatorComponent, {
attrs: {
elements: records.length
},
scopedSlots: records.reduce((a,x) => ({
...a,
['element_' + x.index]: () =>
createElement( 'div', 'hello world')
}), {})
});
},
});
new Vue({
el: '#app',
data: () => ({})
});
<script src="https://cdn.jsdelivr.net/npm/vue@2.x/dist/vue.js"></script>
<div id="app">
<my-component></my-component>
</div>