1

web components

组件是前端的发展方向,现在流行的 React angular2.0 Vue 都是组件框架。

谷歌公司由于掌握了 Chrome 浏览器,一直在推动浏览器的原生组件,即Web Components 。相比第三方框架,原生组件简单直接,符合直觉,不用加载任何外部模块,代码量小。目前,它还在不断发展,但已经可用于生产环境。

Web Components 标准非常重要的一个特性是,它使开发者能够将HTML页面的功能封装为 custom elements(自定义标签)。

首先我们需要知道,Web Components 包括了四个部分:
• Custom Elements
• HTML Imports
• HTML Templates
• Shadow DOM
这四部分有机地组合在一起,才是 Web Components。
可以用自定义的标签来引入组件是前端组件化的基础,在页面引用 HTML 文件和 HTML 模板是用于支撑编写组件视图和组件资源管理,而 Shadow DOM 则是隔离组件间代码的冲突和影响。

Custom Elements

概述
Custom Elements 顾名思义,是提供一种方式让开发者可以自定义 HTML 元素,包括特定的组成,样式和行为。支持 Web Components 标准的浏览器会提供一系列 API 给开发者用于创建自定义的元素,或者扩展现有元素。
https://developer.mozilla.org...

HTML Imports

概述
HTML Imports 是一种在 HTMLs 中引用以及复用其他的 HTML 文档的方式。
我们最常见的引入一个 css 文件的方式是:
<link rel="stylesheet" href="/css/master.css">
Web Components 现在提供多了一个这个:
<link rel="import" href="/components/header.html">
需要服务器环境,可以用nodejs搭一个

https://segmentfault.com/a/11...

HTML Templates

概述
这个东西很简单,用过 handlebars 的人都知道有这么一个东西:

  1. <script id="template" type="text/x-handlebars-template">
  2. ...
  3. </script>

其他模板引擎也有类似的东西,那么 HTML Templates 便是把这个东西官方标准化,提供了一个 template 标签来存放以后需要但是暂时不渲染的 HTML 代码。
以后可以这么写了:

  1. <template id="template"> ...
  2. </template>
Shadow DOM

Shadow DOM 好像提出好久了,最本质的需求是需要一个隔离组件代码作用域的东西,例如我组件代码的 CSS 不能影响其他组件之类的。

ShadowDOM-ShadowRoot
ShadowDOM主要解决一个文档中可能需要大量交互的多个DOM树建立和维护各自功能边界的问题

HTML支持的其他一些比如视频、音频甚至一些表单的控件,这些控件有些是由很复杂的界面组成的,其实这些界面也是用HTML+CSS写的
例如<video>
https://www.bilibili.com/vide...
1111111111111.PNG
f12后只能看到一个video的标签,但实际它还有个隐藏的shadowDom
我们把浏览器里的settings-Elements-show user agent shadow Dom 勾选上以后就能看到shadowDom
22222222.PNG
33333333333.PNG
444444444444.PNG

CSS 相关
因为 Shadow DOM 很大程度上是为了隔离样式作用域而诞生的,主文档中的样式规则不对 Shadow DOM 里的子文档生效,子文档中的样式规则也不影响外部文档。

自定义元素可以给它指定全局样式
但是,组件的样式应该与代码封装在一起,只对自定义元素生效,不影响外部的全局样式。所以,可以把样式写在<template>里面。

一个小例子:把card封装成<user-card>标签
效果如下:
555.PNG
card.html

<!DOCTYPE  html\>

<html\>

<head\>

<meta  charset\="utf-8"  />

<meta  name\="viewport"  content\="width=device-width"  />

<title\>web Components</title\>

<link  rel\="stylesheet"  type\="text/css"  href\="a.css"  />

</head\>

<body\>

<user-card

image\="https://s0.2mdn.net/simgad/320245132277053394?sqp=-oaymwEOCKwCEPoBIAFIZFABWAE&rs=AOga4qmxkPL\_xXMXJ0ZrdWUAw31Jff3bmw"

name\="User Name"

email\="yourmail@some-email.com"

\>

</user-card\>

<user-card

image\="component.PNG"

name\="小明"

email\="yourmail@some-email.com"

\>

<span  slot\="my-text"\>slot!</span\>

</user-card\>

  

<template  id\="userCardTemplate"\>

<style\>

:host {

display: flex;

align-items: center;

width: 450px;

height: 180px;

background-color: #d4d4d4;

border: 1px  solid  #d5d5d5;

box-shadow: 1px  1px  5px  rgba(0, 0, 0, 0.1);

border-radius: 3px;

overflow: hidden;

padding: 10px;

box-sizing: border-box;

font-family: "Poppins", sans-serif;

margin-bottom: 10px;

}

.image {

flex: 0  0  auto;

width: 160px;

height: 160px;

vertical-align: middle;

border-radius: 5px;

}

.container {

box-sizing: border-box;

padding: 20px;

height: 160px;

}

.container > .name {

font-size: 20px;

font-weight: 600;

line-height: 1;

margin: 0;

margin-bottom: 5px;

}

.container > .email {

font-size: 12px;

opacity: 0.75;

line-height: 1;

margin: 0;

margin-bottom: 15px;

}

.container > .button {

padding: 10px  25px;

font-size: 12px;

border-radius: 5px;

text-transform: uppercase;

}

</style\>

  

<img  class\="image"  />

<div  class\="container"\>

<p  class\="name"\></p\>

<p  class\="email"\></p\>

<button  class\="button"\>Follow John</button\>

</div\>

<div\><slot  name\="my-text"\></slot\></div\>

</template\>

</body\>

<script  type\="text/javascript"  src\="./card.js"\></script\>

</html\>

card.js

class  UserCard  extends  HTMLElement {

constructor() {

super();

var  shadow  \=  this.attachShadow({ mode:  "open" });

  

var  templateElem  \=  document.getElementById("userCardTemplate");

var  content  \=  templateElem.content.cloneNode(true);

content

.querySelector("img")

.setAttribute("src", this.getAttribute("image"));

content.querySelector(".container>.name").innerText  \=  this.getAttribute(

"name"

);

content.querySelector(".container>.email").innerText  \=  this.getAttribute(

"email"

);

  

shadow.appendChild(content);

console.log(this.shadowRoot);

}

}

window.customElements.define("user-card", UserCard);

参考文章:http://www.ruanyifeng.com/blo...
参考文章:
https://juejin.im/post/57c40f...


lizehua
7 声望0 粉丝