Vue js动态组件

时间:2018-04-28 09:13:40

标签: vuejs2 vue-component

我有一个元素的数据结构,如:

[
  {
    type: 'text',
    content: 'some text'
  },
  {
    type: 'image',
    content: {
      name: 'filename.jpg',
      url: 'http://example.com/filename.jpg'
    }
  }
]

在我的模板中,我使用if进行v-for以根据类型呈现不同的组件:

<div v-for="element in elements">
  <div v-if="element.type === 'text'">
    <p>{{ element.content }}</p>
  </div>
  <div v-if="element.type === 'image'">
    <some-component :image="element.content"></some-component>
  </div>
</div>

我的问题是,有没有“更清洁”,更好的方法呢?

1 个答案:

答案 0 :(得分:1)

我想我会根据<component>标签创建一个组件交换器 - 比如:

&#13;
&#13;
//  template swapper based on the <component> tag
//  :is     - string value pointing to the component to be used
//  :value  - data to be used in the selected component 
Vue.component('vue-html-tag', {
  props: ['value'],
  template: `<component :is="'vue-' + value.tag + '-tag'" :value="value"></component>`
});


//  tag components 
Vue.component('vue-p-tag', {
  props: ['value'],
  template: `<p :class="value.class">
        {{ value.text }}
        <vue-html-tag v-for="item in value.content" :key="item.id" :value="item"></vue-html-tag>
    </p>`
});

Vue.component('vue-img-tag', {
  props: ['value'],
  template: `<img :src="value.src" />`
});

Vue.component('vue-a-tag', {
  props: ['value'],
  template: `<a :href="value.href" :target="value.target">{{ value.text}}</a>`
});

Vue.component('vue-span-tag', {
  props: ['value'],
  template: `<span :class="value.class">
        {{ value.text }}
        <vue-html-tag v-for="item in value.content" :key="item.id" :value="item"></vue-html-tag>
    </span>`
});



//  app instance
new Vue({
  el: '#app',
  data: {
    html: [
      { id: 1, tag: 'p', text: 'Lorem ipsum', class: 'foo',
        content: [
          { id: 11, tag: 'span', text: 'Nested span:', class: 'foo-span',
            content: [
              { id: 111, tag: 'a', text: 'Link 1 inside span inside p', href: 'http://example.com' },
              { id: 112, tag: 'a', text: 'Link 2 inside span inside p', href: 'http://example.com' },
          ]
        }]
      },
      { id: 2, tag: 'img', src: 'http://via.placeholder.com/350x150' },
      { id: 3, tag: 'a', text: 'Link', href: 'http://example.com' }
    ]
  }
})
&#13;
.foo {
  padding: 10px;
  border: 1px solid olive
}

.foo-span {
  padding: 20px;
  display: block;
  border: 1px solid orange
}

.foo-span a {
  display: block;
  padding: 10px;
  margin-bottom: 5px;
  border: 1px solid tomato
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.js"></script>

<div id="app">
  <vue-html-tag v-for="item in html" :key="item.id" :value="item"></vue-html-tag>
</div>
&#13;
&#13;
&#13;