前端JavaScript中常见设计模式

Web组件化实践:从概念到实现
本文介绍了WebComponents技术,包括自定义元素、ShadowDOM和HTML模板。通过示例展示了如何创建和使用原生组件,以及如何通过附着ShadowDOM和使用HTML模板来定制样式和结构。最后,通过一个Button组件的实现,详细阐述了Web组件的完整流程,并提供了实际代码示例。

1、为啥会有这一篇 ?

前两天有个同学问我,然后组内同学也即将分享相关实践内容,此处 在他之前发出(早一天发布的发布会),good!

2、是何物?

组件化是前端非常重要的一块内容,现在流行的 React 和 Vue 都是组件框架。

谷歌 Chrome 一直在推动浏览器的原生组件,即 Web Components API。相比第三方框架,原生组件简单直接,不用加载任何外部模块,代码量小。当前发展较为成熟,在很多项目中被使用

广受好评!

3、基本概念早知道

Web Components主要由三项技术组成,分别为

  • Custom elements(自定义元素)

  • Shadow DOM(影子DOM)

  • HTML templates(HTML模板)

  • 自定义元素实例

customElements.define(
'test-custom', // name 
class TestCustom extends HTMLParagraphElement { // 这个类定义功能constructor() {super();// 功能代码...}
}, { extends: 'p' }); // 继承自哪个元素 此处 p 
  • 影子 DOM

Shadow DOM 可将隐藏的 DOM挂到一个元素上:且 shadow root 节点为起始根节点,在这个根节点的下方,可以是任意元素,和普通的 DOM 元素一样

  • 如下图
  • 想将一个 Shadow DOM 附加到 custom element 怎么做?
class Button extends HTMLElement {constructor() {super();let shadow = this.attachShadow({mode: 'open'}); // 挂到 构造函数上}
} 
  • 操作一下 也是 ok 的
class Button extends HTMLElement {constructor() {super();let shadow = this.attachShadow({mode: 'open'});let p = document.createElement('p');shadow.appendChild(p);}
} 
  • 我想添加样式 怎么办 ?
let mySelfStyle = document.createElement('style');

mySelfStyle.textContent = `.btn-container {position: relative;}.btn {// ...}
`

shadow.appendChild(mySelfStyle); 
  • good !* HTML模版* 类似于 html 结构 和 vue slot```

```

4、磨拳擦掌,怎么使用 ?

1.创建一个类或函数来指定 web 组件的功能,如果使用类,请使用 ECMAScript 2015 的类语法 (参阅获取更多信息)。
2.使用 CustomElementRegistry.define() 方法注册您的新自定义元素,并向其传递要定义的元素名称、指定元素功能的类、以及可选的其所继承自的元素。
3.如果需要的话,使用Element.attachShadow() 方法将一个 shadow DOM 附加到自定义元素上。使用通常的 DOM 方法向 shadow DOM 中添加子元素、事件监听器等等。
4.如果需要的话,使用 <template><slot> 定义一个 HTML 模板。再次使用常规 DOM 方法克隆模板并将其附加到您的 shadow DOM 中。
5.在页面任何位置使用自定义元素,就像使用HTML DIV一样(为例)

5、实现一个 Button

  • 上面那段话 请忘掉!!! , 我们 写给 Button 试试

1、创建一个类来指定 web 组件的功能

customElements.define('mark-button', Button); 

2、使用Element.attachShadow() 方法将一个 shadow DOM 附加到自定义元素上

 const shadowRoot = this.attachShadow({ mode: 'open' });const btn = document.createlement('button');btn.appendChild(templateContent.cloneNode(true));btn.setAttribute('class', 'mark-button'); 

3、使用 <template><slot> 定义一个 HTML 模板

<template id="btn_tpl"><slot name="btn-content">button contentxxx</slot>
</template> 

4、使用

<mark-button type="primary"><span slot="btn-content" id="btn_show">button test1</span></mark-button>
<mark-button type="warning"><span slot="btn-content">button test2</span></mark-button>
<mark-button type="default"><span slot="btn-content">button test3</span></mark-button> 

5、添加点击事件

document.querySelector('#btn_show').addEventListener('click', () => {modal.setAttribute('visible', 'true');
}, false) 

6、效果

  • 完整代码
// index.html

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Web Component</title></head><body style="padding: 60px"><h1>Web Component 马克付</h1><h2>1. Button</h2><mark-button type="primary"><span slot="btn-content" id="btn_primary">button test1</span></mark-button><mark-button type="warning"><span slot="btn-content" id="btn_danger">button test2</span></mark-button><mark-button type="default"><span slot="btn-content">button test3</span></mark-button><!-- template定义区 --><template id="btn_tpl"><slot name="btn-content">button content xxx</slot></template><script src="components/button.js"></script><script> document.querySelector('#btn_primary').addEventListener('click',() => {alert('我是 btn_primary ,我被点击了')},false)document.querySelector('#btn_danger').addEventListener('click',() => {alert('我是 btn_danger 我很危险')},false) </script></body>
</html> 
// Button.js
class Button extends HTMLElement {constructor() {super();// 获取模板内容let template = document.getElementById('btn_tpl');let templateContent = template.content;const shadowRoot = this.attachShadow({ mode: 'open' });const btn = document.createElement('button');btn.appendChild(templateContent.cloneNode(true));btn.setAttribute('class', 'mark-button');// 定义类型primary | warning | defaultconst type = {'primary': '#06c','warning': 'red','default': '#f0f0f0'}const btnType = this.getAttribute('type') || 'default';const btnColor = btnType === 'default' ? 'pink' : '#fff';// 创建样式const style = document.createElement('style');// 为shadow Dom添加样式style.textContent = `.mark-button {position: relative;display: inline-block;padding:8px 20px;border-radius: 50px;margin-right: 3px;background-color: ${type[btnType]};color: ${btnColor};box-shadow: inset 0 5px 10px rgba(0,0,0, .3);cursor: pointer;}`shadowRoot.appendChild(style);shadowRoot.appendChild(btn);}
}
customElements.define('mark-button', Button); 

最后

最近还整理一份JavaScript与ES的笔记,一共25个重要的知识点,对每个知识点都进行了讲解和分析。能帮你快速掌握JavaScript与ES的相关知识,提升工作效率。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值