简体   繁体   English

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

[英]Aurelia conditionally wrapping slots in components

I'm creating Aurelia components which wrap material-components-web, cards specifically right now and am wondering what's the correct way of implementing multiple content sections (actions, etc.). 我正在创建Aurelia组件,它们专门包装材料组件 - 网络, 卡片,并且想知道实现多个内容部分(操作等)的正确方法是什么。

Slots seem to be the right choice but I cannot just put the actions div on the template at all times, but only if any actions are actually present. 插槽似乎是正确的选择,但我不能随时将动作div放在模板上,但前提是实际存在任何动作。

Simply put I need to check if a slot has been defined inside the component template. 简单地说,我需要检查组件模板中是否已定义插槽。

<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>

Out-of-the-box, there is no direct way to do this like a $slots property, however you should be able to access slots via the template controller instance itself: au.controller.view.slots - the specific slot inside of this array has more information about the slot itself and its children. 开箱即用,没有直接的方法像$slots属性那样做,但是你应该能够通过模板控制器实例本身访问插槽: au.controller.view.slots - 内部的特定插槽这个数组有关于插槽本身及其子节点的更多信息。

Here is an example of an Aurelia application with a modal component (custom modal element). 以下是具有模态组件(自定义模态元素)的Aurelia应用程序的示例。 The modal itself has a slot where HTML can be projected inside of it. 模态本身有一个插槽,可以在其中投影HTML。 We have a header, body and footer. 我们有一个标题,正文和页脚。

Each predefined slot inside of our custom element should show up inside of a children object, where the property name is the name of our slot. 我们的自定义元素内的每个预定义插槽都应显示在children对象内部,其中属性名称是插槽的名称。 If you do not provide a name for a slot (the default slot) the name of it internally is: __au-default-slot-key__ . 如果您没有为插槽(默认插槽)提供名称,则其内部名称为: __au-default-slot-key__

We first check if the slot exists and then we check the length of its children, the children array exists inside each slot. 我们首先检查插槽是否存在然后检查其子节点的长度,每个插槽中都存在children数组。 If a slot has no HTML projected into it, it will have a children length of zero. 如果插槽中没有投射HTML,则子节点长度为零。 This is reliable, because default content defined inside of the slot does not get put into the children array, only projected HTML does. 这是可靠的,因为在插槽内定义的默认内容不会被放入children数组中,只有投影的HTML才会。

You'll see the work is being done mostly inside of modal.html , but pay close attention to modal.js where we inject the element reference of the custom element and then access the Aurelia instance using au to get to the controller containing our slots itself. 您将看到工作主要在modal.htmlmodal.html ,但要密切关注modal.js ,我们在其中注入自定义元素的元素引用,然后使用au访问Aurelia实例以获取包含我们的插槽的控制器本身。

There is one caveat with this approach: you cannot use if.bind to conditionally remove HTML inside of your custom element. 这种方法有一点需要注意:您不能使用if.bind有条件地删除自定义元素中的HTML。 If you use if.bind on a DIV containing a slot, it actually removes its slot reference so it can't be checked. 如果在包含插槽的DIV上使用if.bind ,它实际上会删除其插槽引用,因此无法检查它。 To work around this, just use show.bind (as I do in my provided running example). 要解决这个问题,只需使用show.bind (就像我在提供的运行示例中所做的那样)。

Use CSS :empty Selector 使用CSS:空选择器

CSS is the right tool for this job, not Aurelia. CSS是这项工作的正确工具,而不是Aurelia。 The :empty selector will allow you to display: none the div.actions when the slot isn't populated. :空选择器将允许您在未填充插槽时display: none div.actions

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

According to the :empty selector spec as explained by CSS-Tricks , white space will cause empty to fail to match, so we just need to remove the white space around the slot. 根据CSS-Tricks解释:空选择器规范 ,空格导致空无法匹配,因此我们只需要移除插槽周围的空白区域。

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

Working example here: https://gist.run/?id=040775f06aba5e955afd362ee60863aa 这里的工作示例: https//gist.run/?id = 040775f06aba5e955afd362ee60863aa

Here's a method I've put together to detect if any slots have children (excluding HTML comments) 这是我用来检测是否有任何插槽有子节点的方法(不包括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 HTML

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

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

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