繁体   English   中英

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

[英]vue pass custom component as a property to parent component

我还没有看到其他试图回答我正在做的事情的问题,我不确定是否只是我没有在寻找正确的措辞,所以我会解释发生了什么。

我正在尝试开发一个界面,用户可以在其中使用 vue 拖动或输入图像。 我还制作了一个名为Card的组件,它有点像卡片对象的 vue 和 bulma。 Card组件有两个propstitlecontent 当您要填写的titlecontent属性是预加载的文本或图像数据时,使用起来非常简单。

但是,我想做的是在Card内放置另一个vue 组件(来自npm上的vue-picture-inputPictureInput组件)。 我试图通过将它作为content道具传递来做到这一点。 我已经阅读了关于反应性道具动态组件的 vue 文档,但都没有真正谈论这个用例。

代码:

卡片.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>

图像输入.vue:

    <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代码中看到的那样,我尝试动态构造PictureInput对象并将其作为道具content传递给Card但它不起作用,我收到两个错误,一个是Card中的“循环对象值”另一个是PictureInputClass对象没有toJSON方法,我猜测 vue 框架的某些部分是期望的。 我也尝试过这样做: <Card :title="makeCardTitle()" :content="PictureInput"/> ,但我最终得到有关PictureInput未定义但在渲染期间被引用的错误。 也许我可以将content更改为命名的<slot></slot>但我不确定这是否也是我想要的。

我经历这一切的原因是,我真的很欣赏 Vue 是如何被设计成在创建界面时允许组件被重用和重新集成的。 我显然可以从Card中获取(大部分)模板并针对这种情况重新配置它,但我想看看是否有更简单的方法可以让PictureInput组件成为Card组件的子组件。

我会使用插槽将 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>

图像输入.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) 进行实例化。 通常,您需要做的就是将其添加到组件选项键中。

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM