使用组合我们可以用来设计复杂的组件。
组合一些比较小的组件,可以增加组件的重新性以及可维护性。
通过以下一个简单的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. chrome Network 过滤和高级过滤

    转自:https://blog.csdn.net/tengdazhang770960436/article/details/90644523

  2. HTML5中的lang属性,zh-CN还是zh-Hans?

    一.资源 先提供资源.如果我弄错了什么,请以这些文档为准: W3C文档.IANA已登记的子标签.BCP 47.RFC 5646. 二.格式简介 先上一张图片: 一个Language Tags,由①到⑦ ...

  3. kafka学习笔记(一)——概述

    1.kafka是什么? 官方说明是: Kafka是一个分布式的基于发布/订阅模式的消息队列,主要应用于大数据实时处理领域. 提到了两个概念: 发布/订阅模式 消息队列 下边来理解一下这两个名词. 2. ...

  4. FORM表单 onclick()与onsubmit()

    FORM表单中onclick().submit()与onsubmit()的问题 最近遇到一次处理form数据的过滤,采用了button的onclick事件来检查,发现return false后表单仍然 ...

  5. dump net core lldb 安装

    原文https://www.cnblogs.com/calvinK/p/9263696.html centos7下安装lldb,dotnet netcore 进程生成转储文件,并使用lldb进行分析 ...

  6. ThreadLocal简解

    ThreadLocal特点 ThreadLocal实现了线程间数据隔离,ThreadLocal的实例代表了一个线程局部的变量,每条线程都只能看到自己的值,并不会意识到其它的线程中也存在该变量.简单来说 ...

  7. pandas-14 concatenate和combine_first的用法

    pandas-14 concatenate和combine_first的用法 concatenate主要作用是拼接series和dataframe的数据. combine_first可以做来填充数据. ...

  8. layui 框架 table插件 实现键盘快捷键 切换单元格编辑

    最近使用layui的框架时,发现table插件不支持键盘快捷键切换单元格,花了点时间实现此功能. 分享给有需要的朋友们~~~ 效果图 代码: 1.支持 enter,上,下,右键 切换单元格,支持隐藏列 ...

  9. window.requestAnimationFrame()的使用,处理更流畅的动画效果

    https://blog.csdn.net/w2765006513/article/details/53843169 window.requestAnimationFrame()的使用 2016年12 ...

  10. 红米手机使用应用沙盒一键修改sdk信息

    前面文章介绍了怎么在安卓手机上安装激活XPOSED框架,XPOSED框架的极强的功能各位都介绍过,能不修改APK的前提下,修改系统内核的参数,打个比方在某些应用情景,各位需要修改手机的某个系统参数,这 ...