一定要了解的前端趋势之Web Component

Web Components

概念(来自 MDN )
  • 作为开发者,我们都知道尽可能多的重用代码是一个好主意。这对于自定义标记结构来说通常不是那么容易 — 想想复杂的 HTML(以及相关的样式和脚本),有时你不得不写代码来呈现自定义 UI 控件,并且如果你不小心的话,多次使用它们会使你的页面变得一团糟。

  • Web Components 旨在解决这些问题 — 它由三项主要技术组成,它们可以一起使用来创建封装功能的定制元素,可以在你喜欢的任何地方重用,不必担心代码冲突。

    • Custom element(自定义元素):一组 JavaScript API,允许你定义 custom elements 及其行为,然后可以在你的用户界面中按照需要使用它们。
    • Shadow DOM(影子 DOM):一组 JavaScript API,用于将封装的“影子”DOM 树附加到元素(与主文档 DOM 分开呈现)并控制其关联的功能。通过这种方式,你可以保持元素的功能私有,这样它们就可以被脚本化和样式化,而不用担心与文档的其他部分发生冲突。
    • HTML template(HTML 模板): <template><slot> 元素使你可以编写不在呈现页面中显示的标记模板。然后它们可以作为自定义元素结构的基础被多次重用。
如何使用
  1. 首先需要准备一个 .html 文件和一个 .js 文件,然后通过<script></script>标签引入 js 文件。
  • HTML 文件
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <title>Document</title>
    <style>
      body {
        font-family: "STSong";
      }
      html {
        --theme-color: orange;
      }
      h1 {
        color: orange;
      }
      /* 
        注意:
        1.自定义组件默认和span一样,所以需要设置 display:block
        2.在外面只能修改自定义组件本身的样式,不能渗透到组件内部
      */
      lf-card {
        display: block;
        margin: 15px;
        margin-bottom: 0;
        box-shadow: 0px 0px 10px orange;
      }
    </style>
  </head>

  <body>
    <lf-card
      data-name="Stephen"
      data-position="后端开发工程师"
      data-email="stephen@example.com"
    ></lf-card>

    <lf-card
      james
      data-name="James"
      data-position="前端开发工程师"
      data-email="james@example.com"
    ></lf-card>

    <script src="main.js"></script>
  </body>
</html>

在上面的代码中,我们首先定义了一个自定义元素 lf-card,然后使用 data-* 属性来传递数据给自定义元素。

  • JS 文件
class LfCard extends HTMLElement {
  // 返回需要监听变化的属性
  static get observedAttributes() {
    return ["data-name", "data-position"];
  }

  constructor() {
    super();

    /* 
    附加 shadowRoot

    shadowRoot的作用:将组件的样式与页面样式隔离开

    如果需要通过JS的 querySelector去查找元素,则需要通过 
    document.querySelector('自定义组件名').shadowRoot.querySelector('目标元素')
    */
    this.attachShadow({ mode: "open" });
  }
  /*
    生命周期

    connectedCallback:当自定义元素第一次被连接到文档 DOM 时被调用。
    disconnectedCallback:当自定义元素与文档 DOM 断开连接时被调用。
    adoptedCallback:当自定义元素被移动到新文档时被调用。
    attributeChangedCallback:当自定义元素的一个属性被增加、移除或更改时被调用。
   */

  connectedCallback() {
    this.render();
  }

  attributeChangedCallback(attr, oldVal, newVal) {
    console.log(attr, oldVal, newVal);
    if (oldVal) {
      this.shadowRoot.querySelector(".name").textContent = newVal;
    }
  }

  changeTransparent(n) {
    this.setAttribute("data-name", "张三丰");
    setTimeout(() => {
      n.classList.add("transparent");
    }, 1000);
  }

  render() {
    // console.log(this.dataset); // 获取动态属性传过来的参数
    let uName = this.dataset.name;
    let uPosition = this.dataset.position;
    let uEmail = this.dataset.email;

    this.template = document.createElement("template");
    this.template.innerHTML = `
     <div class="business-card">
       <div class="card-front">
         <h1 class="name">${uName}</h1>
         <h2>${uPosition}</h2>
         <p class="company-name">创新科技未来有限公司</p>
         <p>固定电话: 010-88** **88</p>
         <p>Email: ${uEmail}</p>
         <p>地址: 北京市梦幻城区银河东路99号</p>
        
       </div>
     </div>
     `;
    this.styles = document.createElement("style");
    this.styles.innerHTML = `
      /*  
      :host 代表的是标签本身,它的权重比外面的标签低,所以会被覆盖
      */

       :host{
         dissplay: block;
         box-shadow: 0px 0px 10px deeppink;
       }
       :host([james]){
         border-radius: 10px; 
       }
       :host(:not([james])){
         border: 5px solid orange;
       }

       /* 
        有些属性,默认是可以从外面页面继承的(如:font-family)
        如果不想继承所有属性,可以设置all: initial
       */
       :host{
         all: initial;
       }
      .business-card {
       box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1), 0 1px 3px rgba(0, 0, 0, 0.06);
       transition: transform 0.5s;
      }
      .business-card:hover {
        transform: translateY(-3px) scale(1.01); 
      }
      .card-front,.card-back {
       padding: 15px; 
       box-sizing: border-box;
      }
   
      h1 {
       margin: 0;
       font-size: 24px; 
       /* 也可以支持自定义属性  */
       color: var(--theme-color,#333);
       text-shadow: none; 
      }
      .last-name{  display: none; }
   
      h2 {
       margin: 0;
       font-weight: 300;
       color: #666;
       margin-bottom: 10px;
       font-size: 12px; 
    }
    .company-name{ 
      font-size: 18px;
      color: #333;
      margin-bottom: 15px; 
    }
    p {
       line-height: 1.4;
       margin: 2px 0; 
       color: #666;
       font-size: 14px; 
    }
   .transparent{  opacity: .4; }
   
   `;

    this.shadowRoot.appendChild(this.template.content);
    this.shadowRoot.appendChild(this.styles);

    this.shadowRoot.querySelector(".name").addEventListener("click", (e) => {
      console.log(this, e.target);
      this.changeTransparent(e.target);
    });
  }
}

customElements.define("lf-card", LfCard);
结语
  • Web Components 不仅仅是一项技术,它代表了网页开发的一种未来趋势——组件化、模块化。掌握它,就如同拥有了一个强大的工具箱,无论是在快速原型设计、提高代码复用性,还是在维护大型项目方面,都能让你如虎添翼。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值