简体   繁体   English

Vue:如何根据父数据渲染动态组件?

[英]Vue: How do I render a dynamic component based on parent data?

I am trying to render components based on the data that is passed to the parent page.我正在尝试根据传递给父页面的数据来呈现组件。

I am trying to use dynamic components to render the correct components based on the JSON object @type and grab the file name in the url (without the extension) of that object to then render the related component and pass the data from Page.vue to the rendered components.我正在尝试使用动态组件基于 JSON 对象@type呈现正确的组件,并在该对象的 url (不带扩展名)中获取文件名,然后呈现相关组件并将数据从Page.vue 传递到渲染的组件。

If I set :is="content.@type" (as an example) then the output will render child components with the name Image & Video (removing everything in the URL expect for the filename) to render the correct component.如果我设置:is="content.@type" (例如),那么输出将呈现名为Image & Video的子组件(删除 URL 中期望文件名的所有内容)以呈现正确的组件。

Is this possible or is there a better approach to this?这是可能的还是有更好的方法呢?

Data:数据:

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"

The data comes from a CMS and I'm not able to change the data.数据来自 CMS,我无法更改数据。

Page.vue页面.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>

Child Component Example Images.vue子组件示例 Images.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>

As mentioned in the comment, you could parse the URL in a method with v-bind:is directive.如评论中所述,您可以使用v-bind:is指令在方法中解析 URL。 You've probably figured it out by now, but here's my quick attempt.您现在可能已经弄清楚了,但这是我的快速尝试。

 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>

BTW, I would advise against using HTML reserved words as the component names (like in your case<video> ) as it may fail to compile.顺便说一句,我建议不要使用HTML 保留字作为组件名称(如您的情况<video> ),因为它可能无法编译。 See this related issue on GitHub.在 GitHub 上查看此相关问题

[Vue warn]: Do not use built-in or reserved HTML elements as component id: Dialog [Vue 警告]:不要使用内置或保留的 HTML 元素作为组件 id:Dialog

Your approach is correct.你的方法是正确的。 You can use the is directive to call your components.您可以使用is指令来调用您的组件。 It is the best way.这是最好的方法。

As you asked, you need a method in your Page.vue to parse your @type .正如您所问的,您需要在Page.vue中使用一个方法来解析您的@type

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

Now you can use this function in your template.现在您可以在模板中使用此功能。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Vue,如何在渲染方法中将数据传递给组件 - Vue, how do I pass data to component in render method 如何通知父组件Vue动态组件中发生了什么? - How do I inform the parent component that something has happened in a Vue dynamic component? 如何基于 state 渲染组件 - How do I render component based on state 如何在父组件中使用来自 Vue.js 子组件的数据? - How do I use data from Vue.js child component within parent component? 如何在 Vue 的 iframe 中渲染子组件? - How do I render a child component within an iframe in Vue? 使用 vue-js-modal 如何将数据传回父组件 - Using vue-js-modal how do I pass data back up to the parent component 如何不渲染 ViewChild 元素,而是在父组件中访问它? - How do I not render ViewChild element but access it in the parent component instead? 如何在不刷新 Vue.js 中的页面的情况下在同一组件内单击动态链接时呈现动态数据 - How to render dynamic data on clicking dynamic link within the same component without refreshing the page in Vue.js 如何在 Modal 组件中为我的文本呈现动态变量? - How do i render a dynamic variable for my text in the Modal component? 如何在 Vue 中创建动态编辑器表单组件 - How do I create a dynamic editor form component in Vue
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM