如何在Vue中的插槽内设置组件的属性?

时间:2018-06-14 10:59:14

标签: vue.js vue-component

问题

我有一个BaseFormControl组件接受id道具。它将id prop值设置为for元素上的<label>属性值和给定输入上的id属性值。由于我希望BaseFormControl是一个可以与各种输入类型重用的通用组件,我将输入作为一个插槽传递。以下组件的代码:

<script>
export default {
   props: {
     id: {
       type: String,
       required: true
     }
   }
};
</script>

<template>
  <div>
    <label :for="id">
      <slot name="label" />
    </label>
    <slot
      name="input"
      :id="id"
    />
  </div>
</template>

这种方法的问题是<slot>没有将任何属性传递给插槽内容,因此:id根本不会传递给实际输入。

所以我尝试以编程方式设置它:

export default {
   props: {
     id: {
       type: String,
       required: true
     }
   }

   created() {
     let inputSlot = this.$slots.input;
     if (inputSlot) {
       inputSlot[0].data.attrs.id = this.id;
     }
   }
};

在某些情况下它完美地工作(作为插槽传递的输入在其HTML中正确设置了id属性),但在其他情况下它没有。特别有趣的是,所有输入组件(我在输入槽中放入的是另一个基本组件,而不是通用的<input>标签)实际上已经this.$attrs正确地填充了id,但是有时它出现在实际的HTML中,有时它不会出现。

有人可以解释我的行为,告诉我我做错了什么以及如何解决这个问题?

我创建了一个pen来说明这些概念。唯一的问题是在笔中一切正常。在我的应用中,只有1个选项在页面上,只有1个设置正确id - 另一个在没有id的情况下呈现(尽管id设置在其中this.$attrs })。

2 个答案:

答案 0 :(得分:1)

  

这种方法的问题在于没有将任何属性传递给插槽内容,

您正在做的是将id作为广告位数据传递到广告位。这意味着您正在创建scoped slot

您可以使用BaseFormControl属性在slot-scope中访问此数据。

<BaseFormControl :id="'myInput'">
  <p slot="label">Input label</p>
  <input slot="input" slot-scope="props" :id="props.id" type="text" placeholder="type anythin">
</BaseFormControl>

PS:

如果您将id作为道具传递,可以直接使用它来设置输入的ID,如下所示

<BaseFormControl :id="'myInput'">
  <p slot="label">Input label</p>
  <input id="myInput" type="text" placeholder="type anythin">
</BaseFormControl>

答案 1 :(得分:0)

寻找解决方案我决定最简单的方法是为组件添加“for”属性并将其转发到标签。

我还手动为插槽内容设置了“id”属性。这几乎与我们在 HTML 中使用 <label> 的方式相同。

<!-- component.vue -->
<template>
    <div class="form-group row my-2">
        <label class="col-4 col-form-label" :for="$props.for">{{ label }}</label>
        <div class="col-8" >
            <slot></slot>
        </div>
    </div>
</template>
<script>

export default {
    name: "SettingsRow",
    props: {
        label: {required: true, type: String},
        for: {required: true, type: String}
    }
}
</script>

这就是我使用这个组件的方式。

<settings-row label="Choose chromosome" for="someId">
    <select v-model="ch" id="someId">
        <option>X</option>
        <option>Y</option>
    </select>
</settings-row>

看起来所有其他方法都需要许多不明确的属性用于组件本身及其使用中的作用域/命名插槽。