使用组合我们可以用来设计复杂的组件。
组合一些比较小的组件,可以增加组件的重新性以及可维护性。
通过以下一个简单的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. MSSQLSERVER 服务运行内存设置较小导致启动服务失败

    问题产生原因: 手动设置MSSQLSERVER 运行内存,设置值未达到MSSQLSERVER 服务运行内存最低值(max server memory 所允许的最小内存量是 128 MB.),导致MSS ...

  2. 【题解】Luogu P5339 [TJOI2019]唱、跳、rap和篮球

    原题传送门 这题zsy写的是\(O(n^2)\),还有NTT\(O(n^2\log n)\)的做法.我的是暴力,\(O(\frac{a b n}{4})\),足够通过 考虑设\(f(i)\)表示序列中 ...

  3. (转).Net Core控制台生成exe能独立运行

    原文介绍了两种方式,方式一经测试可用(生成exe在开发机器上可运行),但是因为服务器是windows server2012 r2,没有安装补丁,造成了困难,尚未在服务器上运行成功. (提示 api-m ...

  4. 以yarn-client方式提交spark任务,任务一直卡在ACCEPTED状态

    问题背景 spark是以客户端的方式安装的,并没有启动spark的mesos集群,这时候的spark就相当与hive客户端. 以local模型和yarn-cluster方式提交任务,都能正确额执行,但 ...

  5. Fiddler-修改请求的上行参数

    方法一:对所有的请求打断点 1.rules->automatic Breakpoints->Befor Requests 2.点击选择需要修改的请求 3.选择右侧请求区域的 Inspect ...

  6. Mysql中类似于oracle中nvl()函数的ifnull()函数

    IFNULL(expr1,expr2)  如果expr1不是NULL,IFNULL()返回expr1,否则它返回expr2.IFNULL()返回一个数字或字符串值,取决于它被使用的上下文环境.  my ...

  7. maven设定项目编码

    今天在DOS下执行mvn compile命令时报错说缺少必要符号,事实上根本就没有缺少,但何以如此呢,为啥eclipse在编译时就没有这问题呢? 原因是编码的问题造成的! eclipse在编译的使用使 ...

  8. 如何免费试用SAP的Fiori应用

    什么是SAP Fiori?SAP Fiori不是SAP发布的某款产品,而是SAP新一代UI设计风格和用户体验的代号. Fiori是一个意大利语中的单词,意思是"花": 不得不说SA ...

  9. Windows Server 2008 R2 + IIS 环境部署Asp.Net Core App

    Windows + IIS 环境部署Asp.Net Core App   环境:Windows Server 2012, IIS 8, Asp.Net Core 1.1. 不少人第一次在IIS中部署A ...

  10. 复盘一篇浅谈KNN的文章

    认识-什么是KNN KNN 即 K-nearest neighbors, 是一个hello world级别, 但被广泛使用的机器学习算法, 中文叫K近邻算法, 是一种基本的分类和回归方法. KNN既可 ...