组件是前端的发展方向,如今流行的 React angular2.0 Vue 都是组件框架。javascript
谷歌公司因为掌握了 Chrome 浏览器,一直在推进浏览器的原生组件,即Web Components 。相比第三方框架,原生组件简单直接,符合直觉,不用加载任何外部模块,代码量小。目前,它还在不断发展,但已经可用于生产环境。css
Web Components 标准很是重要的一个特性是,它使开发者可以将HTML页面的功能封装为 custom elements(自定义标签)。html
首先咱们须要知道,Web Components 包括了四个部分:
• Custom Elements
• HTML Imports
• HTML Templates
• Shadow DOM
这四部分有机地组合在一块儿,才是 Web Components。
能够用自定义的标签来引入组件是前端组件化的基础,在页面引用 HTML 文件和 HTML 模板是用于支撑编写组件视图和组件资源管理,而 Shadow DOM 则是隔离组件间代码的冲突和影响。前端
概述
Custom Elements 顾名思义,是提供一种方式让开发者能够自定义 HTML 元素,包括特定的组成,样式和行为。支持 Web Components 标准的浏览器会提供一系列 API 给开发者用于建立自定义的元素,或者扩展示有元素。
https://developer.mozilla.org...java
概述
HTML Imports 是一种在 HTMLs 中引用以及复用其余的 HTML 文档的方式。
咱们最多见的引入一个 css 文件的方式是:
<link rel="stylesheet" href="/css/master.css">
Web Components 如今提供多了一个这个:
<link rel="import" href="/components/header.html">
须要服务器环境,能够用nodejs搭一个node
https://segmentfault.com/a/11...web
概述
这个东西很简单,用过 handlebars 的人都知道有这么一个东西:segmentfault
其余模板引擎也有相似的东西,那么 HTML Templates 即是把这个东西官方标准化,提供了一个 template 标签来存放之后须要可是暂时不渲染的 HTML 代码。
之后能够这么写了:浏览器
Shadow DOM 好像提出很久了,最本质的需求是须要一个隔离组件代码做用域的东西,例如我组件代码的 CSS 不能影响其余组件之类的。服务器
ShadowDOM-ShadowRoot
ShadowDOM主要解决一个文档中可能须要大量交互的多个DOM树创建和维护各自功能边界的问题
HTML支持的其余一些好比视频、音频甚至一些表单的控件,这些控件有些是由很复杂的界面组成的,其实这些界面也是用HTML+CSS写的
例如<video>
https://www.bilibili.com/vide...
f12后只能看到一个video的标签,但实际它还有个隐藏的shadowDom
咱们把浏览器里的settings-Elements-show user agent shadow Dom 勾选上之后就能看到shadowDom
CSS 相关
由于 Shadow DOM 很大程度上是为了隔离样式做用域而诞生的,主文档中的样式规则不对 Shadow DOM 里的子文档生效,子文档中的样式规则也不影响外部文档。
自定义元素能够给它指定全局样式
可是,组件的样式应该与代码封装在一块儿,只对自定义元素生效,不影响外部的全局样式。因此,能够把样式写在<template>里面。
一个小例子:把card封装成<user-card>标签
效果以下:
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...