[英]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.