【问题标题】:Vue: How do I render a dynamic component based on parent data?Vue:如何根据父数据渲染动态组件?
【发布时间】:2019-06-09 17:47:47
【问题描述】:

我正在尝试根据传递给父页面的数据来呈现组件。

我正在尝试使用动态组件来根据 JSON 对象 @type 渲染正确的组件,并在 (不带扩展名) 的 url 中获取文件名该对象然后渲染相关组件并将数据从 Page.vue 传递到渲染的组件。

如果我设置 :is="content.@type" (作为示例),那么输出将呈现名称为 ImageVideo 的子组件(删除 URL 中除文件名之外的所有内容)以呈现正确的组件。

这是可能的还是有更好的方法来解决这个问题?

数据:

Content: object
  Content [Array]
    0:Object
      @id: "4effb045"
      @type: "http://url/images.json"
      _meta: Object
         name: "TestingImage"
    1:Object
      @id: "4effb045"
      @type: "http://url/video.json"
      _meta: Object
         name: "TestingVideo"

数据来自 CMS,我无法更改数据。

Page.vue

<template>
  <div id="page" v-if="content" class="page-wrapper container" :cid="this.$root.cidItem">

    <div class="row">

      <div class="page__items">

        <component v-for="content in content.content" :is="content.@type" :key="content.id"></component>

      </div>
    </div>

  </div>
</template>

<script>
  import axios from 'axios'
  import Images from "./components/Images"
  import Video from "./components/Video"
  import TextType from "./components/TextType"
  import Card from "./components/Card"

  export default {
    name: 'page',
    props: ['cid'],
    components: {
      Images,
      Video,
      TextType,
      Card
    },

    mounted () {
      axios({
        method: 'GET',
        'url': this.$root.contentDeliveryUrl + this.$root.encodedQuery + this.$root.cidItem + this.$root.store
      }).then(result => {
        // eslint-disable-next-line
        this.content = amp.inlineContent(result.data)[0];
        console.log(this.content)
      }, error => {
        console.error(error)
      })
    },
    data () {
      return {
        content: []
      }
    }

  }
</script>

<style lang="scss">
  @import '../node_modules/bootstrap-css-only/css/bootstrap.min.css';
  .container {
    max-width: 1366px;
  }
</style>

子组件示例 图片.vue

<template>
  <div class="images-wrapper container">
    <div class="row">
      <div class="col">
        <div class="images">
          {{content.imageAltText}}
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>

export default {
  name: 'Images'
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
  .images-wrapper {
    &__image {

    }
  }
</style>

【问题讨论】:

  • 那的输出是什么?
  • 如果我设置 :is="content._meta" (作为示例),那么输出将呈现名称为 的子组件,这与我的组件名称和没有数据通过。 @type 返回一个无效的表达式
  • 不确定我是否理解这一行 ...will render child components with the name... 使用名称渲染是什么意思?
  • 编辑以更好地解释。
  • 好吧,我相信你可以在一个方法中做文件名提取工作,并在:is指令上使用它。

标签: javascript vue.js vuejs2


【解决方案1】:

正如评论中提到的,您可以使用 v-bind:is 指令在方法中解析 URL。您现在可能已经弄清楚了,但这是我的快速尝试。

const content = {
  content: [{
    '@id': '4effb045',
    '@type': 'http://url/images.json',
    _meta: {
      name: 'TestingImage'
    }
  }, {
    '@id': '4effb046',
    '@type': 'http://url/videos.json',
    _meta: {
      name: 'TestingVideo'
    }
  }]
}

new Vue({
  el: '#app',

  data() {
    return {
      content
    }
  },

  methods: {
    extractName(content) {
      const [name] = /[^\/]*(?=\.\w+$)/.exec(content['@type']);

      return name;
    }
  },

  components: {
    Images: {
      template: '<img src="https://via.placeholder.com/150x45" />'
    },

    Videos: {
      template: '<div>Some video component</div>'
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <component 
    v-for="content in content.content" 
    :is="extractName(content)" 
    :key="content['@id']">
  </component>
</div>

顺便说一句,我建议不要使用 HTML 保留字 作为组件名称(例如在您的情况下为 &lt;video&gt;),因为它可能无法编译。请参阅 GitHub 上的 related issue

[Vue 警告]:不要使用内置或保留的 HTML 元素作为组件 id:Dialog

【讨论】:

    【解决方案2】:

    你的方法是正确的。您可以使用is 指令来调用您的组件。这是最好的方法。

    如您所问,您需要在 Page.vue 中使用一个方法来解析您的 @type

    methods: {
        parseType: function(type) {
            let typeParts = type.split("/")
            let filenameParts = typeParts[typeParts.length - 1].split('.')
            let parsedType = filenameParts[0]
            return parsedType 
        }
    }
    

    现在您可以在模板中使用此功能了。

    <component v-for="content in content.content" :is="parseType(content.@type)" :key="content.id"></component>
    

    【讨论】:

      猜你喜欢
      • 2019-04-29
      • 1970-01-01
      • 1970-01-01
      • 2021-08-15
      • 1970-01-01
      • 2021-09-15
      • 1970-01-01
      • 1970-01-01
      • 2018-03-10
      相关资源
      最近更新 更多