일.What?
Web Components are a new browser feature that provides a standard component model for the Web, consisting of several pieces: Shadow DOM, Custom Elements, HTML Imports and HTML Templates.
(w3c/webcomponents 에서 발췌)
즉, Web Components 는 Web 컴포넌트 모델 표준으로, 브라우저가 네이티브 특성 지원을 제공하며, Shadow DOM, Custom Elements, HTML Imports 와 HTML Templates 를 포함합니다
규범 상태
의존하는 4 가지 것, 현재 (2017/12/1) 상태는 다음과 같습니다:
Completed Work
2014-03-18 HTML Templates Group Note
Drafts
2017-09-05 Shadow DOM Working Draft
2016-10-13 Custom Elements Working Draft
2016-02-25 HTML Imports Working Draft
Obsolete
2014-07-24 Introduction to Web Components Retired
(All Standards and Drafts - W3C 에서 발췌)
즉, 이들 4 가지 의존 항목은 현재 1 개만 완료 (HTML Templates) 되었으며, 아직 추천 표준이 되지 못했습니다 (NOTE 만이고 REC 가 되지 못함). 나머지 3 개는 모두 작업 초안 (WD) 상태입니다
P.S. REC, NOTE 등의 W3C 문서 상태에 대한 더 많은 정보는, [W3C 규범 제정 프로세스](/articles/w3c 규범 제정 프로세스/) 참조
Web Components 규범 자신은 14 년에 1 판 (Introduction to Web Components) 을 냈지만, 폐기되었습니다 (Retired). 현재 Web Components 는규범 없음상태이며, github 는 아직 움직임이 있는 것 같습니다
P.S. 정말 궁금하다면, 폐기된 버전 을 한 번 볼 수 있습니다
구현 상태
규범은 불투명한 상태이지만, 일부 브라우저는 Web Components 의존 특성에不同程度的인 지원을 제공:
Shadow DOM
v0 Chrome25+ Firefox X Safari X Opera15+ Android4.4+ IOS Safari X
v1 Chrome53+ Firefox X Safari 10+ Opera40+ Android5+ IOS Safari 10.2+
Custom Elements
v0 Chrome33+ Firefox X Safari X Opera20+ Android4.4.4+ IOS Safari X
v1 Chrome54+ Firefox X Safari 10.1+ Opera41+ Android5+ IOS Safari 10.3
HTML Imports
Chrome36+ Firefox X Safari X Opera23+ Android5+ IOS Safari X
HTML Templates
Chrome26+ Firefox 22 Safari 7.1 Opera15+ Android4.4+ IOS Safari 8
주의:Android5+ 는 Android5-6.x WebView: Chromium 62 를 지칭하며, 부분 지원과 완전 지원을 구분하지 않음
Chrome, Opera 는一路緑이며, Safari 및 모바일端은 거의 따라가고, Firefox 는 조금만. 그러나 현재의 호환 형세에서 보면, PC 端과 모바일端은 모두사용 불가입니다
P.S. 호환성에 대한 더 많은 정보는, Can I use... Support tables for HTML5, CSS3, etc 참조
게다가, polyfill 과 컴포넌트 라이브러리로试玩 가능:
-
Polymer 2.0:Google
-
X-Tag:Microsoft
작용
Web Components 는 규범적인 컴포넌트 정의 방식을 제공하여, Web 컴포넌트 표준화를 추진하기를 희망
브라우저가 컴포넌트화方案에 필요한 환경 특성을 지원하며, Shadow DOM, Custom Elements, HTML Imports 와 Templates 를 포함
그럼 먼저 이들 4 가지 의존 특성이 무엇을 할 수 있는지 봅시다:
-
Shadow DOM:샌드박스 환경, 컴포넌트 격리에 사용. 컴포넌트는 외부의 영향을 받지 않으며, 컴포넌트 간도 서로 영향을 주지 않음
-
Custom Elements:컴포넌트 참조 방식. 커스텀 요소의 형식으로 컴포넌트를 참조
-
HTML Imports 와 Templates:컴포넌트 리소스 로드 방식과 컴포넌트声明 방식. 컴포넌트声明은
<template>태그 안에 놓고,<link rel="import" href>로 컴포넌트 리소스를 로드
핵심은컴포넌트 봉쇄임을 알 수 있습니다. Shadow DOM 으로 컴포넌트 상세를 은폐하며, 효과는 다음과 유사:
<video src="./video.mp4" controls></video>
이 프래그먼트를 포함한 HTML 페이지는 기능 완전한 비디오 플레이어를 제시하며, 재생 버튼, 프로그레스 바, 음량 조절 버튼 등을 포함
Web Components 의 용법은 이와 유사:
<my-app>
<my-nav-bar>
<my-title>Order Center</my-title>
</my-nav-bar>
<my-aside-menu/>
<my-filter-panel/>
<my-order-list/>
</my-app>
뷰 구조와 스타일을 커스텀 HTML 요소에 패키징하여, 블랙박스 컴포넌트 형식으로 참조. 컴포넌트는 격리된 환경 (Shadow DOM) 에서 정의되며, HTML, CSS, Script 는 모두 안전하고, 외부 는 컴포넌트 내부의 로직/뷰 상태를 직접 변경할 수 없음
물론, 컴포넌트는 봉쇄성 외에, 최소한 이하가 결여:
-
조합 방식, 예를 들어 Shadow DOM 의
<slot>를 통해 -
통신 메커니즘, 예를 들어 attributeChangedCallback 등의 라이프사이클 Hook 을 통해
这部分 내용은 Web Components 자신의 규범에 정의되어야 합니다 (예를 들어 이전 폐기된 Introduction 등). 더 상층의 것에 대해서는, Web Components 의 고려 범위 내에 없습니다. 결국 컴포넌트 표준화의 첫 걸음은 무에서 유여야 합니다
이.video 에서说起
1 줄의 video 태그를 쓰기만 하면:
<video src="./foo.webm" controls></video>
페이지는 기능 완전한 비디오 플레이어를 제시합니다. 그럼 재생 버튼, 프로그레스 바의 구조 정의와 스타일 선언은 어디에 숨어 있을까요?难道는单选버튼 등의 폼 요소처럼, 시스템 플랫폼이 컨트롤을 렌더링? 그렇다면, 플랫폼 무관계의 부분은, 예를 들어 텍스트박스의 placeholder 는, 어떻게 구현되어 있을까요?
실제, 텍스트박스의 placeholder 는 video 와 유사하며, 몇 가지의보이지만 (구조화 문서 내에서) 찾을 수 없는 요소는 모두 Shadow DOM 에 숨어 있습니다:

video, input 은브라우저의 내장 컴포넌트에 상당하며, 컴포넌트 뷰 구조 및 디폴트 스타일은 Shadow DOM 에 숨고, 컴포넌트 로직은 완전히 숨겨지며, autoplay, oninput 등의 상태/행동 Hook 만 외부와의 통신을 위해 노출
여기서, Web Components 의 개념과 매우 비슷함을 알 수 있습니다.所谓 Web Components 는 브라우저의 컴포넌트 메커니즘을 노출하여, Web 개발자에게 사용하게 하는 것뿐입니다. 이렇게 하면 우리도 즐겁게「네이티브 컨트롤」(컴포넌트) 을 정의할 수 있습니다
삼.Shadow DOM
앞에서 계속 물건을 Shadow DOM 에 숨기는 것을 강조해 왔습니다. Shadow DOM 의 작용은 sandbox(샌드박스) 에 상당하며, 컴포넌트 격리 환경을 제공
Chrome 에서 이 특성을试玩:

Shadow DOM 표시 스위치를 켠 후, 텍스트박스의 숨은 부분을 들여다봅시다:
<input class="nav-search column-07 start-18" name="s" type="text" placeholder="嗯。我看到过你的小熊。">
#shadow-root (user-agent)
<div pseudo="-webkit-input-placeholder" id="placeholder" style="display: block !important; text-overflow: clip;">嗯。我看到过你的小熊。</div>
<div id="inner-editor"></div>
placeholder 는 조용히 여기서 대기하며, #inner-editor 는 입력된 텍스트를 표시
브라우저가 제공하는 Shadow DOM 특성을 이용하여, 자신의 Shadow Root 를 생성:
document.body.innerHTML = '<div class="container"></div>';
var host = document.querySelector('.container');
var root = host.createShadowRoot();
root.innerHTML = '<p>How <em>you</em> doin?</p>'
此時노드 구조는 이렇습니다:
<div class="container"></div>
#shadow-root (open)
<p>How <em>you</em> doin?</p>
페이지는「How you doin?」를 표시. Shadow Root 아래의 콘텐츠는 페이지에呈現되기 때문
Shadow Root 는 createShadowRoot() 가 반환하는 Fragment 를 지칭:
host.createShadowRoot() instanceof DocumentFragment === true
Fragment 에 대해 DOM 조작을 할 수 있으며, 독립된 HTML 해석 환경에 상당하며, 외부의 간섭을 받지 않음
게다가 2 가지 개념:Shadow Host 와 Shadow Boundary
Shadow Host
Shadow Root 의「숙주」. Shadow DOM 과 DOM 의 연결점.说白了就是 Shadow DOM 이 어디에 걸려 있는가 (상예 중의 host)
기숙 관계가 있으므로, 시도해 봅시다:
host.parentElement.removeChild(host)
body 중에 아무것도 없어진 것을 알 수 있습니다. Shadow DOM 은 숙주와 함께 삭제되었습니다 (반환값은 유리의 div 노드.此時 Shadow DOM 은 여전히 div 에 걸려 있으며, 노드를 append 돌아와서 검증할 수 있습니다)
Shadow Boundary
1 가지의 추상 개념으로, Shadow DOM 밖의 이 층의「결계」를 지칭. Shadow Root 아래의 HTML 과 CSS 를 격리할 수 있으며, Shadow Host 가所在하는 문서 내의 스타일과서로 영향을 주지 않으며, 외부 는 JS 로 Shadow Root 아래의 노드 오브젝트를 취득할 수 없습니다. iframe 의 격리 효과에 유사
这正是 Web 개발이ずっと 원했던 모듈 격리. 이름공간 등의 공程化方案으로 메울 수 있지만, 항상 몇 가지 메울 수 없는 결함이 있습니다. 근본적인 원인은 최종적으로 페이지상에呈現되는 HTML 과 CSS 에는 스코프의 개념이 없으며, 개발 단계 중의 제한 수단은 여기서 도덕적 구속이 되었습니다. 다른方面, 공程化 수단으로 구속하면, 제한이 너무 많아서 업무가束手束脚이 되는 문제도 존재할 수 있습니다
Insertion Points
게다가, 컴포넌트 조합의 기본 지원을 알 필요가 있습니다:
<div class="breaking">
<ul>
<slot name="breaking"></slot> <!-- slot for breaking news -->
</ul>
</div>
<div class="other">
<ul>
<slot></slot> <!-- slot for the rest of the news -->
</ul>
</div>
(Shadow DOM W3C Editor's Draft 14 November 2017 에서 발췌)
2 종류의 삽입 방식으로, 각각具名슬롯과 디폴트 슬롯을 표. 매우 익숙하고, Vue 템플릿은 이렇게 씁니다. 왜냐하면:
For example, Vue components implement the Slot API and the is special attribute.
Vue 와 Web Components 의 관계에 대해서는, 나중에 이야기합니다
사.Custom Elements
커스텀 요소를 생성. 錦上添花의 작은 것. 커스텀 요소 특성이 없다면, 이렇게 해야 합니다:
<ul class="stories">
<li><a href="//example.com/stories/1">A story</a></li>
<li><a href="//example.com/stories/2">Another story</a></li>
<li class="breaking" slot="breaking"><a href="//example.com/stories/3">Also a story</a></li>
<li><a href="//example.com/stories/4">Yet another story</a></li>
<li><a href="//example.com/stories/5">Awesome story</a></li>
<li class="breaking" slot="breaking"><a href="//example.com/stories/6">Horrible story</a></li>
</ul>
있다면, 이렇게 쓸 수 있습니다:
<stories>
<li><a href="//example.com/stories/1">A story</a></li>
<li><a href="//example.com/stories/2">Another story</a></li>
<breaking slot="breaking"><a href="//example.com/stories/3">Also a story</a></breaking>
<li><a href="//example.com/stories/4">Yet another story</a></li>
<li><a href="//example.com/stories/5">Awesome story</a></li>
<breaking slot="breaking"><a href="//example.com/stories/6">Horrible story</a></breaking>
</stories>
의미의角度에서 보면, 커스텀 요소의 표현력은 더 강하고, 더 간결합니다
커스텀 태그에는 2 가지 제약:
-
태그명은 반드시 短線을 포함
-
프로토타입은 반드시 HTMLElement 에서 상속
同様に试玩:
document.body.innerHTML = '<template id="tmpl"><p>How <em>you</em> doin?</p><style>em {font-size: 200%;}</style></template><div class="container"></div>';
// Grab our template full of markup and styles
var tmpl = document.querySelector('#tmpl');
// Create a prototype for a new element that extends HTMLElement
var HowYouDoinProto = Object.create(HTMLElement.prototype);
// Setup our Shadow DOM and clone the template
HowYouDoinProto.createdCallback = function() {
var root = this.createShadowRoot();
root.appendChild(document.importNode(tmpl.content, true));
};
// Register our new element
var HowYouDoin = document.registerElement('how-you-doin', {
prototype: HowYouDoinProto
});
document.querySelector('.container').innerHTML = '<how-you-doin/>';
以下를 얻습니다:
<div class="container">
<how-you-doin>
#shadow-root (open)
<p>How <em>you</em> doin?</p>
<style>em {font-size: 200%;}</style>
</how-you-doin>
</div>
呈現되는 콘텐츠도 우리의 소원대로:큰 you
상예 중의 document.registerElement 는 Custom Elements 특성. importNode() 에 대해서는, 그냥普通の DOM API(Custom Elements 의 일부가 아님) 로, 노드를 클론하기 위함.否则템플릿은 일회용
HTML Imports 에 대해서는, 더욱 중요하지 않습니다.同様に CORS 가 있으며,シンプルな 컴포넌트 로드方案으로, ajax 로 수동 로드 컴포넌트와 큰 차이는 없습니다. HTTP2.0 시대가 정말 도래하기 전에, 생산 환경에서는 아직 다 파일로 나누지 마십시오
P.S. HTML Imports 에 관심이 있다면, 온라인 Demo 와 참고 자료 참조
오.Vue 와 Web Components
지금까지, 위에서 언급한 모든 예는, 어떻게 봐도 Vue 컴포넌트 정의 같습니다.没错.Vue 는 구현상에서일부의 Web Components 규범을 따랐기 때문. 예를 들어 Shadow DOM 내의 slot:
You may have noticed that Vue components are very similar to Custom Elements, which are part of the Web Components Spec. That's because Vue's component syntax is loosely modeled after the spec. For example, Vue components implement the Slot API and the is special attribute.
주로 2 가지 차이:
- The Web Components Spec is still in draft status, and is not natively implemented in every browser. In comparison, Vue components don't require any polyfills and work consistently in all supported browsers (IE9 and above). When needed, Vue components can also be wrapped inside a native custom element.
- Vue components provide important features that are not available in plain custom elements, most notably cross-component data flow, custom event communication and build tool integrations.
Web Components 규범이 아직 성숙하지 않고, 지원성도 낙관적이지 않아, polyfill 없이는 생산에 투입할 수 없습니다. Vue 는 구축 도구에 의존하여 환경 호환성 문제를 넘었고, 브라우저 특성 지원에 의존하지 않지만, 동시에 Shadow DOM 봉쇄성 등의 Web Components 핵심 우위성을捨었습니다
게다가, Web Components 는 비교적底层의 컴포넌트 규범으로, Vue 는 컴포넌트 규범을 정의하는 외에, 컴포넌트 통신, 데이터 바인딩 등의 상층方案도 제공
육.온라인 Demo
주소:http://www.ayqy.net/temp/web-components/image-slider.html
P.S. 구현이 매우 교묘한 순 CSS 로 인디케이터付き의 image slider 컴포넌트. 매우재미있음. 일반 인접 선택기 (E ~ F) 에 대한 필자의 견해를 갱신
참고 자료
-
A Guide to Web Components:매우 우수한 Web Components 가이드
-
Shadow DOM W3C Editor's Draft 14 November 2017:Shadow DOM 편집 초고
아직 댓글이 없습니다