웹 컴포넌트는 개발자가 재사용 가능한 커스텀 엘리먼트를 만들게 해주는 웹 네이티브 API의 모음을 지칭하는 포괄적인 용어이다.
우리는 뷰와 웹 컴포넌트가 상호 보완적인 관계라고 생각한다. 뷰는 커스텀 엘리먼트를 생성하고 소비하는데 최적의 지원을 해준다. 커스텀 엘리먼트를 뷰 애플리케이션에 통합하려하거나, 뷰를 사용해서 커스텀한 엘리먼트를 구축하고 배포하는 것 모두 좋은 사용 예이다.
뷰에서 커스텀 엘리먼트를 사용하기
뷰는 커스텀 엘리먼트 테스트를 100% 통과했다. 뷰 애플리케이션 안에있는 커스텀 엘리먼트를 사용하는 것과 네이티브 HTML 엘리먼트를 사용하는 것은 몇가지만 주의하면 대부분 동일하게 동작한다:
컴포넌트 확인 스킵하기
기본적으로, 뷰는 네이티브 HTML 태그가 아닌 태그들을 커스텀 엘리먼트로 렌더링을 시도하기 전에 등록된 뷰 컴포넌트 중 하나인지 확인한다. 이것이 뷰가 개발도중 "faild to resolve component" 경고를 나타내는 이유이다. 뷰에게 특정 엘리먼트는 커스텀 엘리먼트로 다뤄서 컴포넌트 확인을 스킵하라고 알려줘야 한다. 우리는 compilerOptions.isCustomElement 옵션으로 특정할 수 있다.
만약 build setup 으로 뷰를 사용한다면, 옵션은 build configs를 통해 넘어갈 수 있다. 왜냐하면 옵션이 컴파일 타임 옵션이기 때문이다.
In-browser 설정 예제
// Only works if using in-browser compilation.
// If using build tools, see config examples below.
app.config.compilerOptions.isCustomElement = (tag) => tag.includes('-')
Vite 설정 예제
// vite.config.js
import vue from '@vitejs/plugin-vue'
export default {
plugins: [
vue({
template: {
compilerOptions: {
// treat all tags with a dash as custom elements
isCustomElement: (tag) => tag.includes('-')
}
}
})
]
}
Vue CLI 설정 예제
// vue.config.js
module.exports = {
chainWebpack: config => {
config.module
.rule('vue')
.use('vue-loader')
.tap(options => ({
...options,
compilerOptions: {
// treat any tag that starts with ion- as custom elements
isCustomElement: tag => tag.startsWith('ion-')
}
}))
}
}
DOM 프로퍼티들을 넘기기
돔 애트리뷰트는 문자열만 될 수 있기 때문에, 돔 프로퍼티로서 커스텀 엘리먼트로 복잡한 데이터를 넘겨야 한다. 커스텀 엘리먼트에 프로퍼티들을 세팅할 때, 뷰 3는 자동적으로 돔 프로퍼티 가 in 오퍼레이터를 사용했는지 체크하고, 키값이 존재한다면 돔 프로퍼티로서 값들을 세팅할 것이다. 이 말은, 대부분의 경우, 커스텀 엘리먼트가 추천되는 사용 사례를 따른다면 이것에 대해 생각할 필요가 없다는 것이다.
하지만, 커스텀 엘리먼트가 적절하게 정의되어 프로퍼티로 투영되지 않으면 발생하는 (in 체크가 실패), 데이터가 돔 프로퍼티로서 넘겨져야만 하는 특이 케이스가 있다. 이런 경우, .prop 제어자를 사용해서 v-bind 바인딩을 돔프로퍼티로서 강제로 지정할 수 있다.
<my-element :user.prop="{ name: 'jack' }"></my-element>
<!-- shorthand equivalent -->
<my-element .user="{ name: 'jack' }"></my-element>
뷰로 커스텀 엘리먼트 만들기
커스텀 엘리먼트의 주요 이점은 모든 프레임워크에서 사용될 수 있다는 것이다. 심지어 프레임워크 없이도 사용할 수 있다. 따라서 배포된 컴포넌트를 소비자들이 다른 프론트엔드 스택이어도 사용할 수 있고, 원한다면 컴포넌트의 상세 구현을 사용하는 애플리케이션에서 구현토록 할수도 있다.
defineCustomElement
뷰는 defineCustomElement 메소드를 통해서 완전히 같은 뷰 컴포넌트 APIs 를 사용해서 커스텀 엘리먼트를 만들 수 있다. 이 메소드는 defineComponent와 같은 아규먼트를 받는다. 하지만 대신 HTMLElement를 상속받은 커스텀 엘리먼트 생성자를 리턴한다:
<my-vue-element></my-vue-element>
import { defineCustomElement } from 'vue'
const MyVueElement = defineCustomElement({
// 일반적인 뷰 컴포넌트 옵션은 여기에 적는다.
props: {},
emits: {},
template: `...`,
// defineCustomElement only: CSS는 shadow root로 삽입될 수 있다.
styles: [`/* inlined css */`]
})
// 커스텀 엘리먼트를 등록한다.
// 등록 이후에, 페이지 위의 모든 `<my-vue-element>` 태그는
// 업그레이드 된다.
customElements.define('my-vue-element', MyVueElement)
// 또한 프로그램적으로 원소를 인스턴스화 할 수 있다:
// (등록 이후에만 가능하다.)
document.body.appendChild(
new MyVueElement({
// initial props (optional)
})
)
라이프 사이클
- 뷰 커스텀 엘리먼트는 엘리먼트의 connectedCallback이 처음 호출되면 shadow 루트안에 내부 뷰 컴포넌트 인스턴스를 마운트 한다.
- 원소의 disconnectedCallback이 호출되면, 뷰는 마이크로테스크 틱 후에 document에서 엘리먼트를 분리할지 말지 결정한다.
- 원소가 document에 있다면, 이동어고 컴포넌트 인스턴스는 보존된다.
- 원소가 document로 부터 분리되면, 이건 제거되고 컴포넌트 인스턴스는 언마운트 된다.
'front > vue' 카테고리의 다른 글
[vue] Rendering Mechanism (0) | 2022.08.11 |
---|---|
[vue] Render Functions & JSX (1) | 2022.08.10 |
[vue] TransitionGroup (0) | 2022.08.08 |
[vue] Transition (0) | 2022.08.08 |
[vue] watch() (0) | 2022.08.08 |
댓글