Vue组件是另一个组件的子组件

时间:2018-08-28 19:04:17

标签: javascript html vue.js vuejs2

我正在努力将现有主题转换为可重用的组件。

我目前有一个类似的按钮组件:

<template>
    <a :href="link" class="button" :class="styling"><slot></slot></a>
</template>

<script>
export default {
    props: {
        link: {},
        styling: {
            default: ''
        }
    }
}
</script>

而且,在我的HTML中,我像这样使用它:

<vue-button link="#" styling="tiny bg-aqua">Button 1</vue-button>

现在,我正在尝试使用现有的按钮组件创建一个“按钮组”。

我想做的是这样的:

<vue-button-group styling="radius tiny">
    <vue-button link="#" styling="tiny bg-aqua">Button 1</vue-button>
    <vue-button link="#" styling="tiny bg-aqua">Button 2</vue-button>
    <vue-button link="#" styling="tiny bg-aqua">Button 3</vue-button>
    <vue-button link="#" styling="tiny bg-aqua">Button 4</vue-button>
</vue-button-group>

我是VueJS的新手,对处理此类问题的正确方法有些困惑。我希望能够根据需要将尽可能多的按钮组件传递到组中。

这是到目前为止我对按钮组的了解:

<template>
    <ul class="button-group" :class="styling">
        <li><slot></slot></li>
    </ul>
</template>

<script>
    export default {
        props: {
            styling: {
                default: ''
            }
        }
    }
</script>

这当然可以与传入的单个按钮一起使用,但是我似乎无法弄清楚如何在将每个按钮包含在其自己的列表项中的同时允许更多的操作。

任何对我进行此操作的建议或更正将不胜感激。谢谢。

4 个答案:

答案 0 :(得分:2)

由于您想对组件的输出进行高级处理,因此可能是时候使用render functions了,因为它们可以提供更大的灵活性:

Vue.component('button-group', {
    props: {
        styling: {
            default: ''
        }
    },
    render(createElement) { // createElement is usually called `h`
        // You can also do this in 1 line, but that is more complex to explain...
        // const children = this.$slots.default.filter(slot => slot.tag).map(slot => createElement('li', {}, [slot]))
        const children = [];
        for(let i = 0; i < this.$slots.default.length; i++) {
            if(!this.$slots.default[i].tag) {
                // Filter out "text" nodes, so we don't make li elements
                // for the enters between the buttons
                continue;
            }
            children.push(createElement('li', {}, [
                this.$slots.default[i]
            ]));
        }

        return createElement('ul', {staticClass: "button-group",class: this.styling}, children);
    }
})

var app = new Vue({
  el: '#app',
})
.rainbow-background {
    /* todo: implement rainbow background */
    border: red 1px solid;
}
.button-group {
    border-color: blue;
}
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script>

<div id="app">
    <button-group styling="rainbow-background">
        <button>hi</button>
        <button>How are you?</button>
        <button>I'm fine</button>
        <button>Have a nice day!</button>
    </button-group>
</div>

render函数通过返回虚拟html结构来工作,该结构是通过重复调用createElement函数而生成的。 createElement接受3个参数,标记名(例如ulli),选项对象和子代列表。

我们首先从生成一个带有接收到的插槽的孩子列表开始,这些孩子存储在this.$slots.default内。

然后,我们遍历此列表,过滤掉基本上是文本的传入插槽数据,这是因为HTML将标记之间的空白视为文本的方式。

我们现在几乎完成了最后的结构,现在将slot元素包装在一个新生成的li标签中,然后通过将所有内容包装在一个新的ul标签中来完成的生成正确的类名。

答案 1 :(得分:1)

Vue实现此目的的方法是使用名称插槽,并将子级使用的数据提供给父级。数据将通过slot-scope传播给孩子。

整个过程的关键是数据从父级流到子级

这是该过程的有效代码笔:https://codepen.io/Flamenco/pen/ZMOdYz

该示例使用默认插槽,因此父或子不需要name属性。

父母

<template>
    <ul class="button-group" :class="styling">
        <li v-for='item in items'><slot :item='item'></slot></li>
    </ul>
</template>

<script>
   ...
   props:{
      items: Array
   }
</script>

孩子

<vue-button-group class="radius tiny" :items='items'>
    <template slot-scope='scope'>
       <vue-button link="#" styling="tiny bg-aqua">{{scope.item.text}}</vue-button>
   </template>
</vue-button-group>


<script>
   ...
   data:{
      items:[{text:'Button 1'},{text:'Button 2'},{text:'Button 3}]
   }
</script>

答案 2 :(得分:0)

为此可能的解决方案是使用v-for

<button v-for="button in buttons" :key="button">
Button{{button}}
</button>

这里是fiddle

从那里您可以自己构建<buttongroup>组件;以props的形式将“元信息”传递到您的<buttongroup>中(在我看来,data部分的数组中是这样)。

Slots很有意义,如果您想渲染按钮以外的其他东西,并为此注入组件。否则,您将无法获得任何空位。

答案 3 :(得分:0)

您也可以尝试使用named slot

<template>
    <ul class="button-group">
        <li><slot name="buttons"></slot></li>
    </ul>
</template>

比:

<vue-button-group class="radius tiny">
    <template slot="buttons">
       <vue-button link="#" styling="tiny bg-aqua">Button 1</vue-button>
       <vue-button link="#" styling="tiny bg-aqua">Button 2</vue-button>
       <vue-button link="#" styling="tiny bg-aqua">Button 3</vue-button>
       <vue-button link="#" styling="tiny bg-aqua">Button 4</vue-button>
   </template>
</vue-button-group>