VueJs:组件槽作为属性

时间:2017-05-17 08:32:41

标签: vue.js vuejs2 vue-component

我已阅读文档,但我不确定我想要实现的目标是否真的可行。 我所追求的是包含html标签的组件属性,显然会产生无效的html - 因此我想知道是否有一种方法可以将html传递给组件并使用发出的事件进一步发送。 最合适的方法是named slot,但我认为我不能将命名广告位的内容与内部属性相关联。

我正在处理的组件是一个简单的确认对话框。触发器组件将包装两个插槽 - 一个用于标签,另一个用于消息,我希望将事件调度到对话框组件。

我的触发器组件目前看起来像这样:

<template>
    <a :class="cssClass" @click="clicked()">
        <slot></slot>
    </a>
</template>
<script>
    export default {
        props: {
            id: {
                type: String,
                required: true
            },
            route: {
                type: String,
                required: true
            },
            message: {
                type: String,
                required: true
            },
            cssClass: {
                type: String,
                required: false
            }
        },
        mounted() {
            window.EventHandler.listen('confirm-dialog-' + this.id + '-called', () => {
                window.location.reload(true);
            });
        },
        methods: {
            clicked() {
                window.EventHandler.fire('top-confirm', {
                    id: 'confirm-dialog-' + this.id,
                    message: this.message,
                    url: this.route
                });
            }
        }
    };
</script>

并添加到html:

<call-dialog
    route="{{ route('subscriber.destroy', $subscriber->id) }}"
    css-class="alert"
    id="{{ $subscriber->id }}"
    message="Are you sure you wish to remove '{{ $subscriber->email }}'?<br />There is no undo!"
>
   <i class="fa fa-trash"></i> Remove
</call-dialog>

正如您所看到的,目前我正在使用message道具传递消息,但此特定内容包含<br />标记,这会生成无效的HTML。

知道如何解决这个问题吗?

注意

我想我已经找到了使用命名插槽的方法:

<template>
    <a :class="cssClass" @click.prevent="clicked()">
        <slot name="label"></slot>
    </a>
</template>
<script>
    export default {
        props: {
            id: {
                type: String,
                required: true
            },
            route: {
                type: String,
                required: true
            },
            cssClass: {
                type: String,
                required: false
            }
        },
        mounted() {
            window.EventHandler.listen('confirm-dialog-' + this.id + '-called', () => {
                window.location.reload(true);
            });
        },
        methods: {
            message() {
                 return this.$slots.message[0].context.message;
            },
            clicked() {
                window.EventHandler.fire('top-confirm', {
                    id: 'confirm-dialog-' + this.id,
                    message: this.message(),
                    url: this.route
                });
            }
        }
    };
</script>

现在只需传递和附加命名的广告位slot="message"

<call-dialog
    route="{{ route('subscriber.destroy', $subscriber->id) }}"
    css-class="alert"
    id="{{ $subscriber->id }}"
>
    <span slot="label"><i class="fa fa-trash"></i></span>
    <span slot="message">Are you sure you wish to remove '{{ $subscriber->email }}'?<br />There is no undo!</span>
</call-dialog>

2 个答案:

答案 0 :(得分:0)

您应该在v-html组件内部使用call-dialog将原始HTML从消息道具插入到元素中。

<div v-html="message"></div>

https://vuejs.org/v2/api/#v-html

答案 1 :(得分:0)

我必须对自定义按钮组件执行类似的操作。

Vue.prototype.$getSlotText = function( name = 'default' ) {
    const htmlElements = this.$slots[name];
    if(!htmlElements || !htmlElements.length) return '';

    return htmlElements.reduce((fullText, {tag, text}) => {
        return fullText + (tag === 'br' ? '\n' : text || '');
    }, '');
}

本质上,这将访问“默认”位置(默认情况下)上的HTML元素。

  • 如果未找到,则返回''空字符串。
  • 如果找到某些元素,则对每个Element进行迭代,如果找到,则将其串联为text属性,如果是\n则将其串联为<br/>

注意:.reduce(...)方法用于迭代/串联。另外,使用类似箭头功能的.map(...)调用,后接.join('')可能会产生相同的结果。