Web Components & Polymer
-
Upload
jae-sung-park -
Category
Technology
-
view
517 -
download
4
Transcript of Web Components & Polymer
WEB COMPONENTS&
POLYMER2014.11.04
박재성
WHO IS THIS GUY?JindoJS 자바스크립트 프레임워크
일반적인 웹 개발은?
WEB COMPONENTS?재사용 가능한 컴포넌트를 만들 수 있는 표준 기술들의 모음
Custom Elements : 커스텀 태그를 통한 요소 생성
HTML Imports : HTML 페이지 로딩
HTML Templates : 템플릿
Shadow DOM : DOM과 스타일의 캡슐화
CUSTOM ELEMENTS커스텀 태그를 통한 요소 생성
새로운 HTML 요소를 생성
다른 요소를 확장해 생성가능
단일 태그에 커스텀 기능의 묶음 가능
기존 DOM 요소의 API를 확장
태그명에 '-'(dash)는 반드시 포함해야 한다.
CUSTOM ELEMENTS기본 사용방법
// document.registerElement()를 통해 등록 var NTag = document.registerElement('n-tag');
// 또는 다음과 같이 특정 HTML 인터페이스를 사용해 등록할 수도 있다. // custom element는 기본적으로 'HTMLElement'를 상속한다. var NTag = document.registerElement('n-tag', { prototype: Object.create(HTMLElement.prototype) });
// 문서에 추가 document.body.appendChild(new NTag());
CUSTOM ELEMENTSvar NTag = document.registerElement('n-tag', { prototype: Object.create(HTMLElement.prototype)});
document.body.appendChild(new NTag());
//alert(document.querySelector("n-tag"));//alert(document.getElementsByTagName("n-tag")[0].__proto__.constructor +"");
JavaScript
CUSTOM ELEMENTS기존 요소를 확장
// <button> 태그를 확장 var XButton = document.registerElement('x-button', { prototype: Object.create(HTMLButtonElement.prototype), extends: 'button' });
확장된 요소들은 type extension custom elements라 불리우며,"element X is a Y"와 같이 사용
<button is="x-button"></button>
CUSTOM ELEMENTS속성과 메서드 추가
// 1. HTML 객체 생성var XTestProto = Object.create(HTMLElement.prototype);
// 2. ‘hi’ 메서드 추가XTestProto.hi = function() { alert('안녕하세요.'); };
// 3. 읽기 전용 ‘bar’ 속성 설정Object.defineProperty(XTestProto, "bar", {value: 5});
// 4. <x-test> 태그 등록. 태그명에는 '-'가 꼭 포함되어야 함.var XTest = document.registerElement('x-test', { prototype: XTestProto });
/*var XTestProto = document.registerElement('x-test', {
JavaScript
HTML
CUSTOM ELEMENTSLifecycle callback
콜백 발생시점
createdCallback 인스턴스가 생성될 때
attachedCallback 생성된 인스턴스가 문서에 추가될때
detachedCallback 인스턴스가 문서에서 제거될 때
attributeChangedCallback
(attrName, oldVal, newVal)
속성이 변경될 때(추가/삭제/수정)
var proto = Object.create(HTMLElement.prototype);
// 콜백 등록 proto.createdCallback = function() { ... }; proto.attachedCallback = function() { ... };
var XFoo = document.registerElement('x-foo', {prototype: proto});
CUSTOM ELEMENTS컨텐츠가 포함된 custom element
var NTagProto = Object.create(HTMLElement.prototype);
NTagProto.createdCallback = function() { this.innerHTML = "<b>반갑습니다~</b>";};
var NTagHi = document.registerElement('n-tag-hi', { prototype: NTagProto });
JavaScript
HTML
CUSTOM ELEMENTS아직 요소의 등록이 제대로 되지 않은 상태인 경우,
FOUC* 상태로 페이지가 렌더링될 수 있다.
:unresolved pseudo class를 사용해 이를 방지할 수 있다.
x-test { ... } x-test:unresolved { opacity: 0; }
*FOUC(Flash Of Unstyled Content) - http://en.wikipedia.org/wiki/Flash_of_unstyled_content
HTML IMPORTSHTML 페이지를 로딩
JS/HTML/CSS를 묶음 형태로 사용 → 단일 URL로 호출
HTML Import를 통한 추가되는 컴포넌트들은 중복되는 경우라도 호출,
파싱 및 실행은 단 한 번만 수행
Import 내의 스크립트는 메인 문서의 파싱을 블럭하지 않음
스크립트는 import시 실행되나, 다른 요소(마크업,CSS 등)들은
메인 페이지에 추가되는 시점에 활성화
HTML IMPORTS기본 사용방법
<link rel="import" href="/path/file_name.html">
다른 도메인의 파일을 임포트 하기 위해선CORS가 활성화 되어 있어야 한다.
HTML IMPORTS이벤트 (load & error)
<link rel="import" href="/path/file_name.html" onload="handleLoad(event)" onerror="handleError(event)">
브라우저가 <link rel="import"> 태그를 만나면즉시 로딩하기 때문에 이벤트 핸들러는import 태그 이전에 선언되어야 한다.
var el = document.createElement("link");el.rel = "import";el.href="./resource/blank.html";
el.onload = function(e) { // TODO
};
document.head.appendChild(el);
JavaScript
HTML IMPORTSimport된 컨텐츠의 활용
import가 수행된다고 해서 그 지점에 컨텐츠가포함되는 형태는 아니며, 브라우저가 해당 파일을
파싱하고 사용할 수 있도록 준비되는 것.
import 속성을 사용해 컨텐츠 문서에 접근할 수 있다.
// import된 문서를 얻는다.var contentDoc = document.querySelector('link[rel="import"]').import;
// 컨텐츠 문서에서 셀렉터를 통해 요소를 선택한다.//alert(contentDoc.querySelector("*").outerHTML);
JavaScript
main.html
import.html
HTML IMPORTS페이지의 동작
<link rel="import" href="import.html">
<link rel="stylesheet" href="common.css"><style>
</style><script>
</script>
/* 이 블럭내의 스타일은 기본적으로 main.html에 반영됨 */
// import.html 문서를 가리킴. 즉, 현재 파일var importDoc = document.currentScript.ownerDocument;
// main.html 문서를 가리킴. 즉, 현재 파일을 import 하는 파일var mainDoc = document;
// import.html 문서내의 스타일시트를 main.html에 포함하고자 한다면, 아래와 같이 별도 추가작업이 필요var styles = importDoc.querySelector('link[rel="stylesheet"]');mainDoc.head.appendChild(styles.cloneNode(true));
HTML IMPORTS기억할 점
스크립트는 window 문맥에서 실행import는 메인 페이지의 파싱을 블럭하지는 않지만,렌더링은 블럭
import되는 페이지에 style이 포함될 수 있으므로, 브라우저는 FOUC를 방지하기 위해 렌더링을 블럭
비동기적으로 import 하고자 한다면 async 속성을 추가<link rel="import" href="/path/some.html" async>
import 파일들은 일반적인 리소스와 마찬가지로 브라우저 캐싱됨
HTML IMPORTS <!-- main.html --> <head><link rel="import" href="some.html"></head> <body> <script>
</script> </body>
var link = document.querySelector('link[rel="import"]'); var content = link.import; var el = content.querySelector('div'); document.body.appendChild(el.cloneNode(true));
<!-- some.html --> <script> </script> <div> <style> </style> <h3>HTML Imports</h3> <p>안녕하세요. 반갑습니다~!</p> </div>
alert("파일이 import 되었습니다.");
h3 { color: red; }
HTML IMPORTS// TODO : import "./resource/some.html"
/*var link = document.querySelector('link[rel="import"]');var content = link.import;var el = content.querySelector('div');document.getElementById("content02").appendChild(el.cloneNode(true));*/
JavaScript
HTML TEMPLATES재사용을 위한 템플릿
비활성화 상태의 복제 가능한 DOM chunk
새로운 태그 : <template> … </template>
태그 내의 태그들은 사용되기 전까진 파싱은 되나 렌더링되지 않음
컨텐츠는 클론/사용 되기전까진 비활성
페이지의 일부분이 아님
중첩된 <template>은 동작하지 않음
HTML TEMPLATES // 1. content 속성을 사용해 템플릿의 노드(#document-fragment)에 접근할 수 있다. var content = document.getElementById("count").content;
// 2. 템플릿내의 DOM에 대한 작업을 한다. var span = content.querySelector('span'); span.textContent = parseInt(span.textContent, 10) + 1;
// 3. 메인 DOM에 document.importNode()를 통해 추가한다. document.getElementById("content03").appendChild( document.importNode(content, true));
<!-- 템플릿 --> <template id="count"> <div>Template used: <span>0</span></div> <script> </script> </template>
alert('클릭하셨네요!');
HTML TEMPLATES// 1. content 속성을 사용해 템플릿의 노드(#document-fragment)에 접근할 수 있다.var content = document.getElementById("count").content;
// 2. 템플릿내의 DOM에 대한 작업을 한다.var span = content.querySelector('span');span.textContent = parseInt(span.textContent, 10) + 1;
// 3. 메인 DOM에 document.importNode()를 통해 추가한다.document.getElementById("content03").appendChild(document.importNode(content, true));
JavaScript
<template id="count"> <div>Template used: <span>0</span></div> <script>alert('클릭하셨네요!');</script></template>
HTML
SHADOW DOMDOM과 스타일의 캡슐화
별도의 스코프를 갖는 DOM
새로운 root node → "shadow root"
shadow root를 가지고 있는 요소는 "shadow host"라고 불리움
shadow host의 컨텐츠는 렌더링되지 않으며, 대신 shadow root의 컨텐츠가 렌더링됨
Polymer에서 생성하는 모든 요소들은 shadow DOM으로 처리
<video src="http://v2v.cc/~j/theora_testsuite/320x240.ogg" controls="controls"></video>
0:03
SHADOW DOM기본 사용방법
// shadow root를 포함할 host를 얻는다.var host = document.getElementById('shadow_btn');
// shadow root를 생성한다.var root = host.createShadowRoot();root.textContent = '안녕하세요.';
JavaScript
<button id="shadow_btn">Hello, world!</button> HTML
SHADOW DOMPesudo class
Shadow DOM에 정의된 css 스타일은기본적으로 ShadowRoot 스코프를 갖는다.
:host / :host(selector)host 요소를 의미 (ShadowRoot context내에서만 사용가능)
var host = document.getElementById('shadow_btn2');var root = host.createShadowRoot();
// ShadowRoot를 host 하는 요소를 가리킨다.root.innerHTML = '<style>' + ':host { text-transform: uppercase; }' + '</style>' + '<content></content>';
JavaScript
My Button
SHADOW DOMPesudo class
:host-context(selector)host의 조상 요소들중 selector와 매칭되는 경우에만 host에 스타일을 지정
var host = document.getElementById('shadow_btn3');var root = host.createShadowRoot();
// ShadowRoot를 host 하는 조상 요소들 중 매칭되는 경우에만 스타일을 지정root.innerHTML = '<style>' + ':host-context(.host-context) { text-transform: uppercase; }' + '</style>' + '<content></content>';
JavaScript
<div class="host-context"> <button id="shadow_btn3" class="red">My Button</button></div>
HTML
SHADOW DOMPesudo element
::shadowShadowRoot를 갖는 요소
var host = document.getElementById('shadow_div');var root = host.createShadowRoot();
root.innerHTML = '<span>Shadow DOM</span>' + '<content></content>';
JavaScript
<style>#shadow_div::shadow span { color: red }</style>
<div id="shadow_div"> <span>Light DOM</span></div>
HTML
SHADOW DOMCombinator
/deep/::shadow 보다 강력하며, 모든 shadow boundary를 가로질러 임의의 요소와 매칭
// shadow 트리내의 모든 .hello 클래스 요소와 매칭body /deep/ .hello { /* 스타일 */ }
<style>/* 네이티브 요소 스타일링 */video /deep/ input[type="range"] { background: hotpink; }</style>
HTML
0:03
SHADOW DOM<content> : host의 특정 요소를 출력(포함)
var host = document.getElementById('shadow_div06');var root = host.createShadowRoot();root.innerHTML = '<style>h3 { color: red; }\ content[select="h3"]::content > h3 { color: green; }\ ::content section p { text-decoration: underline; }</style>\ <h3>Shadow DOM</h3>\ <content select="h3"></content>\ <content select="section"></content>';
JavaScript
<div id="shadow_div06"><h3>Light DOM</h3><section> <div>I'm not underlined</div> <p>I'm underlined in Shadow DOM!</p></section></div>
HTML
SHADOW DOM몇가지 특징
한개의 host에서 여러 개의 ShadowRoot를 만들 수 있음
하지만, LIFO(Last In, First Out) 스택과 같이 마지막에 추가된
ShadowRoot가 렌더링됨
제일 처음 추가된 트리는 'older tree'
→ .olderShadowRoot 속성을 통해 접근
제일 마지막에 추가된 트리는 'yonger tree'
→ .shadowRoot를 통해 접근
SHADOW DOM<shadow> : shadow root에서 shadow 요소를 출력(포함)var host = document.getElementById('shadow_div7');var root1 = host.createShadowRoot();var root2 = host.createShadowRoot();
root1.innerHTML = '<div>루트 1</div><content></content>';root2.innerHTML = '<div>루트 2</div><shadow></shadow>';
JavaScript
<div id="shadow_div7">Light DOM</div> HTML
SHADOW DOMElement.getDistributedNodes()
<content>로 포함된 노드들을 접근할 수 있도록 한다.
var host = document.getElementById('shadow_div8');var root = host.createShadowRoot();
// 템플릿을 ShadowRoot에 추가한다.var template = document.getElementById('sdom');var clone = document.importNode(template.content, true);root.appendChild(clone);
var html = [];[].forEach.call(root.querySelectorAll('content'), function(el) { html.push(el.select + ': ');
JavaScript
<div id="shadow_div8"> <span>HTML</span> <span>5</span> <div>Shadow DOM</div> <h5>footer</h5></div>
HTML
SHADOW DOMElement.getDestinationInsertionPoints()
자신을 포함시킨 ShadowRoot 요소에 접근
var host = document.getElementById('shadow_div9');var root1 = host.createShadowRoot();var root2 = host.createShadowRoot();
root1.innerHTML = '<content select="h2"></content>';root2.innerHTML = '<shadow></shadow>';
// 해당 요소를 ShadowRoot에 포함시킨 요소에 접근var h2 = document.querySelector('#shadow_div9 h2');var insertionPoints = h2.getDestinationInsertionPoints();
var html = [];[].forEach.call(insertionPoints, function(contentEl) { html.push(contentEl.outerHTML);
JavaScript
<div id="shadow_div9"> <h2>Light DOM</h2></div>
HTML
SHADOW DOMShadow DOM Visualizer
ShadowDOM Visualizer
<div id="host"> <h2>Eric</h2> <h2>Bidelman</h2> <div class="desc"> Title: <span>Digital Jedi</span> </div> <div>Not selected</div> <h4>footer text</h4></div>
HOST NODE
<header> <content select="h2"></content> </header> <section> <content select="div.desc"></content> </section> <footer> <content select="h4"></content> </footer>
SHADOW DOM
div[id=host]
header
content[select=h2]
h2 #Eric h2 #Bidelman
section
content[select=div.desc]
div[class=desc] #Title:
span #Digital Jedi
footer
content[select=h4]
h4 #footer text
COMPOSED/RENDERED TREE
What's this?
WEB COMPONENT를사용하면?
태그 형태로 특정 기능을 갖는 UI 컴포넌트들을삽입할 수 있어, 손쉬운 재사용이 가능해집니다!
POLYMER?Polymer is a library that makes building applications easier.
Is built on Web Components.
https://www.polymer-project.org/
POLYMER ARCHITECTUREPolymer Elements : polymer.js
Polyfill : platform.js (webcomponent.js로 변경예정)
POLYFILL?브라우저가 네이티브 하게 지원하지 않는 기능을
사용 가능하도록 만들어주는 코드 모음http://remysharp.com/2010/10/08/what-is-a-polyfill/
Web Components polyfillMozilla X-Tag : Google Polymer :
http://www.x-tags.org/http://www.polymer-project.org/
브라우저 호환성Polyfill
ChromeAndroid Chrome Canary Firefox IE 10+ Safari 6+ Mobile
Safari
TemplateMutationObserver [1]HTML ImportsCustom Elements [1]Shadow DOMObject.observe()Web Animations
Platform
Native implementationChromeAndroid Chrome Canary Firefox IE 10+ Safari 6+ Mobile
Safari
TemplateMutationObserverHTML Imports F F 36Custom Elements 33 33Shadow DOM 35 35 35 [2]Object.observe() 35 F 35 F 36Web Animations
Platform
https://www.polymer-project.org/resources/compatibility.html
Chrome 36+ 부터 웹컴포넌트 스펙들은 네이티브하게 지원
POLYMER 는EVERGREEN BROWSER*에서
문제없는 실행을 목표.*Evergreen Web Browser is a web browserthat automatically updates itself on startup.
http://www.yetihq.com/blog/evergreen-web-browser/
POLYMER ELEMENTS : CORE ELEMENTS유틸리티 요소와 공통적 UI 요소들의 모음
Ajax, 애니메이션, 드래그&드롭, 아이콘 모음, 툴팁, etc.
Animation
animated!
raw raw group custom infinite
Core Elements
Animation
Collapse
Drag and Drop
Drawer Panel
Dropdown
Dropdown Menu
http://www.polymer-project.org/docs/elements/core-elements.html
POLYMER ELEMENTS : PAPER ELEMENTSMaterial design*이 적용된 UI 요소들의 모음
버튼, 체크박스, 다이얼로그, 입력요소, 탭, 토스트, etc.
Checkbox
Notifications
Notify me about updates to apps or games that I'vedownloaded
Auto-updates
Auto-update apps over wifi only
Clear search history
Remove all the searches you have ever performed
Paper Elements
Checkbox
Radio Button
Toggle Button
Input
Toolbar
Progress Bar
http://www.polymer-project.org/docs/elements/paper-elements.html
MATERIAL DESIGN?"머티리얼 디자인에서 표면과 그림자는 물리적인 구조를 형성하여,
사용자들이 화면 상의 어떤 부분을 터치할 수 있고
움직일 수 있는지 쉽게 이해할 수 있도록 돕습니다."
다양한 디바이스를 아우르는 일관된 디자인질감이 느껴지는 표면(tactile surfaces)대담하고 선명한 그래픽 디자인 (bold graphic design)자연스러운 애니메이션
사용방법 #1이미 만들어진 요소들을 사용하는 방법
1. platform.js를 페이지에 로딩
2. 사용할 요소를 페이지에 로딩
3. 페이지 내에 새로 추가된 요소를 태그로 선언
<script src="../components/platform/platform.js"></script>
<link rel="import" href="./components/paper-checkbox/paper-checkbox.html">
<paper-checkbox></paper-checkbox>
이미 만들어진 요소들을 사용하는 방법<!-- paper elementspaper-input label="이름을 입력하세요."paper-checkboxpaper-radio-button-->
HTML
사용방법 #2 - 직접 요소를 생성Step 1: 요소에 해당되는 페이지 작성
1. Polymer core를 페이지에 삽입
2. <polymer-element>를 사용해 새로운 태그 등록
<link rel="import" href="../components/polymer/polymer.html">
<polymer-element name="사용자정의-태그" noscript> <template> <span>내용</span> </template></polymer-element>
사용방법 #2 - 직접 요소를 생성Step 2: 사용될 페이지에서 요소 페이지 삽입 후, 태그로 선언
<head> <script src="../components/platform/platform.js"></script> <link rel="import" href="./파일.html"></head><body> <사용자정의-태그></사용자정의-태그></body>
직접 생성한 요소를 사용하는 방법JavaScript
<naver-search></<naver-search> HTML
POLYMER DEMO APP / Topeka Calculator
Sign In
Choose an Avatar
First Name
Last Initial
7
4
1
.
8
5
2
0
9
6
3
=
DEL
+
-
÷
×
2nd
sinh
EXP
VULCANIZE사용되는 웹 컴포넌트 파일들을 병합해
HTTP request를 줄일 수 있도록 해주는 도구
# 설치 $ sudo npm install -g vulcanize
# 사용 $ vulcanize 대상파일.html --inline --strip -o 결과파일.html
https://github.com/Polymer/vulcanize
WEB COMPONENTS ECOSYSTEM다양한 웹컴포넌트 생태계
http://component.kitchen/
http://customelements.io/
http://googlewebcomponents.github.io/
BOWER대다수의 웹컴포넌트들은
Bower*를 통한 손쉬운 설치를 제공
$ bower install 컴포넌트명
*A package manager for the web - http://bower.io/
<SORTABLE-TABLE>$ bower install sortable-table
<sortable-table columns='["과일","가","나","다"]' data='[ [ "사과", 4, 10, 2 ], [ "바나나", 0, 4, 0 ], [ "포도", 2, 3, 5 ] ]'></sortable-table>
HTML
<GOOGLE-MAP>$ bower install GoogleWebComponents/google-map
<google-map latitude="37.499405" longitude="127.033716" zoom="17" fitToMarkers="true"> <google-map-marker latitude="37.499405" longitude="127.033716" title="포스코P&S타워"></google-map-marker></google-map>
HTML
MOZILLA BRICK모질라에서 개발한 UI 웹컴포넌트
Brick
Blog
Components
action
appbar
calendar
deck
flipbox
form
layout
menu
tabbar
storage-indexeddb
BrickBrick is a collection of UI components designed for the easy and quick building ofweb application UIs. Brick components are built using the Web Components standardto allow developers to describe the UI of their app using the HTML syntax theyalready know.
InstallBrick can be installed using the Bower package manager:
bower install mozbrick/brick
To use Brick in your project, place the following in the <head> of your main HTML:
<script src="bower_components/brick/dist/platform/platform.js"></script>
<link rel="import" href="bower_components/brick/dist/brick.html">
https://mozbrick.github.io/
REFERENCEWebComponents.org
Google I/O 2014 - Polymer and Web Components change everything you know about
Web development
Google I/O 2014 - Polymer and the Web Components revolution
Google I/O 2014 - Unlock the next era of UI development with Polymer
Custom Elements
HTML Imports
HTML's New Template Tag
Shadow DOM
http://webcomponents.org/
https://www.youtube.com/watch?v=8OJ7ih8EE7
https://www.youtube.com/watch?v=yRbOSdAe_JU
https://www.youtube.com/watch?v=HKrYfrAzqFA
http://www.html5rocks.com/en/tutorials/webcomponents/customelements/
http://www.html5rocks.com/en/tutorials/webcomponents/imports/
http://www.html5rocks.com/en/tutorials/webcomponents/template/
http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom/
http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom-201/
http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom-301/
<thank-you><thank-you> 고맙습니다.고맙습니다.
</thank-you></thank-you>