html 코드를 짜다보면 <div>
들이 매우 많아 귀찮은 경우가 있다.
=> 코드가 매우 지저분해진다.
그럴 땐 여러개의 <div>
태그들을 하나의 단어로 축약할 수 있는 문법을 쓰면 된다.
=> 즉, 자주 쓰는 코드 덩어리들을 한 단어로 축약하고 싶은 충동이 든다.
=> 마치, 자주 쓰는 기능을 "함수"로 만들어서 재사용하는 것처럼...
이것을 가능하게 해주는 기능이 Web Component
라는 문법이다.
=> 간단하게 말해서, 나만의 커스텀 태그 같은 걸로 축약을 가능하게 해주는 기능!!
JS 문법은 아니고 브라우저 기본 기능 중 하나이다.
=> 그저 이 브라우저 기능을 JS로 컨트롤할 수 있는 것뿐이다.
=> 그래서, 웹을 컨트롤하기 위한 코드를 잘 짜고 싶으면, 웹 브라우저에서 제공하는 기능들을 많이 알아야지, JS 문법만을 아는 것은 무언가를 구현하는데, 한계가 있다.
=> 도구를 잘 다룬다고 냉장고 수리 잘 하는 거 아니다.
냉장고 사용법, 동작원리 같은 거를 잘 알아야 냉장고 수리를 잘 할 수 있다.
이 냉장고 동작 원리 중에 하나가 Web Component
이다.
냉장고는 브라우저를 비유한 거임!!
네이버 웹싸이트 devtool로 열어보면, 이런 식으로 되어있다.
약간의 class 문법만 알고계시면, 복잡한 html 태그들을
<pretty-card>
<grey-button>
이런 식으로 이쁘게 축약해서 사용가능하다.
customElements
라는 브라우저의 기본함수가 있다.
이것만 써놓고 시작하면, Web Components를 만들 수가 있다.
customElements.define( 작명하고 싶은 이름 , 클래스명);
위처럼 축약할 html을 정하고, 어떤 단어로 축약할지 정하면 된다.
축약하고 싶은 html 태그들은 class 형식으로 만들어서 집어넣어야 한다.
class
의 경우, 이미 정해진 틀이 있는데, 이것을 묻고따지지도 말고 그대로 갖다쓰면 된다.
class 클래스 extends HTMLElement {
connectedCallback() {
}
}
그 다음에는 class 안에 중요한 함수 하나 써주면 된다. 이것도 이름이 정해져 있기 때문에, 딱 맞게 써줘야 한다.
예를 들어, <custom-input>
이라는 태그를 하나 만들었다면, 이 커스텀 태그가 HTML에 장착이 될 때, 어떤 코드를 실행할지 적어주면 된다.
즉, connectedCallback()
안에다가는 축약한 HTML을 적어주면 된다.
this는 "인스턴스"라고 했죠?? 즉, class로부터 새로 생성될 객체를 뜻한다.
근데, 여기서는 그냥 새로 생성될 나만의 커스텀 HTML이라고 생각하면 된다.
위의 예시를 들자면, this는 <custom-input>
말로만 하면, 이해가 잘 안되니, 예시를 통해 알아보자.
다음과 같은 예제로 실습해보자!!
예를 들어서 <custom-input>
이라고 입력하면
<label><input>
이렇게 2개의 태그가 안에 출현하게 만들고 싶어진 것이다.
그럼 어떻게 코드를 짜야하는지 알아보자.
<custom-input>
같은 커스텀 태그를 이제부터 컴포넌트라고 칭한다.
컴포넌트를 만들고 싶으면 이런 형식에 따라서 그대로 타이핑만 하면 된다.
이건 정해진 문법이라 이해할 필요는 없고 따라치면 된다.
class 클래스 extends HTMLElement {
connectedCallback() {
this.innerHTML = '<label>이름을 입력하쇼</label><input>'
}
}
customElements.define("custom-input", 클래스);
<custom-input></custom-input>
위와 같은 방식으로 하는게
innerHTML
보다 html 생성속도가 10배 빨라진다.
좌우지간, 이 connectedCallback()
에 길고 복잡한 HTML을 다 집어넣으면, 내가 원할 때, 언제든 갖다쓸 수있으니까 아주 HTML 코딩 생활이 편해지겠다.
<커스텀 태그>
의 장점개발자가 다른 곳에서 마음대로 갖다가 쓸 수 있다는 뜻이다. 즉, 온갖 곳에 다 복붙해서 코드의 양을 줄일 수 있다. 일종의 함수 문법이라고 생각하면 된다.
<커스텀 태그>
안에서도 파라미터 문법 구현 가능맨날 label, input 같은 태그들만 복붙할 수 있는게 아니라,
attribute
를 파라미터처럼 활용할 수있다.
위의 경우처럼, "비번"이라고 name을 입력하면, "비번인풋이에요"라고 출력되는 커스텀 HTML을 만들 수 있다.
즉, 이렇게 만들어서 각각 다른 HTML을 상황에 맞게 생성해줄 수 있는거다.
이러면, 이제 "확장성"도 잡을 수 있음!!
그리고 이런 기능도 제공을 하는데,
name이라는 custom attribute가 변경 될 때마다, 특정 코드를 실행할 수도 있다.
참고로, React나 Vue에서는 Props가 변경되면, 그거를 사용하는 HTML도 재렌더링 되게할 수 있다. 이거랑 똑같은 기능을 만드는 거라고 보면 된다.
즉, 무슨 이유로 attribute가 바뀌면, HTML도 자동으로 업데이트 해줄 수있는 거다.
static get observedAttributes()
라는 함수에 변경을 감지하고 싶은 attribute를 배열 형식으로 집어넣는다.
몇 개를 넣어도 상관없다. ['name', 'age']
실제로 값에 변경이 일어날 때마다, attributeChangedCallback()
의 코드가 실행된다.
class 클래스 extends HTMLElement {
connectedCallback() {
let name = this.getAttribute('name');
this.innerHTML = '<label>${name}을 입력하쇼</label><input>'
}
static get observedAttributes() {
return ['name']
}
attributeChangedCallback() {
(attribute 변경시 실행할 코드)
}
}
customElements.define("custom-input", 클래스);
this.getAttribute('name')
; ??리엑트나 뷰에서도 Props가 변경이 되면, HTML이 자동으로 렌더링되는 거랑 똑같은 원리이다.
이것을 웹 컴포넌트에서도 똑같이 만들 수 있다고 생각하면 된다.
그래서, 이런 Web Components 라는 기본 기능을 갖다 쓰면, 아무리 긴 HTML 코드도 함수처럼 재사용 가능하고 재사용할 때마다, 각각 조금씩 다른 기능도 구현 가능하다.
이러면, 아무리 규모가 큰 싸이트도 확장성이 좋아진다.
근데, 실은 이런 작업들은 잘하는 라이브러리가 "리엑트"나 "뷰"같은 라이브러리들이다.
얘네들은 Web Components에서 영감을 받아서 조금 더 좋게 만든 라이브러리들이다.
그리고 Web Components보다 조금 더 다양한 기능을 제공한다.
Lit
, Stencil
등을 갖다 쓰면 되게 가볍다. class와 extend 문법 저렇게 그대로 써주시면 되고 (class명 작명가능)
안에는 connectedCallback()
이라는 함수안에
여러분의 커스텀 html을 막 꾸미면 된다.
(참고) connectedCallback()
함수는 컴포넌트가 html에 장착될 때 실행된다.
(컴포넌트 이름 작명시 보통 대시기호 넣는게 관습이다)
▲ 그럼 브라우저에서 개발자도구로 검사해보면
<custom-input>
이라고 쓸 때마다 <label> <input>
이것들이 남는다.
이것이 html을 컴포넌트로 축약해서 쓸 수 있는 Web Component 문법이다.
<custom-input>
쓸 때마다 같은 코드만 나오니까 쓸모없어보인다고?
그러면 attribute를 추가해서 쓸 때마다 각각 다른 내용을 보여줄 수도 있다.
class 클래스 extends HTMLElement {
connectedCallback() {
let name = this.getAttribute('name');
this.innerHTML = '<label>${name}을 입력하쇼</label><input>'
}
}
customElements.define("custom-input", 클래스);
<custom-input name="이메일"></custom-input>
<custom-input name="비번"></custom-input>
getAttribute(X)
를 쓰면 현재 요소의 X라고 정의된 attribute
를 가져올 수 있다.
그래서 name attribute
가 있으면 그걸 가져와서 <label>
안에 넣으라고 코드를 짜놨다.
그랬더니 <custom-input name="비번"></custom-input>
이렇게 쓰면 "비번을 입력하쇼"
<custom-input name="이메일"></custom-input>
이렇게 쓰면 "이메일을 입력하쇼"
라고 출력된다.
attribute 활용하시면 각각 다른 내용을 보여줄 수 있다.
class 클래스 extends HTMLElement {
connectedCallback() {
let name = this.getAttribute('name');
this.innerHTML = '<label>${name}을 입력하쇼</label><input>'
}
static get observedAttributes() {
return ['name']
}
attributeChangedCallback() {
(attribute 변경시 실행할 코드)
}
}
customElements.define("custom-input", 클래스);
static get observedAttributes()
안에 감시할 attribute
들을 array
로 적으면 된다.
그럼 그게 변경되는 순간 밑에 있는 attributeChangedCallback()
함수를 실행해준다.
제가 임의로 만든게 아니라 이런 함수명들이 미리 다 정해져있으니 복사해서 쓰면 된다.
그럼 React, Vue에서 제공하는 자동 html 재렌더링 기능도 쌩 자바스크립트만으로 구현할 수 있다.
attribute 변경시 html을 업데이트해주는 코드를 실행하면 끝!!
그럼 새로고침없이도 html에 변경사항을 바로바로 반영할 수 있게 된다.
근데 재렌더링 그런건 React, Vue 이런걸로 웹앱을 안만들어보셨다면 아직 알 필요는 없다.
많이들 좋아라하는 React, Vue도 똑같은 기능을 제공한다.
React도 html을 하나로 묶어서 component로 만들어서 재사용이 가능하다.
하지만 React는 웹앱을 만드는 라이브러리라 용도가 약간 다르다.
React는 state가 변할 경우 자동으로 html 재렌더링해주는 기능도 제공하고
React는 virtual DOM을 이용해서 재렌더링을 매우 빠르고 효율적으로 도와준다.
하지만 문법이 약간 더러울 뿐,
Vue는 더 정돈된 느낌이고 깔끔하다.