lit은 빠르고 가벼운 web components를 구축하기 위한 간단한 라이브러리
(lit 라이브러리 사용해서 web component 쉬운 문법으로 구현 (like 과거 polymer))
lit의 구성 요소는 표준 web component, 각 lit 컴포넌트는 UI의 독립형 단위
Lit 구성 요소는 HTML 요소이므로 모든 표준 요소 API를 가지고 있음
주요 기능
두가지 주요 API
Lit으로 앱 구축 시 장점
// Import lit-html
import {html, render} from 'lit-html';
// Define a template
const myTemplate = (name) => html`<p>Hello ${name}</p>`;
// Render the template to the document
render(myTemplate('World'), document.body);
classMap
styleMap : 인라인스타일
when : 삼항식
choose : switch
map : repeat보다 작고 빠름
repeat : 키 함수를 사용하지 않는다면 map 과 유사하므로 map 사용 권장
join
range : index로 반복문 돌림
ifDefined : attribute 값이 undefined 나 null 이면 속성 자체를 제거
decorator | customElements.define()
LitElement는 ReactiveElement, HTMLElement 를 상속함
https://lit.dev/docs/components/rendering
render() 메소드에 템플릿 작성
render 메소드에는 모든 JavaScript 포함 가능
렌더가능한 값
https://lit.dev/docs/components/rendering/#composing-templates 진행중 ing
https://lit.dev/docs/components/properties
Lit 구성 요소는 입력을 수신하고 상태를 JavaScript 클래스 필드 또는 속성으로 저장합니다.
반응형 속성은 변경 시 반응형 업데이트 주기를 트리거하고 구성 요소를 다시 렌더링하며 선택적으로 특성에 읽거나 쓸 수 있는 속성입니다.
public properties
: 컴포넌트의 public API
: 보통 public은 입력으로 처리
: 사용자 입력의 반응을 제외하고 컴포넌트의 public 속성을 바꾸면 안됨
(사용자 입력으로 public 속성 바뀔 시 속성 변경에 대한 이벤트를 내보내야(dispatch)함)
@state
_속성명
속성 변경으로 인해 구성 요소가 템플릿을 다시 렌더링하는 반응형 업데이트 주기가 트리거될 수 있습니다.
property가 변하면 아래 과정이 순차적으로 일어난다.
1. property의 setter 호출
2. setter는 컴포넌트의 requestUpdate 메소드 호출
3. property의 이전값과 새로운값이 비교됨
개체 또는 어레이 속성이 변하는 경우
개체 또는 어레이 속성을 변환하는 경우 개체 자체가 변경되지 않았기 때문에 업데이트가 트리거되지 않습니다.
불변 객체와 함께 하향식 데이터 흐름이 가장 좋음
새 값을 렌더링해야 하는 모든 구성 요소가 변경되지 않은 데이터 트리의 일부는 해당 구성 요소에 의존하는 구성 요소를 업데이트하지 않으므로 가능한 한 효율적으로 수행됩니다.
데이터를 직접 변환하고 업데이트 요청을 호출하는 건 고급 사용 사례(변환된 데이터를 사용하는 모든 구성 요소 식별하고 각 구성 요소를 찾아 업데이트 요청해야함, 관리 어려움)
https://lit.dev/docs/components/properties/#attributes 진행중 ing
컴포넌트의 shadow root 아래의 shadow dom 에만 스타일이 적용 됨
정적 스타일 클래스 필드
CSS의 모든 표현식은 한 번 평가된 후 모든 인스턴스에 재사용됩니다.
super class의 스타일 상속 가능
지정된 스타일 내보내는 모듈 생성하여 스타일 공유 가능
쉐도우돔 스타일링
:host
셀렉터 : 쉐도우 트리를 소유하는 호스트 요소 (컴포넌트 가장 상위):host
, :host()
는 섀도 트리 외부의 스타일에도 영향을 받을 수 있으<slot>
요소를 포함해야 함스타일을 추가하는 다른 방법 (lit 템플릿에 스타일을 정의해야할 때) (2가지)
1. <style></style>
요소 추가
1,2 방법 모두 webcomponents/polyfills - shadyCSS 사용 시 제한되는 부분이 있음
https://github.com/webcomponents/polyfills/tree/master/packages/shadycss#limitations
동적으로 인스턴스에 클래스, 인라인 스타일 적용하기
classMap, styleMap (Built-in directives)
(https://lit.dev/docs/templates/directives/)
Theming
커스텀 웹 컴포넌트 위에 스타일 적용 (my-element 태그 CSS 선택자 사용)
lit-html에서 saas 사용하기?
https://stackoverflow.com/questions/61221405/lit-element-unable-to-load-scss-into-lit-element
lit components 는 custom element 라이프사이클 메소드를 사용한다.
반응형 속성이 변경될 때 DOM에 변경사항을 렌더링하는 반응형 업데이트 주기를 도입한다.
custom element 라이프사이클 mdn
표준 사용자 지정 요소 수명 주기 메서드를 사용자 지정해야 하는 경우 표준 Lit 기능이 유지되도록 슈퍼 구현(예: super.connectedCallback())을 호출해야 합니다.
constructor()
element가 생성되거나 업그레이드(요소가 이미 DOM에 있는 이후에 사용자 지정 요소에 대한 정의가 로드되는 경우)될때 호출
requestUpdate() 메서드를 사용하여 비동기 업데이트를 요청하여 Lit 구성 요소가 업그레이드되면 즉시 업데이트를 수행합니다.
connectedCallback()
컴포넌트가 document에 붙었을때 호출(shadowRoot 생성 보장)
요소 외부의 노드에 이벤트 수신기를 추가
일반적으로 connectedCallback()에서 수행한 모든 작업은 요소의 연결이 끊겼을 때 취소되어야 합니다. (메모리 누수를 방지하기 위해 창에서 이벤트 리스너를 제거해야 함)
disconnctedCallback()
컴포넌트가 document에서 지워졌을 때 호출
반응형 업데이트 주기를 일시 중지합니다. 요소가 연결되면 다시 시작됩니다.
외부 이벤트 리스너 제거 (내부 이벤트 리스너는 제거할 필요 없음)
attributeCahngedCallback()
요소의 observedAttributes 중 하나가 변경될때 호출
lit은 이 콜백을 사용하여 속성의 변경사항을 반응형 속성에 동기화 (자동진행)
이 콜백을 구현할 필요가 거의 없습니다.
adoptedCallback()
component가 새 문서로 이동될 때 호출
lit은 이 콜백에 대한 동작이 없음
이 콜백은 문서를 변경할 때 요소 동작이 변경되어야 하는 고급 사용 사례에만 사용해야 합니다.
[reactive update cycle]
표준 사용자 지정 요소 수명 주기 외에도 Lit 구성 요소는 사후 업데이트 주기도 구현합니다.
반응형 업데이트 주기는 반응형 속성이 변경되거나 requestUpdate() 메서드가 명시적으로 호출될 때 트리거됩니다. Lit는 비동기식으로 업데이트를 수행하여 속성 변경사항이 일괄 처리되도록 합니다. 업데이트가 요청된 후 업데이트가 시작되기 전에 더 많은 속성이 변경되면 모든 변경사항이 동일한 업데이트에 캡처됩니다.
업데이트는 마이크로 태스크 타이밍에 발생합니다. 즉, 업데이트는 브라우저가 화면에 다음 프레임을 그리기 전에 발생합니다. 브라우저 타이밍에 대한 자세한 내용은 Jake Archibald의 마이크로 태스크 기사 참조(https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/)
1. 하나 또는 그 이상의 프로퍼티가 변경되거나 requestUpdate()가 호출 될 때 업데이트가 예약됩니다.
2. 업데이트는 다음 프레임이 페인트 되기전에 수행됩니다.
https://lit.dev/docs/components/lifecycle/#changed-properties 진행중
lit components 는 shadow DOM을 사용하여 DOM을 캡슐화 함
분리되고 캡슐화된 별도의 DOM 트리를 요소에 추가
장점
document.querySelector
로 shadow DOM 요소 찾을 수 없으므로 글로벌 스크립트가 component 를 깰 수 없음레거시 브라우저 지원
lit의 polyfill-support
모듈 다운로드
Lit 은 기본적으로 shadow root 인 renderRoot
에 component를 렌더링 한다.
내부 요소를 찾으려면 this.renderRoot.querySelector()
같은 DOM 쿼리 API를 사용한다.
renderRoot
는 항상 .querySelectorAll()
과 .children
과 같은 API를 공유하는 shadow root 또는 요소여야 한다.
component 초기 렌더링 후에(ex. firstUpdated) 내부 DOM을 쿼리하거나 getter 패턴을 사용할 수 있다.
(@query, @queryAll, @queryAsync 데코레이터 사용도 가능)
@queryAsync
: updateComplete promise를 기다리는 대신 이것을 사용 가능
: @queryAsync에서 반환한 노드가 다른 속성 변경으로 인해 변경될 수 있는 경우에 유용
하나 또는 그 이상의 요소를 포함해야함 자식 노드의 placeholder와 같은 역할
자식은 DOM tree 를 이동하지않고 의 자식처럼 렌더링 된다.
slotchange
이벤트와 함께 slot.assignedNodes
, slot.assignedElements
메소드 사용 가능
Lit component는 렌더 루트(내부 DOM의 컨테이너 역할을 하는 DOM 노드) (기본 shadowRoot)가 있다.
Lit Element 에는 이 렌더 루트를 아래 두 방법으로 커스텀할 수 있다.
참고
Lit 요소는 사용자 정의 이벤트를 디스패치할 수 있습니다. (ex. 메뉴 요소는 이벤트를 발송하여 선택한 항목이 변경되었음을 나타낼 수 있으며, 팝업 요소는 팝업을 열거나 닫을 때 이벤트를 발송할 수 있습니다.)
decorators를 사용하지 않는 경우 객체를 이벤트 리스너 식으로 전달하여 이벤트 리스너 옵션을 사용자 정의할 수 있습니다. 개체에는 handleEvent() 메서드가 있어야 하며 EventListener()를 추가하기 위한 options 인수에 일반적으로 나타나는 옵션을 포함할 수 있습니다.
Adding event listeners to the component or its shadow root
component constructor는 components에 이벤트리스너를 추가하기 좋은 곳임
구성 요소 자체에 이벤트 수신기를 추가하는 것은 이벤트 위임의 한 형태(코드를 줄이거나 성능을 향상시키기 위해 수행할 수 있음, 이벤트 처리를 중앙 집중화 하여 코드 줄일 수 있음, 버블이 발생하는 이벤트만 처리 가능)
그러나 component의 shadow dom에서 발생한 이벤트는 component의 이벤트 리스너가 이벤트를 수신할 때 대상이 다지 지정된다. 대상을 다시 지정하면 이벤트 위임이 방해될 수 있으며 이를 방지하기위해서 이벤트 수신기를 component의 shadow dom 자체에 추가할 수도 있습니다. constructor에서는 shadowRoot 에 접근할 수 없기에 createRenderRoot
메서드에 이벤트 수신기를 추가할 수 있다. createRenderRoot
에서 shodow root를 반환하는 것 이 중요하다.
다른 요소(window, document 등)에 이벤트 리스너 추가
구성 요소가 이벤트 리스너를 자신 또는 템플릿으로 지정된 DOM(ex. window, document 또는 기본 DOM의 일부 요소)을 제외한 다른 항목에 추가하는 경우, connectedCallback()에서 이벤트 리스너를 추가하고 disconnectedCallback() 에서 제거해야 함
이벤트 리스너에서의 this
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
인스턴스 or 컴포넌트
반복되는 항목의 이벤트를 들을 때 이벤트가 거품이 일 경우 이벤트 위임을 사용하는 것이 편리한 경우가 많습니다.
모든 DOM 노드는 dispatchEvent
메소드를 이용해 이벤트를 디스패치 할 수 있다.
event type, options을 지정해 event instance 생성 후 dispatchEvent에 전달한다.
bubble 옵션 : 이벤트가 DOM 트리에서 디스패치 요소의 상위로 이동할 수 있다. 이벤트가 이벤트 위임에 참여할 수 있도록 하려면 이 플래그를 설정하는게 중요 함
composed 옵션 : shadow dom tree 를 넘어서 이벤트를 디스패치 할 수 있도록 설정
https://lit.dev/docs/components/events/#when-to-dispatch-an-event 진행중 ing
표준 이벤트 시스템과 다른 몇가지를 이해하는 것이 중요
shadow dom은 'shadow'요소에 대한 세부 정보를 캡슐화 하는 dom의 범위 지정 메커니즘을 제공하기 위해 존재 한다.
shadow dom의 이벤트는 외부 dom 요소에서 특정 세부 정보를 캡슐화 한다.
shadow root 내부에 디스패치된 이벤트는 해당 shadow root 외부에 표시되지 않는다. 이벤트가 shadow dom 경계를 통과하도록 하려면 composed 프로퍼티를 true로 설정해야 한다. dom 트리의 모든 노드가 이벤트를 볼 수 있도록 composed 와 bubbles가 쌍을 이루는 것이 일반적이다.
예시 코드 아래 inging
https://lit.dev/docs/components/decorators
데코레이터는 제안된 자바스크립트 기능이므로 데코레이터를 사용하려면 Babel이나 TypeScript와 같은 컴파일러를 사용해야 합니다.
2가지 방법
https://stackoverflow.com/questions/68988650/how-to-add-a-scss-stylesheet-to-a-lit-web-component
npm i -D lit-scss-loader extract-loader
module.exports = {
entry: './src/index.js',
module: {
rules: [
{
test: /\.css|\.s(c|a)ss$/,
use: [{
loader: 'lit-scss-loader',
options: {
minify: true, // defaults to false
},
}, 'extract-loader', 'css-loader', 'sass-loader'],
},
],
},
};
unsafeCSS
static get styles() {
return css`${unsafeCSS(styles)}`;
}
공통 스타일 파일 분리
@use
사용
https://stackoverflow.com/questions/17598996/sass-use-variables-across-multiple-files
결론: global, reset css 를 컴포넌트 마다의 스타일로 적용해줘야 함
https://stackoverflow.com/questions/57706814/lit-element-how-do-i-set-global-reset-css
LitElement는 기본적으로 외부 CSS가 구성 요소의 내부 트리에 영향을 미치지 않도록 설계된 Shadow DOM을 사용하기 때문에 예상대로 작동하지 않습니다.
web components 내부의 스타일에 영향을 미치는 유일한 방법은 components 가 CSS 변수를 사용하거나 스타일을 상속하는 속성이 web component 내부에서 정의되지 않은 경우입니다. ( lit docs - CSS inheritance )
https://github.com/lit/lit/issues/1645 (21년 12월)
https://stackoverflow.com/questions/55126694/how-to-create-litelement-without-shadow-dom
createRenderRoot를 사용하면 섀도 루트를 생성하는 작업을 재정의할 수 있습니다. 일반적으로 라이트덤에 렌더링할 때 사용합니다.
createRenderRoot() {
return this;
}
but 섀도 DOM을 사용하는 것을 정말 추천합니다.
요소가 light dom으로 덮어써지면 합성이 어렵습니다.
각 구성요소에 필요한 부품만 가져올 수 있도록 스타일시트를 세분화하는 것이 이상적입니다. 나는 그 부품들이 자동적으로 부품들과 함께 로드될 수 있도록 JS 모듈로 포장하고, 그것들을 shadow root 에 주입할 것이다.
createRenderRoot를 재정의하면 캡슐화된 CSS 및 슬롯과 같은 섀도 DOM 기능을 사용할 수 없게 됩니다. 그럼 웹 컴포넌트를 사용하는 의미는 무엇인가요?
웹 구성요소를 사용하면 코드를 구성요소화할 수 있습니다. 이는 아직 React/Vue/Angular 등을 사용하지 않는 경우 거의 항상 향상된 기능입니다. 여전히 캡슐화가 가능합니다. 또한, 이미 많은 CSS 규칙을 가진 거대한 코드 기반을 가지고 있다면, 조명이 켜진 CSS를 사용하기 위해 스타일을 변환하는 것이 어려울 수 있다. 그리고 섀도 DOM을 채택하는 것을 복잡하게 만드는 다른 많은 사소한 문제들이 있다. 우리는 이상적인 세계에 살고 있지 않다.
섀도 DOM이 없으면 web component가 아닌 custom element입니다.
슬롯은 그림자 영역에만 한정됩니까? 조명도 슬롯을 사용할 수 없나요?
<slot>
은 섀도 DOM 기능입니다. 슬롯 개념이 작동하려면 투영된 콘텐츠와 투영할 지점을 분리해야 합니다. 섀도 DOM이 없는 DOM과 같은 하나의 컨텍스트에서만 작동하지 않습니다.
부트스트랩이나 다른 웹사이트 와이드 스타일시트를 어떻게 사용하는 것이 좋을까요? - 컴포넌트에 bootstrap을 연결해서 부트스트랩 shadow dom을 사용할 수 있음. 동일한 링크는 캐싱되므로 페이지 overload가 걸리지 않음
앞서 만든 Web Component로 부터 이벤트에 따른 변화를 알아야 한다면 어떻게 해야 할까?
가련 버튼을 클릭한 이벤트의 횟수를 외부에서 알아야 한다면?https://enumclass.tistory.com/227
https://stackoverflow.com/questions/60022651/custom-element-custom-event-handler-attributes
https://javascript.works-hub.com/learn/web-components-api-lifecycle-events-and-custom-events-66668
https://www.raymondcamden.com/2022/10/10/working-with-custom-events-and-web-components
웹컴포넌트를 사용하는 곳에서 웹컴포넌트의 이벤트 수신하기
런타임에도 필요하기때문에 dependencies 에 설치