Skip to content

Instantly share code, notes, and snippets.

@shallwefootball
Last active March 25, 2019 08:34
Show Gist options
  • Save shallwefootball/da2ec620819820658043 to your computer and use it in GitHub Desktop.
Save shallwefootball/da2ec620819820658043 to your computer and use it in GitHub Desktop.
custom element

Custom Element

Custom Elements를 사용해야 하는 이유

커스텀엘리먼트는 개발자가 인터페이스로 정의하는 플랫폼 객체이다. 이것을 custom element prototype이라 부른다.(w3c spec)

모든 웹 개발자들이 새로운 타입의 HTML element를 정의하는 것.

  1. 새 HTML/DOM element 정의하기
  2. 다른 Element부터 확장된 element 만들기
  3. 하나의 태그에 사용자 지정 기능을 함께 논리적으로 제공하기
  4. 존재하는 DOM element의 API 확장하기

Custom Element

단순하게 생각해서 html > body<sometag></sometag>를 추가하면 에러가 발생하지 않는다.

그럼 단순하게 태그만 추가하는 것으로 custom element를 만든것일까??

아래의 콘솔을 보자

console

위에서 보듯이 <sometag></sometag>HTMLUnkownElement를 상속받는다.

<div></div>태그는?

console

오.. HTMLDivElement를 상속받았다.

이렇듯 현재 spec에 정의되어있는 엘리먼트들은 HTMLElement를 상속받지만 정의되지않는 <sometag></sometag>를 적으면 HTMLUnknownElement를 상속받고 에러는 발생하지않는다.

유효한 이름을 갖는 Element는 HTMLElement를 상속받는다. 유효하지 않는 이름을 갖는 element는 HTMLUnknownElement로 부터 상속된다. 잘 상속 받았는지 확인하는 소스

document.createElement('tabs').__proto__ === HTMLUnknownElement.prototype
document.createElement('tabs').__proto__ == HTMLElement.prototype

여기서 튀어나오는 Custom Element 명명규칙

W3C스팩에 보면 기존엘리먼트와 커스텀엘리먼트를 구별하기위해 Dash(-)가 포함되어있고 소문자인 명명규칙이있다. 그리고 몇개의 예약어들도 명명해서는 안된다 라고 나와있다. 여기에

그렇다면 Dash와 소문자로 만들어진 '그냥 단지(<just-dash></just-dash>)' 태그를 만들어서 마크업해보자

console

오잉. HTMLElement를 상속받았다. 그럼 이제 커스텀엘리먼트를 다 만든걸까??

여기서 또 튀어나오는 Unresolved elements

<x-tabs>을 페이지 상에 선언할 수 있지만 document.registerElement('x-tabs');호출 이후 훨씬 나중에 종료할 수 있다. elements가 그들의 정의로 업그레이드 되기전에 그들은 unresolved elements로 불린다. 유효한 custom element이름을 갖지만 등록되지 않은 HTML element이다.

  • 출처 : html5rocks

라고 html5rocks에서 말하고 있는데 쉽게 생각하면 Custom Element 의 명명규칙을 따르지만, register 되지않은 상태를 말한다. 아래의 표는 그 둘의 차이점을 보여준다.

이름 상속받은 parent
Unresolved element HTMLElement <x-tabs>, <my-element>, <my-awesome-app>
Unknown element HTMLUnknownElement <tabs>, <foo_bar>

그렇다면... Unresolved 와 register된 녀석을 어떻게 구별하지??

registed된 엘리먼트는 자기자신을 constructor를 갖지만 Unresolved 엘리먼트는 HTMLElementconstructor로 갖는다. - stackoverflow에서...

document.registerElement('amos-forward');
document.createElement('amos-forward').constructor
//⇒ function amos-forward() { [native code] }
document.createElement('amos-forward-not-registered').constructor
//⇒ function HTMLElement() { [native code] }

registerElements

registerElement('some-tag', {prototyope: , extends: });

  1. 첫번째 인자 : String, 작성할 Custom Element명 -> 반드시 Dash(-) 포함

    이는 parser가 일반 element들로부터 custom element를 구별할 수 있도록 하며 HTML에 새태그가 추가될때 앞으로의 호환성을 보장.

    ex)

    • <x-tag>, <my-ele>은 유효한 이름이며,
    • <tabs>, <foo_bar>는 유효하지 않음
  2. 두번째 인자 : Object, prototype정보

아래 두문장은 같음.

document.registerElement('amos-forward');
document.registerElement('amos-forward', {
	prototype: Object.create(HTMLElement.prototype)
});

var AmosMidfielder = document.registerElement('amos-midflieder'); 
document.body.appendChild(new AmosMidfielder());

변수를 소문자?? or 대문자?? var amosMidfielder? or var AmosMidfielder??

엘리먼트의 확장 (Extending Element)

prototype을 전달해 준다.

var AmosButton = document.registerElement('amos-btn', {
	prototype: Object.create(HTMLButtonElement.prototype),
	extends: 'button'
});

확장된 요소들은 type extension custom elements라 불리우며, "element X is a Y"와 같이 사용

<button is="amos-btn">amos Button</button>

Custom Element 상속받은 Custom Element의 오류 (blog 카나프)

HTML5Rocks.com에서 custom element도 상속을 해서 새로운 custom element를 만들수 있다고 하지만 오류가 발생함.

var AmosPlayer = document.registerElement('amos-player');
var amosPlayer = new AmosPlayer();

var AmosForward = document.registerElement('amos-forward', {
	prototype: amosPlayer.prototype, 
	extends: 'amos-player'
})
// Uncaught DOMException: Failed to execute 'registerElement' on 'Document': Registration failed for type 'amos-forward'. The tag name specified in 'extends' is a custom element name. Use inheritance instead.(…)

근데 요것을 해결 할 수 있는 방법이 있음

//HTMLElement의 프로토타입을 상속받는 객체를 만들고
var amosPlayerProto = Object.create(HTMLElement.prototype);

//method 정의
amosPlayerProto.kick = function () {
  return 'kick~~';
}

// 읽기전용 속성 정의
Object.defineProperty(amosPlayerProto, 'HomeColor', {value: 'red'});

//커스텀 엘리먼트를 등록할때 프로토타입을 설정한다.
var AmosPlayer = document.registerElement('amos-player', {
  prototype: amosPlayerProto
});

//상속받을 엘리먼트의 프로토타입을 AmosPlayer의 프로토타입을 상속받는다.(HTMLElement <- AmosPlayer)
var amosForwardProto = Object.create(AmosPlayer.prototype);

amosForwardProto.attack = function () {
  return 'attack!!!!!!';
}

var AmosForward = document.registerElement('amos-forward', {
  prototype: amosForwardProto
})

Object.defineProperty() - MDN

기존spec에 존재하는 엘리먼트를 extends하면 잘된다. 근데 custom으로 한것을 extends 설정을 해주면 에러가 발생한다... 안해주면 안발생하고 상속도 잘됨.. 왜그럴까???

Adding JS properties and methods

위의 상속예제에서 보듯이 메서드와 속성을 추가할수 있고 다른 방법하나 더 추가

var AmosGK = document.registerElement('amos-gk', {
	prototype: Object.create(HTMLElement.prototype, {
		keep: {
			header: function () { return '머리로 막아~~'; }
		}, 
		punching: {
			value: function () {
				alert('펀칭 해버려~~~');
			}
		}
	})
});

위의 코드가 가독성이 더 좋아보인다.

잠깐 짚고나가는 Browser-Support

현재 ie, ff, safari를 지원하지 않는것이 결정적임. 확인은 여기서

Lifecycle

콜백 발생지점
createdCallback 인스턴스가 생성될 때
attachedCallback 생성된 인스턴스가 문서에 추가될때
detachedCallback 인스턴스가 문서에서 제거될 때
attributeChangedCallback(attrName, oldVal, newVal) 속석이 변경될 때 (추가/삭제/수정)
    var amosMidfielder = Object.create(HTMLElement.prototype);

    amosMidfielder.createdCallback = function () { return console.log('create~~~~~'); }
    amosMidfielder.attachedCallback = function () { return console.log('attached~~~~'); }
    amosMidfielder.detachedCallback = function () { return console.log('detached~~~~'); }
    amosMidfielder.attributeChangedCallback = function () { return console.log('change~~~~'); }

    var AmosMidfielder = document.registerElement('amos-mid', {
      prototype: amosMidfielder
    })

특이한점은 등록되는 객체 AmosMifielder에 콜백펑션들이 붙이않고 prototype붙는다는 것이다.

instance

인스턴스화 하는 법 Referrence 참고

Referrence

@shallwefootball
Copy link
Author

custom element browser support

MDN
http://caniuse.com/#feat=custom-elements

Safari, I.E., FireFox 지원 안함..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment