Introduce
ES6 ๋ช
์ธ์ ๋ณด๋ฉด Web Components๋ผ๋ ๊ฒ์ด ์ ์๋์ด ์๋ค.
์๋ ์ผ์ข
์ ๋ถ๋ฆฌ๋ DOM ์ ๋ง๋ค ์ ์๋๋ก ํ๋๋ฐ, ๋ค์๊ณผ ๊ฐ์ด ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค.
ย
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <body> <my-element>Hello</my-element> <!-- === <h1>Hello</h1> --> <script> class MyElement extends HTMLElement { constructor() { super(); const template = document.createElement('template'); template.innerHTML = '<h1><slot></slot></h1>'; this.attachShadow({ mode: 'closed' }) .append(template.content.cloneNode(true)); } } window.customElements.define( 'my-element', MyElement, ); </script> </body> </html>
ย
๊ทธ๋ฐ๋ฐ ๋ณด๋ฉด ์๊ฒ ์ง๋ง, ์ ์ฝ๋๋
innerHTML
์ ์ด์ฉํด HTML ์ฝ๋๋ฅผ ์ธ๋ผ์ธ์ผ๋ก ๋ฃ์ด์ค์ผ ํ๋ค๋ ๋ถํธํจ์ด ์๊ธฐ ๋๋ฌธ์...ย
๋ค์๊ณผ ๊ฐ์ด
xhr
์ ์ด์ฉํด ๋ถ๋ฆฌํด์ค ์๋ ์๋ค.ย
class MyElement extends HTMLElement { constructor() { super(); _connect(); } async _connect() { const rawHtml = await (await fetch(/* html src */)).text(); const template = document.createElement('template'); template.innerHTML = rawHtml; this.attachShadow({ mode: 'closed' }) .append(template.content.cloneNode(true)); } } window.customElements.define( 'my-element', MyElement, );
ย
๋ค๋ง ES6์ Class Constructor๋
async
ํ ์ ์๊ธฐ ๋๋ฌธ์์ด์ฉ ์ ์์ด ๋ฉ์๋๋ฅผ ํ๋ ์์ฑํด์ค์ผ ํ๋ค.
ย
๋ฌผ๋ก ๋ค์๊ณผ ๊ฐ์ด
then
์ ์ด์ฉํด์๋ ๊ฐ๋ฅ์ ํ๋ฐย
class MyElement extends HTMLElement { constructor() { super(); fetch(/* html src */) .then(async (resp) => await resp.text()) .then((rawHtml) => { const template = document.createElement('template'); template.innerHTML = rawHtml; this.attachShadow({ mode: 'closed' }) .append(template.content.cloneNode(true)); }); } } window.customElements.define( 'my-element', MyElement, );
ย
์ด๊ฑด ๊ทธ๋ฅ ๊ฐ์ธ์ ์ผ๋ก ๋ง์ ๋ค์ง ์์๋ค. ๊ทธ๋์ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ด ์๋ ์๊ฐํด ๋ณด์๊ณ ...
ES6์
import
๊ตฌ๋ฌธ์ด ๋ ์ฌ๋๋ค.ย
import rawHtml from './my-element.html'; // ERROR class MyElement extends HTMLElement { constructor() { super(); const template = document.createElement('template'); template.innerHTML = rawHtml; this.attachShadow({ mode: 'closed' }) .append(template.content.cloneNode(true)); } }
ย
๋๋ ์์งํ ๋ ์ค ์์๋ค. ๊ทธ๋ฐ๋ฐ ์ ์ด๋ ํ์ฌ๋ก์๋ ์ค๋ก์ง js ํ์ผ๋ง์ import ํ ์ ์๋ค๊ณ ํ๋ค.
ย
๊ทธ๋์ ๋ด๊ฐ ์๊ฐํ ๋ฐฉ๋ฒ์?
์ด์ฐจํผ ES6์
class
๋ ์ค์ ๋ก๋ ES5์ function
Class Declaration์ ์ถ์ฝํ ๊ฒ์ผ ๋ฟ์ด๋๊น...ย
class Foo { } console.log(typeof Foo); // "function"
ย
๊ทธ๋์ ๋ค์๊ณผ ๊ฐ์ ๋ชจ๋์ ํ๋ ๊ตฌํํ๋ค.
ย
/** * raw html data loader * * @param {String} src source link */ const rawHtmlLoader = async (src) => await (await fetch(src)).text(); export default async (src) => { // create a template lement const template = document.createElement('template'); // set contents template.innerHTML = await rawHtmlLoader(src); // define custom element class (es5 version for async extends) function CustomComponent() { const customComponent = Reflect.construct(HTMLElement, [], CustomComponent); // attach shadow customComponent.attachShadow({ mode: 'closed' }) .append(template.content.cloneNode(true)); // return reflected constructor return customComponent; } // set prototype CustomComponent.prototype = Object.create(HTMLElement.prototype); // return custom component element return CustomComponent; };
ย
์ ์ฝ๋๋ ๊ทธ๋ฅ ES5 ๋ฌธ๋ฒ์ผ๋ก Class๋ฅผ ๊ตฌํํ ๊ฒ์ด๊ณ ,
์ฌ๊ธฐ์ Reflection์ ์ด์ฉํด
HTMLElement
๋ฅผ extends
ํ ์ฝ๋์ด๋ค.ย
์ ์ด๋ ๊ฒ ํ๋? ๋ฐ๋ก
async
๋ฅผ ์ด์ฉํ extends
๋ฅผ ๊ตฌํํ๊ธฐ ์ํด์ ์ด๋ฐ ์ง์ ํ ๊ฒ์ด๋ค.ย
์๋ฌดํผ, ์ด ๋ชจ๋์ ํตํด ๋ค์๊ณผ ๊ฐ์ด html ํ์ฅ์๋ฅผ ๊ฐ์ง
template
์ ๋ฐ๋ก Loadํ ์ ์๋ค.๋ฌผ๋ก ์นํฉ์ด๋ ๋ญ ๊ทธ๋ฐ๊ฑฐ ์์ด Vanilla JS์์ ๋ง์ด๋ค.
ย
import loader from './loader.js'; window.addEventListener('load', async () => { window.customElements.define( 'my-element', await loader('/components/my-element.html'); ); });
<!-- /components/my-element.html --> <h1> <slot></slot> </h1> <!-- ๋ญ ์ด๋ฐ ๊ฒ๋ ๋น์ฐํ ์ฌ์ฉ ๊ฐ๋ฅ --> <style scoped> h1 { font-weight: 100; } </style>
ย
๊ฐ์ธ์ ์ผ๋ก ์ด๋ฌํ ๋ฐฉ์์ด ๋ง์์ ๋ค์๋ค. ์กฐ๊ธ ๋ ๊น๋ํ๋ค๊ณ ์๊ฐํ๋ค.
๊ทผ๋ฐ ๋ ๋ณด๋ฉด ๋ฉ๋ฆฌ ๋์์จ ๊ฒ ๊ฐ๊ธฐ๋ ํ๊ณ ... ์๋ฌดํผ ๋ญ ์์ฌ์ด ์๊ฒจ ๊ตฌํํด ๋ณธ ๋ชจ๋.
ย
GitHub์ ์ฝ๋๋ ์ฌ๋ ค๋์๋ค.
์ฐธ๊ณ ๋ก ๋ค์๊ณผ ๊ฐ์ด๋ ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค.
ย
import componentLoader from 'https://raw.githack.com/Gumball12/vanilla-component-loader/main/index.js'; window.addEventListener('load', async () => { customElements.define( 'my-element', await componentLoader('/components/my-element.html'), ); });
ย
ย
+
๋น์ฐํ ์ข ๋ ๋์ ๋ฐฉ๋ฒ์ด ์กด์ฌํ๋ค..
Vanilla JS๋ก MVVM ํ๋ ์์ํฌ๋ฅผ ๊ตฌํํด๋ณด๋ฉฐ ์๊ฒ ๋์๋๋ฐ,
๊ทธ๋ฅ ์๋ก์ด class๋ฅผ ๊ตฌํํ๋ฉด ๋์๋ ๊ฒ...
ย