使用组合我们可以用来设计复杂的组件。
组合一些比较小的组件,可以增加组件的重新性以及可维护性。
通过以下一个简单的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. MySQL学习一:建表

    目标:创建三张表,学生表student(sid,name,gender), 课程表course(cid,name), 分数mark(mid, sid, cid, gender); 要求sid, cid ...

  2. 【题解】Luogu P5341 [TJOI2019]甲苯先生和大中锋的字符串

    原题传送门 实际按照题意模拟就行 我们先求出字符串的sa 因为要在字符串中出现k次,所以我们枚举\(l,r(r-l+1=k)\)看一共有多少种合法的方案 合法方案的长度下界\(lb\)为\(Max(h ...

  3. 如何配置这个maven仓库的源http://mvnrepository.com/repos

    http://mvnrepository.com/repos 主要是ID .mirrorof.name 怎么配置,这个网站上有spring5.0的,别的仓库没有,我需要这个源. 原文地址:https: ...

  4. mysql修改后启动my.cnf报错Starting MySQL... ERROR! The server quit without updating PID file (/var/lib/mysql/localhost.localdomain.pid).

    mysql中文乱码解决 mysql修改my.cnf后启动报错Starting MySQL... ERROR! The server quit without updating PID file (/v ...

  5. 【代码优化】C#遍历所有控件(Control方法)

    直接上代码: /// <summary> /// 判断价格是否可以购买技能的方法 /// </summary> /// <param name="btnBuyA ...

  6. c#利用定时器自动备份数据库(mysql)

    1:引用dll MySql.Data.dll,   MySqlbackup.dll 2:建一个数据连接静态类 public static class mysql{public static strin ...

  7. 在Centos中安装.net core SDK

    在Linux中运行.net core 项目必须要有.net core SDK 环境.之前配置过几次,但由于没有做总结.过了几天又配置的时候 感觉特别陌生,今天就记录一次.net core SDK 的安 ...

  8. C#设计模式之11:命令模式

    C#设计模式之11:命令模式 命令模式 命令模式用来解决一些复杂业务逻辑的时候会很有用,比如,你的一个方法中到处充斥着if else 这种结构的时候,用命令模式来解决这种问题就会让事情变得简单很多. ...

  9. P1108 低价购买 (DP)

    题目 P1108 低价购买 解析 这题做的我身心俱惫,差点自闭. 当我WA了N发后,终于明白了这句话的意思 当二种方案"看起来一样"时(就是说它们构成的价格队列一样的时候),这2种 ...

  10. Java之路---Day07

    2019-10-21-23:30:24 ArrayList类[集合] What:java.util.ArrayList是大小可变的数组的实现,存储在内的数据称为元元素,此类提供一些方法来操作内部存储的 ...