Aurelia有条件地包装组件中的插槽

时间:2017-07-15 19:11:55

标签: javascript aurelia

我正在创建Aurelia组件,它们现在包装了material-components-web,cards specifically,并且想知道实现多个内容部分(操作等)的正确方法是什么。

插槽似乎是正确的选择,但我不能随时将动作div放在模板上,但只有在实际存在任何动作时才会出现。

简单地说,我需要检查是否在组件模板中定义了一个插槽。

<template>
    <div class="card">
        <div class="content">
            <slot></slot>
        </div>

        <!-- somehow check here if the slot has been defined -->
        <div class="actions">
            <slot name="actions"></slot>
        </div>
    </div>
</template>

3 个答案:

答案 0 :(得分:2)

开箱即用,没有直接的方法像$slots属性那样执行此操作,但是您应该能够通过模板控制器实例本身访问插槽:au.controller.view.slots - 此数组内部的特定插槽有关于插槽本身及其子节点的更多信息。

Here是具有模态组件(自定义模态元素)的Aurelia应用程序的示例。模态本身有一个插槽,可以在其中投影HTML。我们有标题,正文和页脚。

我们自定义元素中的每个预定义插槽都应显示在children对象内,其中属性名称是插槽的名称。如果您没有为插槽(默认插槽)提供名称,则其内部名称为:__au-default-slot-key__

我们首先检查插槽是否存在然后检查其子节点的长度,每个插槽中都存在children数组。如果插槽中没有投射HTML,则子节点长度为零。这是可靠的,因为在插槽内定义的默认内容不会放入children数组中,只会投影HTML。

您将看到工作主要在modal.html内完成,但要密切注意modal.js,我们将注入自定义元素的元素引用,然后使用Aurelia实例访问au到达包含我们插槽的控制器。

此方法有一点需要注意:您无法使用if.bind有条件地删除自定义元素中的HTML。如果在包含插槽的DIV上使用if.bind,它实际上会删除其插槽引用,因此无法检查它。要解决此问题,只需使用show.bind(就像我在提供的运行示例中所做的那样)。

答案 1 :(得分:1)

使用CSS:空选择器

CSS是这项工作的正确工具,而不是Aurelia。 :empty选择器将允许您在未填充插槽的情况下display: none div.actions

.card .actions:empty {
  display: none;
}

根据:empty selector specexplained by CSS-Tricks,空白导致空白无法匹配,因此我们只需要删除插槽周围的空白。

<div class="actions"><slot name="actions"></slot></div>

此处的工作示例:https://gist.run/?id=040775f06aba5e955afd362ee60863aa

答案 2 :(得分:0)

这是我汇总的一种方法,用于检测是否有任何插槽有子级(HTML注释除外)

TypeScript

import { autoinject } from 'aurelia-framework';

@autoinject
export class MyClass {
    private constructor(readonly element: Element) {
    }

    private attached() {
    }

    get hasSlotChildren(): boolean {
        if (!this.element ||
            !(this.element as any).au) {
            return false;
        }
        let childrenCount = 0;
        const slots = (this.element as any).au.controller.view.slots;
        for (let slotName of Object.keys(slots)) {
            const slot = slots[slotName];
            if (slot.children && 
                slot.children.length > 0) {
                for (let child of slot.children) {
                    if (child instanceof Comment) {
                        // Ignore HTML comments
                        continue;
                    }
                    childrenCount++;
                }
            }
        }
        return childrenCount > 0
    }
}

HTML

<template 
    class="my-class" 
    show.bind="hasSlotChildren"
>
    <slot></slot>
</template>