Web Component入门

本文作者为奇舞团前端开发工程师 田厚桔

引言

前端开发者,现在在进行项目的开发时,一般很少使用原生的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);
  }
}

这里我们需要编写一个calss,该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应该有了最基本的了解,下面就给大家简单总结一下使用它的优缺点。

优点

  1. 浏览器原生支持,不用加入任何依赖
  2. 多种场景适用,天生组件隔离

缺点

  1. 跟主流的框架相比,书写较为复杂,需要开发者自己进行原生dom操作
  2. 若要写成单文件组件,需要采用模板字符串的写法,没有语法高亮,代码提示等
© 版权声明
THE END
喜欢就支持一下吧
点赞5 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容