【问题标题】:vue: Dynamically inject property data into <component />vue: 动态注入属性数据到 <component />
【发布时间】:2019-08-11 06:57:26
【问题描述】:

我正在尝试创建一个布局组件,该组件从一个或另一列中的父级动态创建给定组件。在布局组件中,我使用指令来创建子组件。这行得通,但是我很难将数据放入组件本身(它们具有不同的属性集)。

因此:

如何将属性数据注入到指令中?

我有一些事情要做,但是很乱。我可以通过包含所有数据的“genericProps”属性来做到这一点。然后强迫孩子们更新,他们通过updated(),使用Object.assign(this, 'props', this.genericProps)解包genericProps并覆盖它的$props

感觉就像我在这里违背了 vue.js 的一些原则。调试时布局组件的this.$options.components 被填充,但是所有这些组件都没有分配任何propsData。但是在this.$options.components 上直接使用Object.assign() 是行不通的,因为布局组件似乎是这些组件的实际实例,因为它是this.$childrend

我还尝试循环遍历this.$childrend 并分配this.$options.componentspropsData,但必须有一个键来匹配组件与它的正确子级,此时子级不会填充任何属性。

代码 sn-ps 来说明(丑陋的)例子有点工作:

父模板

<template>
  <two-column-layout :firstColumn="$vuetify.breakpoint.mdAndUp ? firstColumn : singleColumn"
                      :secondColumn="$vuetify.breakpoint.mdAndUp ? secondColumn : []"
                      />
</template>

父代码

当来自 API 的异步调用完成时,通过 mount() 或 watch 调用此代码。

  createMetadataContent() {

    let currentContent = this.currentMetadataContent;
    const components = this.$options.components;

    currentContent = this.mixinMethods_enhanceMetadataEntry(currentContent, this.cardBGImages);

    if (currentContent && currentContent.title !== undefined) {

      this.body = metaDataFactory.createBody(currentContent);
      this.$set(components.MetadataBody, 'genericProps', this.body);

      this.citation = metaDataFactory.createCitation(currentContent);
      this.$set(components.MetadataCitation, 'genericProps', this.citation);
      // a few more components and data here


      this.firstColumn = [
        components.MetadataBody,
        // a few more components here
      ];

      this.secondColumn = [
        components.MetadataCitation,
        // a few more components here
      ];

      this.singleColumn = [
        components.MetadataBody,
        components.MetadataCitation,
        // a few more components here
      ];

      this.$forceUpdate();
    }
  }

TwoColumnLayout 模板

<template>          
  <v-layout row wrap>
    <v-flex>

      <v-layout column>
        <v-flex mb-2
                v-for="(entry, index) in firstColumn"
                :key="`left_${index}`"
                >
          <component :is="entry"
                      :genericProps="entry.genericProps"
                      />
        </v-flex>
      </v-layout>
    </v-flex>

    <v-flex v-if="secondColumn" >
      <v-layout column>
        <v-flex mb-2
                v-for="(entry, index) in secondColumn"
                :key="`right_${index}`"
                >
          <component :is="entry"
                      :genericProps="entry.genericProps"
                      />
        </v-flex>
      </v-layout>
    </v-flex>
  </v-layout>
</template>

双列布局代码

updated() {
  this.$children.forEach((child) => {
    child.$forceUpdate();
  });
},

子代码

  props: {
    genericProps: Object,
    id: String,
    citationText: String,
    citationXmlLink: String,
    ciationIsoXmlLink: String,
    ciationGCMDXmlLink: String,
    fixedHeight: Boolean,
    showPlaceholder: Boolean,
  },
  updated: function updated() {
    if (this.genericProps) {
      Object.assign(this, 'props', this.genericProps);
    }
  },

【问题讨论】:

标签: vue.js vuetify.js


【解决方案1】:

我曾经遇到过类似的情况,我有一个动态的&lt;compnonent :is="currentComponent"&gt;,并通过将“childPayload”属性存储到我的数据并将其作为道具传递给孩子来解决它。每当我的有效负载发生变化时,它都会在子级中刷新。

<template>
    <div>
        <div class="btn btn-primary" @click="changePayload">Change Payload</div>
        <component :is="isWhat" :payload="payload"></component>
    </div>
</template>

<script>
    export default {
        name: "Test",
        data() {
            return {
                isWhat: 'div',
                payload: { any: 'data', you: 'want', to: 'pass'}
            }
        },
        methods: {
            changePayload() { // any method or api call can change the data
                this.payload = { some: 'changed', data: 'here' }
            }
        }
    }
</script>

【讨论】:

  • 我理解您的示例,但我正在努力解决具有不同有效负载的多个组件的问题。
【解决方案2】:

我可以通过插槽解决它,但我仍然需要在 LayoutComponent 中使用 forceUpdate()... 但是对于我的情况,使用 genericProps 就足够了。

父模板

  <template v-slot:leftColumn >

    <div v-for="(entry, index) in firstColumn" :key="`left_${index}`" >

      <component :is="entry" :genericProps="entry.genericProps" />
    </div>
  </template>

  <template v-slot:rightColumn>

    <div v-for="(entry, index) in secondColumn" :key="`right_${index}`" >

      <component :is="entry" :genericProps="entry.genericProps" />
    </div>
  </template>

父代码

当来自 API 的异步调用完成时,此代码通过 mounted() 或通过 watch 调用。

  createMetadataContent() {

    let currentContent = this.currentMetadataContent;
    const components = this.$options.components;

    currentContent = this.mixinMethods_enhanceMetadataEntry(currentContent, this.cardBGImages);

    if (currentContent && currentContent.title !== undefined) {

      this.body = metaDataFactory.createBody(currentContent);
      this.$set(components.MetadataBody, 'genericProps', this.body);

      this.citation = metaDataFactory.createCitation(currentContent);
      this.$set(components.MetadataCitation, 'genericProps', this.citation);
      // a few more components and data here


      this.firstColumn = [
        components.MetadataBody,
        // a few more components here
      ];

      this.secondColumn = [
        components.MetadataCitation,
        // a few more components here
      ];

      this.singleColumn = [
        components.MetadataBody,
        components.MetadataCitation,
        // a few more components here
      ];

      this.$forceUpdate();
    }
  }

TwoColumnLayout 模板

    <v-flex v-bind="firstColWidth" >

      <v-layout column>

        <slot name="leftColumn" />

      </v-layout>
    </v-flex>


    <v-flex v-if="secondColumn" v-bind="secondColWidth" >

      <v-layout column>

        <slot name="rightColumn" />

      </v-layout>
    </v-flex>

双列布局代码

updated() {
  this.$children.forEach((child) => {
    child.$forceUpdate();
  });
},

子代码

所有子组件都有 genericProps 对象,可以通过 mixin 方法访问

    props: {
      genericProps: Object,
    },
    computed: {
      title() {
        return this.mixinMethods_getGenericProp('title');
      },
      id() {
        return this.mixinMethods_getGenericProp('id');
      },
      description() {
        return this.mixinMethods_getGenericProp('description');
      },
    }

混合方法

    mixinMethods_getGenericProp(propName) {
      return this.genericProps[propName] ? this.genericProps[propName] : null;
    },

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-03-15
    • 1970-01-01
    • 2018-02-25
    • 2021-09-12
    • 1970-01-01
    • 1970-01-01
    • 2019-08-06
    • 2023-03-18
    相关资源
    最近更新 更多