Постройте динамическое число слотов Vue в функции рендеринга


Постройте динамическое число слотов Vue в функции рендеринга

02.12.2020 07:00:59 Просмотров 72 Источник

Я пытаюсь создать пользовательский компонент из функции рендеринга.

Этот визуализируемый компонент принимает любое количество слотов. В приведенном ниже примере доступны три слота (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

Boussadjra Brahim

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>

user14728407

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>

Является ответом!
Bergi

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>

Помочь в развитии проекта:
Закрыть X