使用组合我们可以用来设计复杂的组件。
组合一些比较小的组件,可以增加组件的重新性以及可维护性。
通过以下一个简单的demo,将会展示关于owner 以及container 的概念,在实际的项目中
example-todo-item 一般是通过for:each 循环动态填充的

 
<!-- todoApp.html -->
<template>
    <example-todo-wrapper>
        <example-todo-item item-name="Milk"></example-todo-item>
        <example-todo-item item-name="Bread"></example-todo-item>
    </example-todo-wrapper>
<template>
 
 

owner

onwer 是拥有该模版的组件,在以上的demo中onwer 是example-todo-app
onwer 控制所有他包含的组合组件,onwer 可以

  • 在组合组件中设置public 属性
  • 调用组合组件中的public 方法
  • 监听通过组合组件分发的事件

container

container包含其他组件,但它本身包含在所有者组件中,在以上的demo 中example-todo-wrapper
是一个container,container 不如onwer 强大,container 可以

  • 读取,但是不能修改包含的组件的public 属性
  • 调用组合组件的额public 方法
  • 监听由它包含的组件冒出的一些事件,但不一定是所有事件

父子

父组件可以包含子组件,父组合可以是一个onwer 或者containerr

在子组件设置属性

要将包含层次结构从所有者传递到子项,所有者可以在子组件上设置属性或属性。
HTML中的属性变为JavaScript中的属性赋值

  • 参考demo
    todoApp.js
 
import { LightningElement, api } from 'lwc';
export default class TodoApp extends LightningElement {}
 
 

todoApp.html

<template>
    <example-todo-item item-name="Milk"></example-todo-item>
    <example-todo-item item-name="Bread"></example-todo-item>
</template>
 
 

todoitems.js

import { LightningElement, api } from 'lwc';
export default class TodoItem extends LightningElement {
    @api itemName;
}
 
 

todoitems.html

<template>
    <div>{itemName}</div>
</template>
 
 
  • 说明
    JavaScript中的属性名称是驼峰大小写,而HTML属性名称是kebab大小写(以破折号分隔)
    以匹配HTML标准。在todoApp.html,item-name标记中的属性映射到的itemName JavaScript
    属性todoItem.js。

调用子组件的方法

对于public 的方法可以通过@api 装饰器进行配置
以下是一个简单的demo

  • 组件class
 
// videoPlayer.js
import { LightningElement, api } from 'lwc';
export default class VideoPlayer extends LightningElement {
    @api videoUrl;
    @api
    get isPlaying() {
        const player = this.template.querySelector('video');
        return player !== null && player.paused === false;
    }
    @api
    play() {
        const player = this.template.querySelector('video');
        // the player might not be in the DOM just yet
        if (player) {
            player.play();
        }
    }
    @api
    pause() {
        const player = this.template.querySelector('video');
        if (player) {
            // the player might not be in the DOM just yet
            player.pause();
        }
    }
    // private method for computed value
    get videoType() {
        return 'video/' + this.videoUrl.split('.').pop();
    }
}
 
 
  • 组件模版
<!-- videoPlayer.html -->
<template>
    <div class="fancy-border">
        <video autoplay>
            <source src={videoUrl} type={videoType} />
        </video>
    </div>
</template>
 
 
  • 创建调用组件方法的cnotainer
<!-- methodCaller.html -->
<template>
    <div>
        <example-video-player video-url={video}></example-video-player>
        <button onclick={handlePlay}>Play</button>
        <button onclick={handlePause}>Pause</button>
    </div>
</template>
 
 
  • container 组件class
// methodCaller.js
import { LightningElement } from 'lwc';
export default class MethodCaller extends LightningElement {
    video = "https://www.w3schools.com/tags/movie.mp4";
    handlePlay() {
        this.template.querySelector('example-video-player').play();
    }
    handlePause() {
        this.template.querySelector('example-video-player').pause();
    }
}
 
 
  • 返回值
    对于返回值的处理,我们通过getter 参考
 
@api get isPlaying() {
    const player = this.template.querySelector('video');
    return player !== null && player.paused === false;
}
 
 
  • 方法参数
@api play(speed) { … }
 
 

传递标记到slots

slot 是一个占位符,我们可以传递数据到组件体中,slot 是web components 的一部分
slot 包含命名以及非命名类型,同时对于slot 内容的变动,我们可以通过事件进行操作

  • 非命名slot
    子组件模版
<template>
    <h1>Content in Slot Demo</h1>
    <div>
        <slot></slot>
    </div>
</template>
 
 

slot 占位符填充

<example-slot-wrapper>
    <example-slot-demo>
        <h1>Content in Slot Demo</h1>
        <div>
            <slot><p>Content from Slot Wrapper</p></slot>
        </div>
    </example-slot-demo>
</example-slot-wrapper>
 
 
  • 命名slot
    参考格式
 
<!-- namedSlots.html -->
<template>
    <p>First Name: <slot name="firstName">Default first name</slot></p>
    <p>Last Name: <slot name="lastName">Default last name</slot></p>
    <p>Description: <slot>Default description</slot></p>
</template>
 
 

slot 内容填充

<!-- slotsWrapper.html -->
<template>
    <example-named-slots>
        <span slot="firstName">Willy</span>
        <span slot="lastName">Wonka</span>
        <span>Chocolatier</span>
    </example-named-slots>
</template>
 
 
  • slotchange 事件
    格式
 
<!-- container.html -->
<template>
    <slot onslotchange={handleSlotChange}></slot>
</template>
 
 

代码处理

//container.js
handleSlotChange (e) {
   console.log("New slotted content has been added or removed!");
}
 
 

query selector

querySelector() 以及 querySelectorAll() 是标准的dom 操作api,通过此api 我们可以操作组件的dom元素

  • 参考模版
<!-- example.html -->
<template>
   <div>First <slot name="task1">Task 1</slot></div>
   <div>Second <slot name="task2">Task 2</slot></div>
</template>
 
 
  • 操作api
// example.js
import { LightningElement } from 'lwc';
export default class Example extends LightningElement {
    renderedCallback() {
        this.template.querySelector('div'); // <div>First</div>
        this.template.querySelector('span'); // null
        this.template.querySelectorAll('div'); // [<div>First</div>, <div>Second</div>]
    }
}
 
 
  • 访问slot 中的元素
    组件不包含通过slot 传递的参数,如果我们需要访问可以通过this.querySelector() 以及 this.querySelectorAll()
    参考代码
 
// namedSlots.js
import { LightningElement } from 'lwc';
export default class NamedSlots extends LightningElement {
    renderedCallback() {
        this.querySelector('span'); // <span>push the green button.</span>
        this.querySelectorAll('span'); // [<span>push the green button</span>, <span>push the red button</span>]
    }
}
 
 

通过slot 以及data 进行组件组合

  • 通过slot 组合组件
    参考组件模版
 
<example-parent>
    <example-custom-child></example-custom-child>
    <example-custom-child></example-custom-child>
</example-parent>
 
 

为了支持这种模式,组件作者使用slot 元素,但是组件作者必须管理通过slot 传递元素的
生命周期,解决方法,通过通知事件,父组件需要知道子组件可以进行
通信,可以在父组件通过附加在slot 元素上的事件handler
参考代码
组件模版

 
<!-- parent.html -->
<template>
    <div onprivateitemregister={handleChildRegister}>
        <!– Other markup here -->
        <slot></slot>
    </div>
</template>
 
 

代码

handleChildRegister(event) {
    // Suppress event if it’s not part of the public API
    event.stopPropagation();
    const item = event.detail;
    const guid = item.guid;
    this.privateChildrenRecord[guid] = item;
}
 
 

处理事件通知自组件的父级,父组件需要使用全局唯一的id 才能使用组件,所以我们看到以上代码使用了guid
要从子组件分发事件,需要使用connectedCallback
参考

connectedCallback() {
    const itemregister = new CustomEvent('privateitemregister', {
        bubbles: true,
        detail: {
            callbacks: {
                select: this.select,
            },
            guid: this.guid,
         }
    });
    this.dispatchEvent(itemregister);
}
 
 

要通知父组件,自组件不可用,我们需要再父子组件之间建立双向通信

在注册期间子组件发送回调到父组件
父组件通过回调调用子组件,将两一个回调做为参数传递
子组件在取消注册的时候调用父组件的回调
 
 

参考处理:
父组件模版

 
<!-- parent.html -->
<template>
    <slot onprivateitemregister={handleChildRegister}>
    </slot>
</template>
 
 

处理通知子组件不可用的事件

// parent.js
handleChildRegister(event) {
    const item = event.detail;
    const guid = item.guid;
    this.privateChildrenRecord[guid] = item;
    // Add a callback that
    // notifies the parent when child is unregistered
    item.registerDisconnectCallback(this.handleChildUnregister);
}
handleChildUnregister(event) {
    const item = event.detail;
    const guid = item.guid;
    this.privateChildrenRecord[guid] = undefined;
}
 
 

自组件在取消注册时调用的组组件回调

// child.js
connectedCallback() {
    const itemregister = new CustomEvent('privateitemregister', {
        bubbles: true,
        detail: {
            callbacks: {
                registerDisconnectCallback: this.registerDisconnectCallback
            },
            guid: this.guid,
         }
    });
    this.dispatchEvent(itemregister);
}
// Store the parent's callback so we can invoke later
registerDisconnectCallback(callback) {
    this.disconnectFromParent = callback;
}
 
 

子组件通知父组件自生不可用

disconnectedCallback() {
    this.disconnectFromParent(this.guid);
}
 
 

将数据传递给子组件
一般组件注册已经完成,我们可以通过暴露的回调方法进行父子之间的数据通信
参考:

this.privateChildrenRecord[guid].callbacks.select();

父组件可以传递数据到子组件,如下

this.privateChildrenRecord[guid].callbacks.setAriaLabelledBy('my-custom-id');

子组件对应暴露的属性

@track ariaLabelledby;
setAriaLabelledBy(id) {
    this.ariaLabelledby = id;
}
 
 
  • 通过数据组合组件
    参考如下,一个通过数据驱动组合的组件
 
<template>
    <div class="example-parent">
        <template for:each={itemsData} for:item="itemData">
            <example-child
                onclick={onItemSelect}
                id={itemData.id}
                key={itemData.id}>
            </example-child>
         </template>
    </div>
</template>
 
 

传递的数据格式如下:

itemsData = [
    {
        label : 'custom label 1',
        id : 'custom-id-1'
        selected : false
    },
    {
        label : 'custom label 2',
        id : 'custom-id-2'
        selected : false
    }
]

参考资料

https://lwc.dev/guide/composition#pass-markup-into-slots

Lightning Web Components 组合(五)的更多相关文章

  1. Lightning Web Components html_templates(三)

    Lightning Web Components 强大之处在于模版系统,使用了虚拟dom 进行智能高效的组件渲染. 使用简单语法以声明方式将组件的模板绑定到组件的JavaScript类中的数据 数据绑 ...

  2. Lightning Web Components 开发指南(二)

    Lightning Web Components 是自定义元素使用html 以及现代javascript进行构建. Lightning Web Components UI 框架使用web compon ...

  3. Lightning Web Components 安装试用(一)

    Lightning Web Components 简称(lwc) 是一个快速企业级的web 组件化解决方案,同时官方文档很全,我们可以完整的 学习lwc 项目结构 使用npx 官方提供了一个creat ...

  4. Lightning Web Components 来自salesforce 的web 组件化解决方案

    Lightning Web Components 是一个轻量,快速,企业级别的web 组件化解决方案,官方网站也提供了很全的文档 对于我们学习使用还是很方便的,同时我们也可以方便的学习了解salesf ...

  5. lightning & web components & templates & slots

    lightning & web components & templates & slots Web components, Custom elements, Template ...

  6. Lightning Web Components 组件生命周期(六)

    组件创建以及渲染流程 组件移除dom 处理流程 组件从dom 移除 组件中的disconnectedCallback() 方法被调用 子组件从dom 移除 每个子组件的disconnectedCall ...

  7. Lightning Web Components 组件样式(四)

    要将样式与组件进行绑定,需要创建一个同名的样式文件,这样样式将会自动应用到组件 在组件中定义的样式的作用域是属于组件的,这样允许组件可以在不同的上下文中可以复用, 可以阻止其他组件的样式的复写 css ...

  8. Web API之Web Components

    本文参考<你的前端框架要被web组件替代了>. 于2011年面世的Web Components是一套功能组件,让开发者可以使用 HTML.CSS 和 JavaScript 创建可复用的组件 ...

  9. Web Components

    Web Components是不是Web的未来   今天 ,Web 组件已经从本质上改变了HTML.初次接触时,它看起来像一个全新的技术.Web组件最初的目的是使开发人员拥有扩展浏览器标签的能力,可以 ...

随机推荐

  1. delphi xe6 窗口 visible 不能隐藏 解决

    delphi xe6 窗口 visible 不能隐藏 解决 在工程代码里面加上 Application.ShowMainForm := false;

  2. Spring AOP 创建Advice 定义pointcut、advisor

    前面定义的advice都是直接植入到代理接口的执行之前和之后,或者在异常发生时,事实上,还可以对植入的时机定义的更细. Pointcut定义了advice的应用时机,在Spring中pointcutA ...

  3. String.Join函数

    string[] str1 = { "abc", "bcd", "cde", "efg" }; string str2 ...

  4. ubuntu16.04 打开chrome弹出“Enter password to unlock your login keyring”解决方法

    问题如图 输入开机密码发现验证失败. 解决 命令: find ~/ -name login.keyring 查找相关文件. 命令: sudo rm -rf /home/la/.local/share/ ...

  5. 2019-07-25 PDO

    PDO是什么? pdo是php数据对象,即php data object .使用pdo是为了让我们能够使用相同的代码连接不同的数据库.PDO扩展是以面向对象的方式来进行封装,也就是说,我们的PDO扩展 ...

  6. python 工厂方法

    工厂方法模式(FACTORY METHOD)是一种常用创建型设计模式,此模式的核心精神是封装类中变化的部分,提取其中个性化善变的部分为独立类, 通过依赖注入以达到解耦.复用和方便后期维护拓展的目的. ...

  7. Typora-yes:typora最舒适的使用-优化主题+图床服务+自动上传图片插件

    转载注明出处:https://www.cnblogs.com/nreg/p/11992678.html,谢谢 开源项目下载:https://github.com/nreg/typora-yes 云盘: ...

  8. 英语Affrike非洲Affrike单词

    中文名称阿非利加洲(全称) 外文名称Africa 别 名Affrike 行政区类别洲 下辖地区北非.东非.西非.中非.南非 地理位置东濒印度洋,西临大西洋,北至地中海,南至好望角 面 积3022万平方 ...

  9. Resource interpreted as Document but transferred with MIME type application/json

    转自:https://blog.csdn.net/just_lover/article/details/81207472 我在修改并保存后,界面返回提示“undifine”,实际我是看到有返回提示的. ...

  10. 介绍一种在ABAP内核态进行内表高效拷贝的方法,和对应的Java和JavaScript版本的伪实现

    内表操作是ABAP开发人员几乎在每个ABAP程序里都会遇到的. 看一个例子:有两个行结构不一样的内表,每个内表的行结构有三列,除了name这一列名字一致外,其他两列的名称都不同,下图用红色和蓝色标注出 ...