查看原文
其他

【第2821期】Web Component入门

田厚桔 前端早读课 2022-12-26

前言

上周末不小心中招了,大家还是要好好戴好口罩。学点浏览器自带的。今日前端早读课文章由 @田厚桔分享,公号:奇舞精选授权。

正文从这开始~~

引言

前端开发者,现在在进行项目的开发时,一般很少使用原生的 js 代码,往往都会依靠 Vue,React 等框架进行开发,而不同的框架都有自己不同的开发规则,但是目前所使用的主流框架,都是遵循组件化开发的模式,即把不同功能的代码,拆分成不同的组件,以此来达到高内聚,低耦合,减少代码量等目的。目前主流的框架,均为是有公司或者公司开源。自己制定了一套完整的开发规范。谷歌在 2011 年的时候就已经提出了组件化开发的概念,即 Web Component ,这个方案现在是被纳入了 w3c 规范之中。

如何构建

构建一个 Web Component,我们需要按照以下三个步骤

1. 定义模板
<template>
<div>web component</div>
<button>按钮</button>
</template>

我们在 <template> 标签内部,编辑我们组件的结构样式,这里可以类比 vue 的模板写法。

2. 组件逻辑编写

class MyWebComponent extends HTMLElement {
constructor() {
super();
// 深度克隆一份template
const content = template.content.cloneNode(true);
// 将克隆的template添加到dom树上
this.attachShadow({ mode: "closed" }).appendChild(content);
}
}

这里我们需要编写一个 class,该 class 并且要继承于 HTMLElement,然后我们在该类的构造函数里面,将我们书写的组件添加到 dom 树上。这里我使用 attachShadow 方法,再把 content 节点添加到 dom,attachShadow 的作用就是创建 shadow dom,这也是 web component 中很重要的一个概念 —— 影子 dom,它和我们一般的 dom 有所不同,我们可以通过这个方法创造一个相对封闭且独立的 dom,这个方法他会接收一个对象,对象的 mode 键值如果为 closed,那么这个 dom 就为与外界隔离,该 dom 以外的脚本也无法对其进行操控,下面的图片,就向我们展示了什么是 shadow dom。

3. 组件注册

window.customElements.define("My-webComponent",MyWebComponent );

我们需要调用 customElements.define 方法,该方法接收两个参数,第一个参数是我们给组件自定义的标签名(这里我们需要注意一下,用 - 连接),第二个参数就是组件对应的 class。

案例演示,如何编写一个单文件组件

我们有了前面的基础知识,下面,我们就采用我们前面所介绍的知识,来编写一个独立的组件。这个组件的功能也非常简单,我们通过父组件传递给子组件初始数据,进行展示,也可以由子组件,点击添加,为列表添加数据。

既然是采用组件化的写法,我们肯定要想办法把组件抽离成一个单文件的形式,方便我们进行复用,但是由于 HTML imports 这个方案已经被废弃,我们无法在一个 html 文件里面直接引入另外一个 html 页面。所以,如果我们想要实现原生组件复用,就需要把代码写在一个 js 文件里面,引入该 js 文件,就等于引入了组件。

//index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
//引入编写好的组件,在这里引入文件,注意要添加defer关键字
<script src="./MyList/index.js" defer></script>
<body>
<div>
//使用组件
<my-list id="node">
<!--原生支持插槽 -->
<slot>web component</slot>
</my-list>
</div>
<script>
//因为是原生,所以我们需要获取dom节点行后续操作
const node = document.getElementById("node");
//我们将变量转换一下格式,就能传递给子组件
node.dataset.arr = JSON.stringify(["吃饭", "睡觉"]);
</script>
</body>
</html>
//index.js
const template = document.createElement("template");
//在js文件中,我们想要书写html和css就必须要借助innerHTML,在其内部书写我们的样式和结构
template.innerHTML = `
<style>
#contain {
display: flex;
flex-direction: column
}
input {
width: 200px
}
</style>
<div id="contain">
<span><slot></slot></span>
<div>
<input type="text" id=input>
<button id="mybutton" data-text1="111111">添加</button>
</div>
</div>
`
;
class MyList extends HTMLElement {
constructor() {
//因为我们的组件继承于HTMLElement,所以需要调用super关键字
super();
// 获取标签
const content = template.content.cloneNode(true);
const mybutton = content.getElementById("mybutton");
const input = content.getElementById("input");
const contain = content.getElementById("contain");

// 获取props
const arr = JSON.parse(this.dataset.arr);
//进行事件的监听
mybutton.addEventListener("click", () => {
arr.push(input.value)
const li = document.createElement("li");
li.innerText = input.value;
contain.appendChild(li);
});
// 将数据渲染到页面
arr.forEach((item) => {
const li = document.createElement("li");
li.innerText = item;
contain.appendChild(li);
});
//初始化一个影子dom
this.attachShadow({ mode: "closed" }).appendChild(content);
}
}
// 注册组件
window.customElements.define("my-list", MyList);

框架

通过前面,我们就可以感受到,编写一个 Web Component 组件,似乎并不是十分的方便,所以我要向大家推荐一个框架 stencil.js, 通过它,我们就能使用 jsx 的语法,更加高效快速的来编写出一个 Web Component 组件。从而避免使用原始的 js。

优缺点

通过前面的介绍,我想大家对 Web Components 应该有了最基本的了解,下面就给大家简单总结一下使用它的优缺点。

优点
  • 浏览器原生支持,不用加入任何依赖

  • 多种场景适用,天生组件隔离

缺点
  • 跟主流的框架相比,书写较为复杂,需要开发者自己进行原生 dom 操作

  • 若要写成单文件组件,需要采用模板字符串的写法,没有语法高亮,代码提示等

关于本文
作者:@田厚桔
原文:https://mp.weixin.qq.com/s/uELw1_5oDvxCqYI-ygDOdw

关于【Web Component】相关推荐,欢迎读者自荐投稿,前端早读课等你来。+v:zhgb_f2er

【第2517期】2021 Web Components技术趋势解读

【第2769期】重磅!哈啰 Quark Design 正式开源,新一代跨技术栈前端组件库

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存