๋ค์ํ ์น ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ๊ณ ์บก์ํ๋ UI ์ปดํฌ๋ํธ๋ฅผ ๊ตฌ์ถํ๊ธฐ ์ํด ์น ์ปดํฌ๋ํธ, ํนํ ์ปค์คํ ์๋ฆฌ๋จผํธ์ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ ์์๋ณด์ธ์.
์น ์ปดํฌ๋ํธ: ์ปค์คํ ์๋ฆฌ๋จผํธ ์ฌ์ธต ๋ถ์
์น ์ปดํฌ๋ํธ๋ ์น ๊ฐ๋ฐ์์ ์ค์ํ ๋ฐ์ ์ ๋ํ๋ด๋ฉฐ, ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ๊ณ ์บก์ํ๋ UI ์ปดํฌ๋ํธ๋ฅผ ๋ง๋๋ ํ์คํ๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค. ์น ์ปดํฌ๋ํธ๋ฅผ ๊ตฌ์ฑํ๋ ํต์ฌ ๊ธฐ์ ์ค์์๋, ์ปค์คํ ์๋ฆฌ๋จผํธ๋ ์ฌ์ฉ์ ์ ์ ๋์๊ณผ ๋ ๋๋ง์ ๊ฐ์ถ ์๋ก์ด HTML ํ๊ทธ๋ฅผ ์ ์ํ๋ ์ด์์ผ๋ก ๋๋๋ฌ์ง๋๋ค. ์ด ํฌ๊ด์ ์ธ ๊ฐ์ด๋์์๋ ์ปค์คํ ์๋ฆฌ๋จผํธ์ ๋ณต์ก์ฑ์ ๊น์ด ํ๊ณ ๋ค์ด, ํ๋์ ์ธ ์น ์ ํ๋ฆฌ์ผ์ด์ ๊ตฌ์ถ์ ์ํ ์ด์ , ๊ตฌํ ๋ฐ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ํ๊ตฌํฉ๋๋ค.
์น ์ปดํฌ๋ํธ๋ ๋ฌด์์ธ๊ฐ?
์น ์ปดํฌ๋ํธ๋ ๊ฐ๋ฐ์๊ฐ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ๊ณ , ์บก์ํ๋์์ผ๋ฉฐ, ์ํธ ์ด์ฉ ๊ฐ๋ฅํ HTML ์๋ฆฌ๋จผํธ๋ฅผ ๋ง๋ค ์ ์๋๋ก ํ๋ ์น ํ์ค์ ์งํฉ์ ๋๋ค. ์น ๊ฐ๋ฐ์ ๋ชจ๋์ ์ ๊ทผ ๋ฐฉ์์ ์ ๊ณตํ์ฌ, ๋ค์ํ ํ๋ก์ ํธ์ ํ๋ ์์ํฌ์์ ์ฝ๊ฒ ๊ณต์ ํ๊ณ ์ฌ์ฌ์ฉํ ์ ์๋ ๋ง์ถคํ UI ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค ์ ์๊ฒ ํฉ๋๋ค. ์น ์ปดํฌ๋ํธ์ ํต์ฌ ๊ธฐ์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ์ปค์คํ ์๋ฆฌ๋จผํธ(Custom Elements): ์๋ก์ด HTML ํ๊ทธ์ ๊ด๋ จ ๋์์ ์ ์ํฉ๋๋ค.
- ์๋ DOM(Shadow DOM): ์ปดํฌ๋ํธ๋ฅผ ์ํ ๋ณ๋์ DOM ํธ๋ฆฌ๋ฅผ ์์ฑํ์ฌ ์บก์ํ๋ฅผ ์ ๊ณตํ๊ณ , ์คํ์ผ๊ณผ ์คํฌ๋ฆฝํธ๋ฅผ ์ ์ญ ์ค์ฝํ๋ก๋ถํฐ ๋ณดํธํฉ๋๋ค.
- HTML ํ ํ๋ฆฟ(HTML Templates): ์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ์ฌ์ฉํ์ฌ ์ธ์คํด์คํํ๊ณ ์กฐ์ํ ์ ์๋ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ HTML ๊ตฌ์กฐ๋ฅผ ์ ์ํฉ๋๋ค.
์ปค์คํ ์๋ฆฌ๋จผํธ ์ดํดํ๊ธฐ
์ปค์คํ ์๋ฆฌ๋จผํธ๋ ์น ์ปดํฌ๋ํธ์ ํต์ฌ์ผ๋ก, ๊ฐ๋ฐ์๊ฐ ์์ ๋ง์ ์๋ฆฌ๋จผํธ๋ก HTML ์ดํ๋ฅผ ํ์ฅํ ์ ์๊ฒ ํด์ค๋๋ค. ์ด๋ฌํ ์ปค์คํ ์๋ฆฌ๋จผํธ๋ ํ์ค HTML ์๋ฆฌ๋จผํธ์ฒ๋ผ ๋์ํ์ง๋ง, ํน์ ์ ํ๋ฆฌ์ผ์ด์ ์๊ตฌ์ ๋ง๊ฒ ์กฐ์ ํ ์ ์์ด ๋ ํฐ ์ ์ฐ์ฑ๊ณผ ์ฝ๋ ๊ตฌ์ฑ์ ์ ๊ณตํฉ๋๋ค.
์ปค์คํ ์๋ฆฌ๋จผํธ ์ ์ํ๊ธฐ
์ปค์คํ
์๋ฆฌ๋จผํธ๋ฅผ ์ ์ํ๋ ค๋ฉด customElements.define() ๋ฉ์๋๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค. ์ด ๋ฉ์๋๋ ๋ ๊ฐ์ ์ธ์๋ฅผ ๋ฐ์ต๋๋ค:
- ์๋ฆฌ๋จผํธ ์ด๋ฆ: ์ปค์คํ
์๋ฆฌ๋จผํธ์ ์ด๋ฆ์ ๋ํ๋ด๋ ๋ฌธ์์ด์
๋๋ค. ์ด๋ฆ์ ํ์ค HTML ์๋ฆฌ๋จผํธ์์ ์ถฉ๋์ ํผํ๊ธฐ ์ํด ํ์ดํ(
-)์ ํฌํจํด์ผ ํฉ๋๋ค. ์๋ฅผ ๋ค์ด,my-element๋ ์ ํจํ ์ด๋ฆ์ด์ง๋งmyelement๋ ๊ทธ๋ ์ง ์์ต๋๋ค. - ์๋ฆฌ๋จผํธ ํด๋์ค:
HTMLElement๋ฅผ ํ์ฅํ๊ณ ์ปค์คํ ์๋ฆฌ๋จผํธ์ ๋์์ ์ ์ํ๋ ์๋ฐ์คํฌ๋ฆฝํธ ํด๋์ค์ ๋๋ค.
๋ค์์ ๊ธฐ๋ณธ์ ์ธ ์์ ์ ๋๋ค:
class MyElement extends HTMLElement {
constructor() {
super();
this.innerHTML = 'Hello, World!';
}
}
customElements.define('my-element', MyElement);
์ด ์์ ์์๋ my-element๋ผ๋ ์ด๋ฆ์ ์ปค์คํ
์๋ฆฌ๋จผํธ๋ฅผ ์ ์ํฉ๋๋ค. MyElement ํด๋์ค๋ HTMLElement๋ฅผ ํ์ฅํ๊ณ ์์ฑ์์์ ์๋ฆฌ๋จผํธ์ inner HTML์ "Hello, World!"๋ก ์ค์ ํฉ๋๋ค.
์ปค์คํ ์๋ฆฌ๋จผํธ ์๋ช ์ฃผ๊ธฐ ์ฝ๋ฐฑ
์ปค์คํ ์๋ฆฌ๋จผํธ์๋ ์๋ฆฌ๋จผํธ ์๋ช ์ฃผ๊ธฐ์ ์ฌ๋ฌ ๋จ๊ณ์์ ์ฝ๋๋ฅผ ์คํํ ์ ์๋ ๋ช ๊ฐ์ง ์๋ช ์ฃผ๊ธฐ ์ฝ๋ฐฑ์ด ์์ต๋๋ค. ์ด๋ฌํ ์ฝ๋ฐฑ์ ์๋ฆฌ๋จผํธ๋ฅผ ์ด๊ธฐํํ๊ณ , ์์ฑ ๋ณ๊ฒฝ์ ์๋ตํ๋ฉฐ, ์๋ฆฌ๋จผํธ๊ฐ DOM์์ ์ ๊ฑฐ๋ ๋ ๋ฆฌ์์ค๋ฅผ ์ ๋ฆฌํ ๊ธฐํ๋ฅผ ์ ๊ณตํฉ๋๋ค.
connectedCallback(): ์๋ฆฌ๋จผํธ๊ฐ DOM์ ์ฝ์ ๋ ๋ ํธ์ถ๋ฉ๋๋ค. ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ๋ ์ด๋ฒคํธ ๋ฆฌ์ค๋ ์ถ๊ฐ์ ๊ฐ์ ์ด๊ธฐํ ์์ ์ ์ํํ๊ธฐ ์ข์ ๊ณณ์ ๋๋ค.disconnectedCallback(): ์๋ฆฌ๋จผํธ๊ฐ DOM์์ ์ ๊ฑฐ๋ ๋ ํธ์ถ๋ฉ๋๋ค. ์ด๋ฒคํธ ๋ฆฌ์ค๋ ์ ๊ฑฐ ๋๋ ๋ฉ๋ชจ๋ฆฌ ํด์ ์ ๊ฐ์ ๋ฆฌ์์ค ์ ๋ฆฌ ์์ ์ ํ๊ธฐ์ ์ข์ ๊ณณ์ ๋๋ค.attributeChangedCallback(name, oldValue, newValue): ์๋ฆฌ๋จผํธ์ ์์ฑ์ด ๋ณ๊ฒฝ๋ ๋ ํธ์ถ๋ฉ๋๋ค. ์ด ์ฝ๋ฐฑ์ ์ฌ์ฉํ๋ฉด ์์ฑ ๋ณ๊ฒฝ์ ์๋ตํ๊ณ ์๋ฆฌ๋จผํธ์ ๋ ๋๋ง์ ๊ทธ์ ๋ง๊ฒ ์ ๋ฐ์ดํธํ ์ ์์ต๋๋ค.observedAttributes๊ฒํฐ(getter)๋ฅผ ์ฌ์ฉํ์ฌ ๊ด์ฐฐํ ์์ฑ์ ์ง์ ํด์ผ ํฉ๋๋ค.adoptedCallback(): ์๋ฆฌ๋จผํธ๊ฐ ์ ๋ฌธ์๋ก ์ด๋๋ ๋ ํธ์ถ๋ฉ๋๋ค.
๋ค์์ ์๋ช ์ฃผ๊ธฐ ์ฝ๋ฐฑ์ ์ฌ์ฉ์ ๋ณด์ฌ์ฃผ๋ ์์ ์ ๋๋ค:
class MyElement extends HTMLElement {
constructor() {
super();
this.shadow = this.attachShadow({mode: 'open'});
}
connectedCallback() {
this.shadow.innerHTML = `Connected to the DOM!
`;
console.log('Element connected');
}
disconnectedCallback() {
console.log('Element disconnected');
}
static get observedAttributes() { return ['data-message']; }
attributeChangedCallback(name, oldValue, newValue) {
if (name === 'data-message') {
this.shadow.innerHTML = `${newValue}
`;
}
}
}
customElements.define('my-element', MyElement);
์ด ์์ ์์ connectedCallback()์ ์๋ฆฌ๋จผํธ๊ฐ DOM์ ์ฐ๊ฒฐ๋ ๋ ์ฝ์์ ๋ฉ์์ง๋ฅผ ๊ธฐ๋กํ๊ณ ์๋ฆฌ๋จผํธ์ inner HTML์ ์ค์ ํฉ๋๋ค. disconnectedCallback()์ ์๋ฆฌ๋จผํธ๊ฐ ์ฐ๊ฒฐ ํด์ ๋ ๋ ๋ฉ์์ง๋ฅผ ๊ธฐ๋กํฉ๋๋ค. attributeChangedCallback()์ data-message ์์ฑ์ด ๋ณ๊ฒฝ๋ ๋ ํธ์ถ๋์ด ์๋ฆฌ๋จผํธ์ ๋ด์ฉ์ ๊ทธ์ ๋ง๊ฒ ์
๋ฐ์ดํธํฉ๋๋ค. observedAttributes ๊ฒํฐ๋ data-message ์์ฑ์ ๋ณ๊ฒฝ ์ฌํญ์ ๊ด์ฐฐํ๊ณ ์ ํจ์ ๋ช
์ํฉ๋๋ค.
์บก์ํ๋ฅผ ์ํ ์๋ DOM ์ฌ์ฉ
์๋ DOM์ ์น ์ปดํฌ๋ํธ์ ์บก์ํ๋ฅผ ์ ๊ณตํ์ฌ, ํ์ด์ง์ ๋๋จธ์ง ๋ถ๋ถ๊ณผ ๊ฒฉ๋ฆฌ๋ ์ปดํฌ๋ํธ์ฉ ๋ณ๋ DOM ํธ๋ฆฌ๋ฅผ ๋ง๋ค ์ ์๊ฒ ํฉ๋๋ค. ์ด๋ ์๋ DOM ๋ด์ ์ ์๋ ์คํ์ผ๊ณผ ์คํฌ๋ฆฝํธ๊ฐ ํ์ด์ง์ ๋๋จธ์ง ๋ถ๋ถ์ ์ํฅ์ ์ฃผ์ง ์์ผ๋ฉฐ, ๊ทธ ๋ฐ๋๋ ๋ง์ฐฌ๊ฐ์ง๋ผ๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค. ์ด ์บก์ํ๋ ์ถฉ๋์ ๋ฐฉ์งํ๊ณ ์ปดํฌ๋ํธ๊ฐ ์์ธก ๊ฐ๋ฅํ๊ฒ ๋์ํ๋๋ก ๋ณด์ฅํฉ๋๋ค.
์๋ DOM์ ์ฌ์ฉํ๋ ค๋ฉด ์๋ฆฌ๋จผํธ์์ attachShadow() ๋ฉ์๋๋ฅผ ํธ์ถํ ์ ์์ต๋๋ค. ์ด ๋ฉ์๋๋ ์๋ DOM์ ๋ชจ๋๋ฅผ ์ง์ ํ๋ ์ต์
๊ฐ์ฒด๋ฅผ ๋ฐ์ต๋๋ค. mode๋ 'open' ๋๋ 'closed'์ผ ์ ์์ต๋๋ค. ๋ชจ๋๊ฐ 'open'์ด๋ฉด ์๋ฆฌ๋จผํธ์ shadowRoot ์์ฑ์ ์ฌ์ฉํ์ฌ ์๋ฐ์คํฌ๋ฆฝํธ์์ ์๋ DOM์ ์ ๊ทผํ ์ ์์ต๋๋ค. ๋ชจ๋๊ฐ 'closed'์ด๋ฉด ์๋ฐ์คํฌ๋ฆฝํธ์์ ์๋ DOM์ ์ ๊ทผํ ์ ์์ต๋๋ค.
๋ค์์ ์๋ DOM ์ฌ์ฉ์ ๋ณด์ฌ์ฃผ๋ ์์ ์ ๋๋ค:
class MyElement extends HTMLElement {
constructor() {
super();
this.shadow = this.attachShadow({ mode: 'open' });
this.shadow.innerHTML = `
This is inside the Shadow DOM.
`;
}
}
customElements.define('my-element', MyElement);
์ด ์์ ์์๋ mode: 'open'์ผ๋ก ์๋ฆฌ๋จผํธ์ ์๋ DOM์ ์ฒจ๋ถํฉ๋๋ค. ๊ทธ๋ฐ ๋ค์ ์๋ DOM์ inner HTML์ ์ค์ ํ์ฌ ๋จ๋ฝ์ ์์์ ํ๋์์ผ๋ก ์ง์ ํ๋ ์คํ์ผ๊ณผ ์ผ๋ถ ํ
์คํธ๊ฐ ์๋ ๋จ๋ฝ ์๋ฆฌ๋จผํธ๋ฅผ ํฌํจํฉ๋๋ค. ์๋ DOM ๋ด์ ์ ์๋ ์คํ์ผ์ ์๋ DOM ๋ด์ ์๋ฆฌ๋จผํธ์๋ง ์ ์ฉ๋๋ฉฐ, ์๋ DOM ์ธ๋ถ์ ๋จ๋ฝ์๋ ์ํฅ์ ๋ฏธ์น์ง ์์ต๋๋ค.
์ปค์คํ ์๋ฆฌ๋จผํธ ์ฌ์ฉ์ ์ด์
์ปค์คํ ์๋ฆฌ๋จผํธ๋ ์น ๊ฐ๋ฐ์ ์ฌ๋ฌ ์ด์ ์ ์ ๊ณตํฉ๋๋ค:
- ์ฌ์ฌ์ฉ์ฑ: ์ปค์คํ ์๋ฆฌ๋จผํธ๋ ์ฌ๋ฌ ํ๋ก์ ํธ์ ํ๋ ์์ํฌ์์ ์ฌ์ฌ์ฉํ ์ ์์ด ์ฝ๋ ์ค๋ณต์ ์ค์ด๊ณ ์ ์ง๋ณด์์ฑ์ ํฅ์์ํต๋๋ค.
- ์บก์ํ: ์๋ DOM์ ์บก์ํ๋ฅผ ์ ๊ณตํ์ฌ ์คํ์ผ ๋ฐ ์คํฌ๋ฆฝํธ ์ถฉ๋์ ๋ฐฉ์งํ๊ณ ์ปดํฌ๋ํธ๊ฐ ์์ธก ๊ฐ๋ฅํ๊ฒ ๋์ํ๋๋ก ๋ณด์ฅํฉ๋๋ค.
- ์ํธ ์ด์ฉ์ฑ: ์ปค์คํ ์๋ฆฌ๋จผํธ๋ ์น ํ์ค์ ๊ธฐ๋ฐ์ผ๋ก ํ๋ฏ๋ก ๋ค๋ฅธ ์น ๊ธฐ์ ๋ฐ ํ๋ ์์ํฌ์ ์ํธ ์ด์ฉ์ด ๊ฐ๋ฅํฉ๋๋ค.
- ์ ์ง๋ณด์์ฑ: ์น ์ปดํฌ๋ํธ์ ๋ชจ๋์ ํน์ฑ์ ์ฝ๋ ์ ์ง๋ณด์ ๋ฐ ์ ๋ฐ์ดํธ๋ฅผ ๋ ์ฝ๊ฒ ๋ง๋ญ๋๋ค. ์ปดํฌ๋ํธ์ ๋ํ ๋ณ๊ฒฝ ์ฌํญ์ด ๊ฒฉ๋ฆฌ๋์ด ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ค๋ฅธ ๋ถ๋ถ์ ์์์ํฌ ์ํ์ ์ค์ ๋๋ค.
- ์ฑ๋ฅ: ์ปค์คํ ์๋ฆฌ๋จผํธ๋ ํ์ฑํ๊ณ ์คํํด์ผ ํ๋ ์ฝ๋์ ์์ ์ค์ฌ ์ฑ๋ฅ์ ํฅ์์ํฌ ์ ์์ต๋๋ค. ๋ํ ๋ ํจ์จ์ ์ธ ๋ ๋๋ง ๋ฐ ์ ๋ฐ์ดํธ๋ฅผ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค.
์ปค์คํ ์๋ฆฌ๋จผํธ์ ์ค์ ์์
์ปค์คํ ์๋ฆฌ๋จผํธ๋ฅผ ์ฌ์ฉํ์ฌ ์ผ๋ฐ์ ์ธ UI ์ปดํฌ๋ํธ๋ฅผ ๊ตฌ์ถํ๋ ๋ช ๊ฐ์ง ์ค์ ์์ ๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
๊ฐ๋จํ ์นด์ดํฐ ์ปดํฌ๋ํธ
์ด ์์ ๋ ์ปค์คํ ์๋ฆฌ๋จผํธ๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ๋จํ ์นด์ดํฐ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค.
class Counter extends HTMLElement {
constructor() {
super();
this.shadow = this.attachShadow({ mode: 'open' });
this._count = 0;
this.render();
}
connectedCallback() {
this.shadow.querySelector('.increment').addEventListener('click', () => {
this.increment();
});
this.shadow.querySelector('.decrement').addEventListener('click', () => {
this.decrement();
});
}
increment() {
this._count++;
this.render();
}
decrement() {
this._count--;
this.render();
}
render() {
this.shadow.innerHTML = `
${this._count}
`;
}
}
customElements.define('my-counter', Counter);
์ด ์ฝ๋๋ HTMLElement๋ฅผ ํ์ฅํ๋ Counter ํด๋์ค๋ฅผ ์ ์ํฉ๋๋ค. ์์ฑ์๋ ์ปดํฌ๋ํธ๋ฅผ ์ด๊ธฐํํ๊ณ , ์๋ DOM์ ์ฒจ๋ถํ๋ฉฐ, ์ด๊ธฐ ์นด์ดํธ๋ฅผ 0์ผ๋ก ์ค์ ํฉ๋๋ค. connectedCallback() ๋ฉ์๋๋ ์ฆ๊ฐ ๋ฐ ๊ฐ์ ๋ฒํผ์ ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ์ถ๊ฐํฉ๋๋ค. increment() ๋ฐ decrement() ๋ฉ์๋๋ ์นด์ดํธ๋ฅผ ์
๋ฐ์ดํธํ๊ณ render() ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ ์ปดํฌ๋ํธ์ ๋ ๋๋ง์ ์
๋ฐ์ดํธํฉ๋๋ค. render() ๋ฉ์๋๋ ์๋ DOM์ inner HTML์ ์ค์ ํ์ฌ ์นด์ดํฐ ๋์คํ๋ ์ด์ ๋ฒํผ์ ํฌํจ์ํต๋๋ค.
์ด๋ฏธ์ง ์บ๋ฌ์ ์ปดํฌ๋ํธ
์ด ์์ ๋ ์ปค์คํ ์๋ฆฌ๋จผํธ๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋ฏธ์ง ์บ๋ฌ์ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค. ๊ฐ๊ฒฐ์ฑ์ ์ํด ์ด๋ฏธ์ง ์์ค๋ ํ๋ ์ด์คํ๋์ด๋ฉฐ API, CMS ๋๋ ๋ก์ปฌ ์คํ ๋ฆฌ์ง์์ ๋์ ์ผ๋ก ๋ก๋๋ ์ ์์ต๋๋ค. ์คํ์ผ๋ง ๋ํ ์ต์ํ๋์์ต๋๋ค.
class ImageCarousel extends HTMLElement {
constructor() {
super();
this.shadow = this.attachShadow({ mode: 'open' });
this._images = [
'https://via.placeholder.com/350x150',
'https://via.placeholder.com/350x150/0077bb',
'https://via.placeholder.com/350x150/00bb77',
];
this._currentIndex = 0;
this.render();
}
connectedCallback() {
this.shadow.querySelector('.prev').addEventListener('click', () => {
this.prevImage();
});
this.shadow.querySelector('.next').addEventListener('click', () => {
this.nextImage();
});
}
nextImage() {
this._currentIndex = (this._currentIndex + 1) % this._images.length;
this.render();
}
prevImage() {
this._currentIndex = (this._currentIndex - 1 + this._images.length) % this._images.length;
this.render();
}
render() {
this.shadow.innerHTML = `
`;
}
}
customElements.define('image-carousel', ImageCarousel);
์ด ์ฝ๋๋ HTMLElement๋ฅผ ํ์ฅํ๋ ImageCarousel ํด๋์ค๋ฅผ ์ ์ํฉ๋๋ค. ์์ฑ์๋ ์ปดํฌ๋ํธ๋ฅผ ์ด๊ธฐํํ๊ณ , ์๋ DOM์ ์ฒจ๋ถํ๋ฉฐ, ์ด๊ธฐ ์ด๋ฏธ์ง ๋ฐฐ์ด๊ณผ ํ์ฌ ์ธ๋ฑ์ค๋ฅผ ์ค์ ํฉ๋๋ค. connectedCallback() ๋ฉ์๋๋ ์ด์ ๋ฐ ๋ค์ ๋ฒํผ์ ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ์ถ๊ฐํฉ๋๋ค. nextImage() ๋ฐ prevImage() ๋ฉ์๋๋ ํ์ฌ ์ธ๋ฑ์ค๋ฅผ ์
๋ฐ์ดํธํ๊ณ render() ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ ์ปดํฌ๋ํธ์ ๋ ๋๋ง์ ์
๋ฐ์ดํธํฉ๋๋ค. render() ๋ฉ์๋๋ ์๋ DOM์ inner HTML์ ์ค์ ํ์ฌ ํ์ฌ ์ด๋ฏธ์ง์ ๋ฒํผ๋ค์ ํฌํจ์ํต๋๋ค.
์ปค์คํ ์๋ฆฌ๋จผํธ ์์ ๋ชจ๋ฒ ์ฌ๋ก
๋ค์์ ์ปค์คํ ์๋ฆฌ๋จผํธ๋ก ์์ ํ ๋ ๋ฐ๋ผ์ผ ํ ๋ช ๊ฐ์ง ๋ชจ๋ฒ ์ฌ๋ก์ ๋๋ค:
- ์ค๋ช ์ ์ธ ์๋ฆฌ๋จผํธ ์ด๋ฆ ์ฌ์ฉ: ์ปดํฌ๋ํธ์ ๋ชฉ์ ์ ๋ช ํํ๊ฒ ๋ํ๋ด๋ ์๋ฆฌ๋จผํธ ์ด๋ฆ์ ์ ํํ์ธ์.
- ์บก์ํ๋ฅผ ์ํด ์๋ DOM ์ฌ์ฉ: ์๋ DOM์ ์คํ์ผ ๋ฐ ์คํฌ๋ฆฝํธ ์ถฉ๋์ ๋ฐฉ์งํ๊ณ ์ปดํฌ๋ํธ๊ฐ ์์ธก ๊ฐ๋ฅํ๊ฒ ๋์ํ๋๋ก ๋์ต๋๋ค.
- ์๋ช ์ฃผ๊ธฐ ์ฝ๋ฐฑ์ ์ ์ ํ๊ฒ ์ฌ์ฉ: ์๋ช ์ฃผ๊ธฐ ์ฝ๋ฐฑ์ ์ฌ์ฉํ์ฌ ์๋ฆฌ๋จผํธ๋ฅผ ์ด๊ธฐํํ๊ณ , ์์ฑ ๋ณ๊ฒฝ์ ์๋ตํ๋ฉฐ, ์๋ฆฌ๋จผํธ๊ฐ DOM์์ ์ ๊ฑฐ๋ ๋ ๋ฆฌ์์ค๋ฅผ ์ ๋ฆฌํ์ธ์.
- ์ค์ ์ ์ํด ์์ฑ ์ฌ์ฉ: ์์ฑ์ ์ฌ์ฉํ์ฌ ์ปดํฌ๋ํธ์ ๋์๊ณผ ๋ชจ์์ ๊ตฌ์ฑํ์ธ์.
- ํต์ ์ ์ํด ์ด๋ฒคํธ ์ฌ์ฉ: ์ปดํฌ๋ํธ ๊ฐ ํต์ ์ ์ํด ์ปค์คํ ์ด๋ฒคํธ๋ฅผ ์ฌ์ฉํ์ธ์.
- ํด๋ฐฑ(fallback) ๊ฒฝํ ์ ๊ณต: ์น ์ปดํฌ๋ํธ๋ฅผ ์ง์ํ์ง ์๋ ๋ธ๋ผ์ฐ์ ๋ฅผ ์ํด ํด๋ฐฑ ๊ฒฝํ์ ์ ๊ณตํ๋ ๊ฒ์ ๊ณ ๋ คํ์ธ์. ์ด๋ ์ ์ง์ ํฅ์(progressive enhancement)์ ์ฌ์ฉํ์ฌ ์ํํ ์ ์์ต๋๋ค.
- ๊ตญ์ ํ(i18n) ๋ฐ ํ์งํ(l10n) ๊ณ ๋ ค: ์น ์ปดํฌ๋ํธ๋ฅผ ๊ฐ๋ฐํ ๋, ๋ค๋ฅธ ์ธ์ด์ ์ง์ญ์์ ์ด๋ป๊ฒ ์ฌ์ฉ๋ ์ง ๊ณ ๋ คํ์ธ์. ์ปดํฌ๋ํธ๋ฅผ ์ฝ๊ฒ ๋ฒ์ญํ๊ณ ํ์งํํ ์ ์๋๋ก ์ค๊ณํ์ญ์์ค. ์๋ฅผ ๋ค์ด, ๋ชจ๋ ํ ์คํธ ๋ฌธ์์ด์ ์ธ๋ถํํ๊ณ ๋์ ์ผ๋ก ๋ฒ์ญ์ ๋ก๋ํ๋ ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํ์ธ์. ๋ ์ง ๋ฐ ์๊ฐ ํ์, ํตํ ๊ธฐํธ ๋ฐ ๊ธฐํ ์ง์ญ ์ค์ ์ด ์ฌ๋ฐ๋ฅด๊ฒ ์ฒ๋ฆฌ๋๋์ง ํ์ธํ์ญ์์ค.
- ์ ๊ทผ์ฑ(a11y) ๊ณ ๋ ค: ์น ์ปดํฌ๋ํธ๋ ์ฒ์๋ถํฐ ์ ๊ทผ์ฑ์ ์ผ๋์ ๋๊ณ ์ค๊ณ๋์ด์ผ ํฉ๋๋ค. ๋ณด์กฐ ๊ธฐ์ ์ ์๋ฏธ๋ก ์ ์ ๋ณด๋ฅผ ์ ๊ณตํ๊ธฐ ์ํด ํ์ํ ๊ฒฝ์ฐ ARIA ์์ฑ์ ์ฌ์ฉํ์ญ์์ค. ํค๋ณด๋ ํ์์ด ์๋ฒฝํ๊ฒ ์ง์๋๊ณ ์๊ฐ ์ฅ์ ๊ฐ ์๋ ์ฌ์ฉ์๋ฅผ ์ํด ์์ ๋๋น๊ฐ ์ถฉ๋ถํ์ง ํ์ธํ์ญ์์ค. ์คํฌ๋ฆฐ ๋ฆฌ๋๋ก ์ปดํฌ๋ํธ๋ฅผ ํ ์คํธํ์ฌ ์ ๊ทผ์ฑ์ ํ์ธํ์ญ์์ค.
์ปค์คํ ์๋ฆฌ๋จผํธ์ ํ๋ ์์ํฌ
์ปค์คํ ์๋ฆฌ๋จผํธ๋ ๋ค๋ฅธ ์น ๊ธฐ์ ๋ฐ ํ๋ ์์ํฌ์ ์ํธ ์ด์ฉ ๊ฐ๋ฅํ๋๋ก ์ค๊ณ๋์์ต๋๋ค. React, Angular, Vue.js์ ๊ฐ์ ์ธ๊ธฐ ์๋ ํ๋ ์์ํฌ์ ํจ๊ป ์ฌ์ฉํ ์ ์์ต๋๋ค.
React์์ ์ปค์คํ ์๋ฆฌ๋จผํธ ์ฌ์ฉํ๊ธฐ
React์์ ์ปค์คํ ์๋ฆฌ๋จผํธ๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ๋ค๋ฅธ HTML ์๋ฆฌ๋จผํธ์ฒ๋ผ ๋ ๋๋งํ๋ฉด ๋ฉ๋๋ค. ๊ทธ๋ฌ๋ ๊ธฐ๋ณธ DOM ์๋ฆฌ๋จผํธ์ ์ ๊ทผํ๊ณ ์ง์ ์ํธ ์์ฉํ๊ธฐ ์ํด ref๋ฅผ ์ฌ์ฉํด์ผ ํ ์๋ ์์ต๋๋ค.
import React, { useRef, useEffect } from 'react';
function MyComponent() {
const myElementRef = useRef(null);
useEffect(() => {
if (myElementRef.current) {
// Access the custom element's API
myElementRef.current.addEventListener('custom-event', (event) => {
console.log('Custom event received:', event.detail);
});
}
}, []);
return ;
}
export default MyComponent;
์ด ์์ ์์๋ ref๋ฅผ ์ฌ์ฉํ์ฌ my-element ์ปค์คํ
์๋ฆฌ๋จผํธ์ ์ ๊ทผํ๊ณ ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ์ถ๊ฐํฉ๋๋ค. ์ด๋ฅผ ํตํด ์ปค์คํ
์๋ฆฌ๋จผํธ์์ ๋์คํจ์น๋ ์ปค์คํ
์ด๋ฒคํธ๋ฅผ ์์ ํ๊ณ ๊ทธ์ ๋ฐ๋ผ ์๋ตํ ์ ์์ต๋๋ค.
Angular์์ ์ปค์คํ ์๋ฆฌ๋จผํธ ์ฌ์ฉํ๊ธฐ
Angular์์ ์ปค์คํ
์๋ฆฌ๋จผํธ๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด Angular๊ฐ ์ปค์คํ
์๋ฆฌ๋จผํธ๋ฅผ ์ธ์ํ๋๋ก ๊ตฌ์ฑํด์ผ ํฉ๋๋ค. ์ด๋ ๋ชจ๋์ ๊ตฌ์ฑ์์ schemas ๋ฐฐ์ด์ ์ปค์คํ
์๋ฆฌ๋จผํธ๋ฅผ ์ถ๊ฐํ์ฌ ์ํํ ์ ์์ต๋๋ค.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class AppModule { }
์ปค์คํ ์๋ฆฌ๋จผํธ๊ฐ ๋ฑ๋ก๋๋ฉด Angular ํ ํ๋ฆฟ์์ ๋ค๋ฅธ HTML ์๋ฆฌ๋จผํธ์ฒ๋ผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
Vue.js์์ ์ปค์คํ ์๋ฆฌ๋จผํธ ์ฌ์ฉํ๊ธฐ
Vue.js ๋ํ ๊ธฐ๋ณธ์ ์ผ๋ก ์ปค์คํ ์๋ฆฌ๋จผํธ๋ฅผ ์ง์ํฉ๋๋ค. ํน๋ณํ ๊ตฌ์ฑ ์์ด ํ ํ๋ฆฟ์์ ์ง์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
Vue๋ ์๋์ผ๋ก ์ปค์คํ ์๋ฆฌ๋จผํธ๋ฅผ ์ธ์ํ๊ณ ์ฌ๋ฐ๋ฅด๊ฒ ๋ ๋๋งํฉ๋๋ค.
์ ๊ทผ์ฑ ๊ณ ๋ ค์ฌํญ
์ปค์คํ ์๋ฆฌ๋จผํธ๋ฅผ ๊ตฌ์ถํ ๋, ์ฅ์ ๊ฐ ์๋ ์ฌ๋๋ค์ ํฌํจํ ๋ชจ๋ ์ฌ๋์ด ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ ์ ์๋๋ก ์ ๊ทผ์ฑ์ ๊ณ ๋ คํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ๋ค์์ ๋ช ๊ฐ์ง ์ฃผ์ ์ ๊ทผ์ฑ ๊ณ ๋ ค์ฌํญ์ ๋๋ค:
- ์๋งจํฑ HTML: ๊ฐ๋ฅํ ๋๋ง๋ค ์๋งจํฑ HTML ์๋ฆฌ๋จผํธ๋ฅผ ์ฌ์ฉํ์ฌ ์ปดํฌ๋ํธ์ ์๋ฏธ ์๋ ๊ตฌ์กฐ๋ฅผ ์ ๊ณตํ์ธ์.
- ARIA ์์ฑ: ARIA ์์ฑ์ ์ฌ์ฉํ์ฌ ์คํฌ๋ฆฐ ๋ฆฌ๋์ ๊ฐ์ ๋ณด์กฐ ๊ธฐ์ ์ ์ถ๊ฐ์ ์ธ ์๋ฏธ๋ก ์ ์ ๋ณด๋ฅผ ์ ๊ณตํ์ธ์.
- ํค๋ณด๋ ํ์: ์ปดํฌ๋ํธ๊ฐ ํค๋ณด๋๋ฅผ ์ฌ์ฉํ์ฌ ํ์๋ ์ ์๋๋ก ๋ณด์ฅํ์ธ์. ์ด๋ ๋ฒํผ ๋ฐ ๋งํฌ์ ๊ฐ์ ๋ํํ ์๋ฆฌ๋จผํธ์ ํนํ ์ค์ํฉ๋๋ค.
- ์์ ๋๋น: ์๊ฐ ์ฅ์ ๊ฐ ์๋ ์ฌ๋๋ค์ด ํ ์คํธ๋ฅผ ์ฝ์ ์ ์๋๋ก ํ ์คํธ์ ๋ฐฐ๊ฒฝ์ ์ฌ์ด์ ์ถฉ๋ถํ ์์ ๋๋น๊ฐ ์๋์ง ํ์ธํ์ธ์.
- ์ด์ ๊ด๋ฆฌ: ์ฌ์ฉ์๊ฐ ์ปดํฌ๋ํธ๋ฅผ ์ฝ๊ฒ ํ์ํ ์ ์๋๋ก ์ด์ ์ ์ฌ๋ฐ๋ฅด๊ฒ ๊ด๋ฆฌํ์ธ์.
- ๋ณด์กฐ ๊ธฐ์ ๋ก ํ ์คํธํ๊ธฐ: ์คํฌ๋ฆฐ ๋ฆฌ๋์ ๊ฐ์ ๋ณด์กฐ ๊ธฐ์ ๋ก ์ปดํฌ๋ํธ๋ฅผ ํ ์คํธํ์ฌ ์ ๊ทผ์ฑ์ ํ์ธํ์ธ์.
๊ตญ์ ํ ๋ฐ ํ์งํ
์ ์ธ๊ณ ์ฌ์ฉ์๋ฅผ ์ํ ์ปค์คํ ์๋ฆฌ๋จผํธ๋ฅผ ๊ฐ๋ฐํ ๋๋ ๊ตญ์ ํ(i18n)์ ํ์งํ(l10n)๋ฅผ ๊ณ ๋ คํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ๋ค์์ ๋ช ๊ฐ์ง ์ฃผ์ ๊ณ ๋ ค์ฌํญ์ ๋๋ค:
- ํ ์คํธ ๋ฐฉํฅ: ์ผ์ชฝ์์ ์ค๋ฅธ์ชฝ(LTR) ๋ฐ ์ค๋ฅธ์ชฝ์์ ์ผ์ชฝ(RTL) ํ ์คํธ ๋ฐฉํฅ์ ๋ชจ๋ ์ง์ํ์ธ์.
- ๋ ์ง ๋ฐ ์๊ฐ ํ์: ๋ค๋ฅธ ๋ก์ผ์ผ์ ๋ง๋ ์ ์ ํ ๋ ์ง ๋ฐ ์๊ฐ ํ์์ ์ฌ์ฉํ์ธ์.
- ํตํ ๊ธฐํธ: ๋ค๋ฅธ ๋ก์ผ์ผ์ ๋ง๋ ์ ์ ํ ํตํ ๊ธฐํธ๋ฅผ ์ฌ์ฉํ์ธ์.
- ๋ฒ์ญ: ์ปดํฌ๋ํธ์ ๋ชจ๋ ํ ์คํธ ๋ฌธ์์ด์ ๋ํ ๋ฒ์ญ์ ์ ๊ณตํ์ธ์.
- ์ซ์ ์์: ๋ค๋ฅธ ๋ก์ผ์ผ์ ๋ง๋ ์ ์ ํ ์ซ์ ์์์ ์ฌ์ฉํ์ธ์.
๊ฒฐ๋ก
์ปค์คํ ์๋ฆฌ๋จผํธ๋ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ๊ณ ์บก์ํ๋ UI ์ปดํฌ๋ํธ๋ฅผ ๊ตฌ์ถํ๊ธฐ ์ํ ๊ฐ๋ ฅํ ๋๊ตฌ์ ๋๋ค. ์ฌ์ฌ์ฉ์ฑ, ์บก์ํ, ์ํธ ์ด์ฉ์ฑ, ์ ์ง๋ณด์์ฑ ๋ฐ ์ฑ๋ฅ์ ํฌํจํ์ฌ ์น ๊ฐ๋ฐ์ ์ฌ๋ฌ ์ด์ ์ ์ ๊ณตํฉ๋๋ค. ์ด ๊ฐ์ด๋์ ์ค๋ช ๋ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๋ฐ๋ฅด๋ฉด, ์ปค์คํ ์๋ฆฌ๋จผํธ๋ฅผ ํ์ฉํ์ฌ ๊ฒฌ๊ณ ํ๊ณ ์ ์ง๋ณด์ ๊ฐ๋ฅํ๋ฉฐ ์ ์ธ๊ณ ์ฌ์ฉ์๊ฐ ์ ๊ทผํ ์ ์๋ ํ๋์ ์ธ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ ์ ์์ต๋๋ค. ์น ํ์ค์ด ๊ณ์ ๋ฐ์ ํจ์ ๋ฐ๋ผ, ์ปค์คํ ์๋ฆฌ๋จผํธ๋ฅผ ํฌํจํ ์น ์ปดํฌ๋ํธ๋ ๋ชจ๋์์ด๊ณ ํ์ฅ ๊ฐ๋ฅํ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ง๋๋ ๋ฐ ์ ์ ๋ ์ค์ํด์ง ๊ฒ์ ๋๋ค.
ํ ๋ฒ์ ํ๋์ ์ปดํฌ๋ํธ๋ก ์น์ ๋ฏธ๋๋ฅผ ๊ตฌ์ถํ๊ธฐ ์ํด ์ปค์คํ ์๋ฆฌ๋จผํธ์ ํ์ ๋ฐ์๋ค์ด์ธ์. ์ปดํฌ๋ํธ๊ฐ ๋ชจ๋ ๊ณณ์ ๋ชจ๋ ์ฌ๋์ด ์ฌ์ฉํ ์ ์๋๋ก ์ ๊ทผ์ฑ, ๊ตญ์ ํ ๋ฐ ํ์งํ๋ฅผ ๊ณ ๋ คํ๋ ๊ฒ์ ์์ง ๋ง์ญ์์ค.