vue将自定义组件作为属性传递给父组件

时间:2019-12-29 19:19:38

标签: javascript vue.js vuejs2

我还没有看到其他尝试回答我在做什么的问题,我不确定是否只是我没有在寻找正确的语言,所以我将解释发生的情况。

我正在尝试开发一个界面,用户可以使用vue拖动或输入图像。我也有一个名为Card的组件,它对于类似卡片的对象有些虚假的东西。 Card组件有两个propstitlecontent。当您要填充titlecontent属性的内容是预加载的文本或图像数据时,使用起来非常简单。

但是,我想做的是在Card内放置另一个 vue组件npmPictureInput的{​​{1}}组件) 。我正在尝试通过将其作为vue-picture-input道具来实现。我已经阅读了reactive propsdynamic components上的vue文档,但都没有真正谈论这个用例。

代码:

Card.vue:

content

ImageInput.vue:

    <template>
      <div class="card is-size-7-mobile is-fluid">
        <div class="card-header">
          <a class="card-header-title">
            <span class="is-info">{{this.title}}</span>
          </a>
          <span v-if="this.isExpanable">
            <a class="card-header-icon card-toggle">
              <span class="icon" @click="arrowClick">
                <span v-if="!this.open">
                  <font-awesome-icon :icon="['fas', 'angle-down']"></font-awesome-icon>
                </span>
                <span v-else>
                  <font-awesome-icon :icon="['fas', 'angle-up']"></font-awesome-icon>
                </span>
              </span>
            </a>
          </span>
        </div>
          <slide-up-down :active="this.open" :duration="400" v-if="this.isExpanable">
            <div v-if="this.open" class="card-content is-size-7-mobile">
              <div class="content">{{this.content}}</div>
            </div>
          </slide-up-down>
          <div v-else>
            <div class="content">{{this.content}}</div>
          </div>
        </div>
    </template>

    <script>
    export default {
      data() {
        return {
          open: false
        };
      },
      props: {
        title: "",
        content: null,
        isExpanable: false
      },
      methods: {
        arrowClick(event) {
          this.open = !this.open;
        }
      }
    };
    </script>

    <style scoped>
    .card {
      border-radius: 1em;
      background-color: transparent !important;
      border-color: transparent !important;
    }
    .card-header {
      box-shadow: transparent;
    }
    </style>

您可以使用 <template> <div class="content"> <Card :title="makeCardTitle()" :content="makeCardContent()"/> </div> </template> <script> import PictureInput from 'vue-picture-input'; import Card from './Card'; import Vue from 'vue'; export default { name: 'ImageInput', components: { PictureInput, Card }, props: { idx:{ type:Number, default: 0 } }, data() { return { pictureComponent: "PictureInput" } }, methods: { makeCardTitle: function(){ return "page ".concat(String(this.idx)) }, makeCardContent: function(){ var PictureInputClass = Vue.extend(PictureInput); var pictureInputInstance = new PictureInputClass(); return pictureInputInstance } } } </script> <style scoped> </style> 代码看到,我尝试动态构造ImageInput.vue对象,并将其作为prop PictureInput传递给content,但是它没有正常工作时,我遇到两个错误,一个是Card中的“循环对象值”,另一个是Card对象没有PictureInputClass方法,我猜这是Vue框架的某些部分预期。我也尝试过这样做: toJSON,但是最终我得到关于<Card :title="makeCardTitle()" :content="PictureInput"/>是如何定义的,但在渲染过程中如何引用的错误。也许我可以将PictureInput更改为命名的content,但是我不确定这是否也是我想要的。

我要经历所有这些的原因是,我非常欣赏Vue在创建接口时如何设计为允许组件重新使用和彼此重新集成。我显然可以从<slot></slot>中提取(大部分)模板,然后针对这种情况重新配置它,但是我想看看是否有一种更简单的方法来使Card组件成为PictureInput组件。

1 个答案:

答案 0 :(得分:1)

我将使用插槽将PictureInput组件放入Card组件。我删除了一些HTML作为简化示例。

Card.vue

<template>
  <div class="card is-size-7-mobile is-fluid">
        <div class="card-header">
            <a class="card-header-title">

                <!-- Don't need to use "this" keyword inside the template,
                it is implied that the context is already "this" -->
                <span class="is-info" @click="isExpanable = !isExpanable">{{title}}</span>
            </a>
        </div>
        <div v-if='isExpanable'>
            <slot/> <!-- Slot where the <PictureInput/> will be inserted -->
        </div>
    </div>
</template>

<script>
export default {
  data() {
    return {
      isExpanable: false, // internal state to manage the open/close toggle
    }
  },
  props: {
    title: String, // Define the data type
  }
};
</script>

<style scoped>
.card {
  border-radius: 1em;
  background-color: transparent !important;
  border-color: transparent !important;
}
.card-header {
  box-shadow: transparent;
}
</style>

ImageInput.vue

<template>
<div class="content">
    <Card :title="makeCardTitle">
        <PictureInput/>
    </Card>
</div>
</template>

<script>
import PictureInput from 'vue-picture-input';
import Card from './Card';

export default {
    name: 'ImageInput',
    components: {
        PictureInput,
        Card
    },
    props: {
        idx:{
            type:Number,
            default: 0
        }
    },
    computed: {
        // Should be a computed property since we are creating data from internal data "idx"
        makeCardTitle: function(){
            return "page ".concat(String(this.idx));
        }
    }
}
</script>

希望这会指导您正确的方向。另外,您不必使用Vue.extend(PictureInput)实例化。通常,您要做的就是将其添加到components选项键中。