박재성
네이버 AU 개발랩
재사용 가능한 컴포넌트를 만들 수 있는 표준 기술들의 모음
커스텀 태그를 통한 요소 생성
기본 사용방법
태그명에 '-'(dash)는 반드시 포함해야 한다. // 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());
기존 요소를 확장
// <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>
속성과 메서드 추가
Lifecycle 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 element
아직 요소의 등록이 제대로 되지 않은 상태인 경우,
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 페이지를 로딩
기본 사용방법
<link rel="import" href="/path/file_name.html">
다른 도메인의 파일을 임포트 하기 위해선
CORS가 활성화 되어 있어야 한다.
이벤트 (load & error)
<link rel="import" href="/path/file_name.html"
onload="handleLoad(event)"
onerror="handleError(event)">
브라우저가 <link rel="import"> 태그를 만나면
즉시 로딩하기 때문에 이벤트 핸들러는
import 태그 이전에 선언되어야 한다.
import된 컨텐츠의 활용
import가 수행된다고 해서 그 지점에 컨텐츠가
포함되는 형태는 아니며, 브라우저가 해당 파일을
파싱하고 사용할 수 있도록 준비되는 것.
import 속성을 사용해 컨텐츠 문서에 접근할 수 있다.
페이지의 동작
main.html<link rel="import" href="import.html">
import.html <link rel="stylesheet" href="common.css">
<style>
/* 이 블럭내의 스타일은 기본적으로 main.html에 반영됨 */
</style>
<script>
// 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));
</script>
기억할 점
import되는 페이지에 style이 포함될 수 있으므로, 브라우저는 FOUC를 방지하기 위해 렌더링을 블럭
비동기적으로 import 하고자 한다면 async 속성을 추가
<link rel="import" href="/path/some.html" async>
<head><link rel="import" href="some.html"></head>
<body>
<script>
var link = document.querySelector('link[rel="import"]');
var content = link.import;
var el = content.querySelector('div');
document.body.appendChild(el.cloneNode(true));
</script>
</body>
<script>alert("파일이 import 되었습니다.");</script>
<div>
<style> h3 { color: red; } </style>
<h3>HTML Imports</h3>
<p>안녕하세요. 반갑습니다~!</p>
</div>
재사용을 위한 템플릿
// 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>alert('클릭하셨네요!');</script>
</template>
DOM과 스타일의 캡슐화
기본 사용방법
Pesudo class
Shadow DOM에 정의된 css 스타일은
기본적으로 ShadowRoot 스코프를 갖는다.
:host / :host(selector)
host 요소를 의미 (ShadowRoot context내에서만 사용가능)
Pesudo class
:host-context(selector)
host의 조상 요소들중 selector와 매칭되는 경우에만 host에 스타일을 지정
Pesudo element
::shadow
ShadowRoot를 갖는 요소
<content> : host의 특정 요소를 출력(포함)
몇가지 특징
<shadow> : shadow root에서 shadow 요소를 출력(포함)
Element.getDistributedNodes()
<content>로 포함된 노드들을 접근할 수 있도록 한다.
Element.getDestinationInsertionPoints()
자신을 포함시킨 ShadowRoot 요소에 접근
태그 형태로 특정 기능을 갖는 UI 컴포넌트들을
삽입할 수 있어, 손쉬운 재사용이 가능해집니다!
The Polymer library is designed to make it easier and faster
for developers to create great,
reusable components for the modern web.
Is built on Web Components.
https://www.polymer-project.org/
브라우저가 네이티브 하게 지원하지 않는 기능을
사용 가능하도록 만들어주는 코드 모음
http://remysharp.com/2010/10/08/what-is-a-polyfill/
(Chrome 36+ 부터 웹컴포넌트 스펙들은 네이티브하게 지원)
*Evergreen Web Browser is a web browser
that updates itself without prompting the user.
유틸리티 요소와 공통적 UI 요소들의 모음
Ajax, 애니메이션, 드래그&드롭, 아이콘 모음, 툴팁, etc.
https://elements.polymer-project.org/browse?package=iron-elements
Material design*이 적용된 UI 요소들의 모음
버튼, 체크박스, 다이얼로그, 입력요소, 탭, 토스트, etc.
https://elements.polymer-project.org/browse?package=paper-elements
"머티리얼 디자인에서 표면과 그림자는 물리적인 구조를 형성하여,
사용자들이 화면 상의 어떤 부분을 터치할 수 있고
움직일 수 있는지 쉽게 이해할 수 있도록 돕습니다."
이미 만들어진 요소들을 사용하는 방법
<script src="bower_components/webcomponentsjs/webcomponents.js"></script>
<link rel="import" href="bower_components/paper-input/paper-input.html">
<paper-input></paper-input>
Step 1: 요소에 해당되는 페이지 작성
<link rel="import" href="bower_components/polymer/polymer.html">
<dom-element name="사용자정의-태그" noscript>
<template>
<span>내용</span>
</template>
</dom-element>
<script>
// element registration
Polymer({
is: "사용자정의-태그",
ready:function(e) {
// when element is ready
},
hi: function() {
alert("안녕하세요~");
},
// add properties and methods on the element's prototype
properties: {
// declare properties for the element's public API
greeting: {
type: String,
value: "Hello!"
}
}
});
</script>
Step 2: 사용될 페이지에서 요소 페이지 삽입 후, 태그로 선언
<head>
<script src="bower_components/webcomponentsjs/webcomponents.js"></script>
<link rel="import" href="./파일.html">
</head>
<body>
<사용자정의-태그></사용자정의-태그>
</body>
Topeka / More on : Built with Polymer
사용되는 웹 컴포넌트 파일들을 병합해
HTTP request를 줄일 수 있도록 해주는 도구
# 설치
$ sudo npm install -g vulcanize
# 사용
$ vulcanize 대상파일.html --inline-scripts > 결과파일.html
https://github.com/Polymer/vulcanize
다양한 웹컴포넌트 생태계
대다수의 웹컴포넌트들은
Bower*를 통한 손쉬운 설치를 제공
$ bower install 컴포넌트명
*A package manager for the web - http://bower.io/
$ bower install clock-face
$ bower install GoogleWebComponents/google-map
모질라에서 개발한 UI 웹컴포넌트
<thank-you>
고맙습니다.
</thank-you>