admin管理员组

文章数量:1357291

I'm building a faceted search system in VueJS. The general idea is simple:

A FilterGroup ponent contains the overall filter logic. This ponent accepts a variety of child ponents, e.g. AttributeXYZFilter. These child ponents are responsible for providing conditions which FilterGroup will use to filter a collection of items.

An example usage of this system looks like this:

<template>
  <FilterGroup :items="items">
    <ABCFilter/>
    <XYZFilter/>
    <AnotherFilter/>
  </FilterGroup>
</template>

My problem is as follows:

The filter ponents should be rendered by FilterGroup in a specific layout. Also, FilterGroup should provide the filter ponents with some additional data using props.

To avoid unnecessary coupling, FilterGroup should not know which filters will be rendered. Each filter adheres to a mon specification/interface (implemented using mixins). Each filter has its own UI template.

How can this be implemented?

I tried using slots, but I can't figure out how to custom render the child ponents. If no slot is being used, this.$children is empty so I don't know which filters to render.

I could provide the filters like this:

<template>
  <FilterGroup :items="items" :filters="['ABCFilter', 'XYZFilter']/>
</template>

Then FilterGroup could dynamically import and render the filter ponents. It would even be possible to pass additional data. However, I think the resulting API is less readable and developer-friendly.

Is there a better way?

I'm building a faceted search system in VueJS. The general idea is simple:

A FilterGroup ponent contains the overall filter logic. This ponent accepts a variety of child ponents, e.g. AttributeXYZFilter. These child ponents are responsible for providing conditions which FilterGroup will use to filter a collection of items.

An example usage of this system looks like this:

<template>
  <FilterGroup :items="items">
    <ABCFilter/>
    <XYZFilter/>
    <AnotherFilter/>
  </FilterGroup>
</template>

My problem is as follows:

The filter ponents should be rendered by FilterGroup in a specific layout. Also, FilterGroup should provide the filter ponents with some additional data using props.

To avoid unnecessary coupling, FilterGroup should not know which filters will be rendered. Each filter adheres to a mon specification/interface (implemented using mixins). Each filter has its own UI template.

How can this be implemented?

I tried using slots, but I can't figure out how to custom render the child ponents. If no slot is being used, this.$children is empty so I don't know which filters to render.

I could provide the filters like this:

<template>
  <FilterGroup :items="items" :filters="['ABCFilter', 'XYZFilter']/>
</template>

Then FilterGroup could dynamically import and render the filter ponents. It would even be possible to pass additional data. However, I think the resulting API is less readable and developer-friendly.

Is there a better way?

Share Improve this question asked Jan 14, 2018 at 21:39 Willem-AartWillem-Aart 2,4604 gold badges20 silver badges29 bronze badges 1
  • Using props, not slots, is the correct approach. Slots are not children. – Roy J Commented Jan 15, 2018 at 0:10
Add a ment  | 

2 Answers 2

Reset to default 4

I think you would like to use Dynamic Components for that. This allows you dynamically render a (child) ponent based on the data. In your example the filters.

The :is="ComponentName" defines the ponent that should be rendered. Use a props to pass down the data:

<template>
    <div class="app-body row">
        <template v-for="(child, index) in children">
            <ponent :is="child.viewName" :key="child.name" :data="child.data"></ponent>
        </template>
    </div>
</template>

Does using scoped-slots solve your problem? You can then provide custom render the child ponents. JSFiddle

Vue.ponent('filter-group', {
  template: `
  <div class="filter-group">
    <slot :items="items">
    </slot>
  </div>
  `,
  data: function() {
    return {
      items: [1, 2, 3, 4, 5]
    }
  }
})

Vue.ponent('filter-a', {
  template: `
  <div class="filter-a">
    filter a: {{ items }}
  </div>
  `,
  props: ['items']
})

Vue.ponent('filter-b', {
  template: `
  <div class="filter-b">
    filter b: {{ items }}
  </div>
  `,
  props: ['items']
})

new Vue({
  el: '#app'
})

本文标签: javascriptDynamically rendering child components in Vuejs v2Stack Overflow