乐趣区

关于前端:如何编写一个原生-Web-Components-组件

在明天的前端编程中,利用语义化的 HTML 联合 CSS 来完一个组件并不是一件难事,这也意味着无论在 ReactVue 中都能够插入,不过它俩不是明天的配角,接下来我将用一个例子来介绍如何封装一个残缺的原生 HTMLWeb Components 组件,让咱们开始吧!

HTML 构造

首先咱们来理解下 HTML 中的 <details> 元素,它能够用于创立一个小部件,其中蕴含仅在小部件处于“关上”状态时才可见的附加信息,<details>元素内能够蕴含的内容没有任何限度。

默认状况下,元素创立的小部件 <details> 处于“敞开”状态(open标签可使其关上)。通过单击小部件在“关上”和“敞开”状态之间切换,以显示或暗藏标签中蕴含的附加信息,外部标签 <summary> 元素则可为该部件提供概要。

一个简略的例子如下:

<details>
    <summary> 不能说的机密 </summary>
    藏的这么深,可还是被你发现了
</details>
details {
    border: 1px solid #aaa;
    border-radius: 4px;
    padding: .5em .5em 0;
}

summary {
    font-weight: bold;
    margin: -.5em -.5em 0;
    padding: .5em;
}

details[open] {padding: .5em;}

details[open] summary {
    border-bottom: 1px solid #aaa;
    margin-bottom: .5em;
}

应用语义化 HTML 的长处:页面内容构造更清晰,不便开发者浏览,更利于浏览器的了解与加载,搜索引擎解析与 SEO 优化。

增加亿点款式

原生元素默认的款式很简陋,因而咱们须要为其定制一下款式,这块内容咱们简略带过,只解说要害局部,款式内容有省略,具体能够在文末的 码上掘金 中看到出现成果。

.ContentWarning > summary {
  position: relative;
  list-style: none; /** 去除默认款式 **/
  user-select: none; 
  cursor: pointer;
  /** 为其增加一个斜线背景 **/
  --stripe-color: rgb(0 0 0 / 0.1);
  background-image: repeating-linear-gradient(45deg,
      transparent,
      transparent 0.5em,
      var(--stripe-color) 0.5em,
      var(--stripe-color) 1em);
}

/** 通过 var 变量调整悬停时的色彩款式 **/
.ContentWarning>summary: hover,
.ContentWarning>summary: focus {--stripe-color: rgb(150 0 0 / 0.1);
}

封装模板

当初咱们来把它封装成一个残缺的组件,这须要先将 HTML 编写在模板 template 当中,并设置一个 id,如下所示:

<template id="warning-card">  
  <details class="ContentWarning">
    <summary>
      <strong>⚠️ 留神:</strong> 以下为暗藏内容
    </summary>
    <slot name="desc"> 藏的这么深,可还是被你发现了 </slot>
  </details>
</template>

相熟 Vue 的小伙伴应该很容易了解下面的代码,构造很类似,不过网页不会间接渲染它包裹的内容。此外咱们还对此模板设置了一个插槽 slot,前面会讲到它的作用。

定义组件

有了下面封装好的模板,咱们就须要在 JS 中定义成可用组件来让其可能被应用,调用 window 下的 customElements.define 办法,第一个参数是传入组件名称,咱们定义组件名为: warning-card,第二个参数传入一个继承了 HTMLElement 的类,在其构造方法当中获取并克隆一个新的 HTML 节点,它会通过 appendChild 渲染到页面当中。

window.customElements.define('warning-card',
  class extends HTMLElement {constructor() {super();
      var templateElem = document.getElementById('warning-card');
      var content = templateElem.content.cloneNode(true);
      this.appendChild(content);
    }
  })

接着咱们就能够在页面中把它当作组件那样应用了:

<warning-card> </warning-card>

插槽与传参

回头看看下面咱们模板中设置的插槽 slot,此时还是没有失效的,咱们须要略微改写一下构造函数中的渲染形式,将 web 组件定义为一个 Shadow DOM,这样结构的是一个能够将标记构造、款式和行为暗藏起来,并与页面上的其余代码相隔离,保障不同的局部不会混在一起的独立元素,并在最初应用 Node.cloneNode() 办法增加了模板的拷贝到 Shadow 的根结点上。

window.customElements.define('warning-card',
  class extends HTMLElement {constructor() {super();
      var template = document.getElementById('warning-card').content;
      this.attachShadow({mode: 'open'}).appendChild(template.cloneNode(true));
    }
  })

当初咱们尝试应用下组件,往其内容增加一个图片,指向名为 descslot 插槽中:

<warning-card>
  <img slot="desc" src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ba825ffee78c4a1b9c0232e5d2f1d048~tplv-k3u1fbpfcp-watermark.image?" />
</warning-card>

这时你会发现,图片插入到 details 元素的暗藏区域当中了,slot 曾经胜利失效,然而款式却隐没了,这时因为组件曾经被 齐全隔离 ,咱们须要将款式作用在其 外部 才会失效。

<template id="warning-card">
  <style>
    <!-- TODO: 组件的款式 -->
  </style>
  
  <details class="ContentWarning">
    <summary>
      <strong>⚠️ 留神:</strong>
    </summary>
    <slot name="desc">THE DESCRIPTION</slot>
  </details>
</template>

这样组件就失常了:

除了定制模板中的插槽,咱们也能够通过 HTML 标签属性来实现一些简略的传参,例如在 summary 标签中显示一个题目:

<warning-card title="后方高能">
</warning-card>

咱们只须要在模板中定义好这个题目的地位:

<template id="warning-card">
  <details class="ContentWarning">
    <summary>
        <!-- TODO: 模板中退出一个 span 标签 -->
      <strong>⚠️ 留神:</strong> <span id="title"></span>
    </summary>
  </details>
</template>

最初在构造函数中咱们通过 document 的原生办法写入模板中就能够了:

window.customElements.define('warning-card',
  class extends HTMLElement {constructor() {super();
      var template = document.getElementById('warning-card').content;
      // TODO: 找到 title 标签,写入传入组件的 title 属性值
      template.querySelector('#title').innerText = this.getAttribute('title');
      this.attachShadow({mode: 'open'}).appendChild(template.cloneNode(true));
    }
  })

完结

至此,咱们通过一个简略的原生组件学习了如何编写 Web Components,能够在此代码片段中查看具体源码。

以上就是文章的全部内容,心愿对你有所帮忙!如果感觉文章写的不错,能够点赞珍藏,也欢送关注,我会继续更新更多前端有用的常识与实用技巧,我是茶无味 de 一天,心愿与你独特成长~

退出移动版