미니앱 컴포넌트
웹 컴포넌트 #
웹 컴포넌트는 개발자들이 조각들을 조립하여 멋진 앱을 만들 수 있다는 약속에서 시작됐어요. 그런 Atomic Component의 예시로 GitHub의 time-elements, Stefan Judis의 web-vitals-element 그리고 Google의 dark mode toggle 등이 있어요. 하지만 어떤 온전한 디자인 시스템의 경우 사람들은 하나의 제조사의 일관적인 세트에 더 의존해요. 몇몇 예시로 SAP의 UI5 Web Components, Polymer Elements, Vaadin's elements, 마이크로소프트의 FAST, Material Web Components, AMP components를 비롯해 수많은 제조사들의 디자인이 있어요.
이 글에서 다루기엔 너무 복잡한 수많은 이유로, 개발자들은 React, Vue.js, Ember.js등으로 완전히 이주하기도 했어요.
개발자들에게 이런 선택지를 주는 대신 (또는, 관점에 따라 특정한 기술적 결정을 내려야만 하도록 강요하는 대신) 슈퍼앱 제조사들은 개발자들이 반드시 사용해야하는 통일된 컴포넌트 세트를 제공해요.
미니앱의 컴포넌트 #
이 컴포넌트들은 위에 언급한 컴포넌트 라이브러리와 비슷하다고 생각하면 돼요. 컴포넌트에 어떤 것들이 있는지 확인하려면 WeChat의 컴포넌트 라이브러리, ByteDance의 컴포넌트, Alipay의 컴포넌트, Baidu의 컴포넌트, 또는 QuickApp 컴포넌트를 확인해보세요.
앞서 몇몇 컴포넌트들은 기반 레벨에서 웹 기술로 동작한다는 것을 보여드렸어요. 예를 들어, WeChat의 <image>
는 웹 기술로 구현되어 있어요. 하지만 모든 컴포넌트가 웹 기술로 구현된 것은 아니에요. <map>
또는 <video>
등의 태그들은 OS에 내장된 컴포넌트로 웹뷰 위에서 렌더링돼요. 어떤 식으로 구현되었는지 자세하게 공개된 바는 없지만, 다른 컴포넌트처럼 프로그램되어 있어요.
여느 때와 같이, 사소한 디테일은 다르지만 모든 슈퍼앱들은 공통된 프로그래밍 철학을 가지고 있어요. 가장 중요한 것은 마크업 언어에서 설명한 것처럼 데이터 바인딩이에요. 컴포넌트들은 주로 기능 단위로 구분되어 있으므로 필요한 컴포넌트를 찾는 것은 어렵지 않아요. 아래는 Alipay의 분류이지만 다른 제조사들도 비슷해요.
- View 컨테이너
view
swiper
scroll-view
cover-view
cover-image
movable-view
movable-area
- 기본 콘텐츠
text
icon
progress
rich-text
- Form 요소
button
form
label
input
textarea
radio
radio-group
checkbox
checkbox-group
switch
slider
picker-view
picker
- 내비게이션
navigator
- 미디어 컴포넌트
image
video
- 캔버스
canvas
- 지도
map
- 오픈 컴포넌트
web-view
lifestyle
contact-button
- 접근성
aria-component
아래는 Alipay의 <image>
로a:for
directive(리스트 렌더링 참고)를 사용하는 예시예요. index.js
에서 이미지 데이터 배열을 받아서 배열을 순회해요.
/* index.js */
Page({
data: {
array: [
{
mode: 'scaleToFill',
text: 'scaleToFill',
},
{
mode: 'aspectFit',
text: 'aspectFit',
},
],
src: 'https://images.example.com/sample.png',
},
imageError(e) {
console.log('image', e.detail.errMsg);
},
onTap(e) {
console.log('image tap', e);
},
imageLoad(e) {
console.log('image', e);
},
});
<!-- index.axml -->
<view class="page">
<view
class="page-section"
a:for="{{array}}"
a:for-item="item"
>
<view class="page-section-demo" onTap="onTap">
<image
class="image"
mode="{{item.mode}}"
onTap="onTap"
onError="imageError"
onLoad="imageLoad"
src="{{src}}"
lazy-load="true"
default-source="https://images.example.com/loading.png"
/>
</view>
</view>
</view>
item.mode
는 mode
속성으로, src
는 src
속성으로, 그리고 3개의 이벤트 핸들러 onTap
, onError
, 그리고 onLoad
는 동명의 함수로 데이터 바인딩이 된다는 점을 참고하세요. 이전에 보았듯이, <image>
태그는 내부적으로 <div>
로 변환되며 이미지의 해상도, (선택) Lazy Loading, 기본 소스 등의 정보를 가지고 있어요.
가능한 세부 옵션들은 문서에 나와있어요. 문서에 내장된 컴포넌트 미리보기 시뮬레이터를 통해 코드를 보다 쉽게 이해할 수 있어요.


각각의 컴포넌트는 독자적인 QR 코드를 가지고 있어서 Alipay 앱으로 스캔하여 컴포넌트를 예시를 통해 확인할 수 있어요.

<image>
컴포넌트를 QR 코드 링크를 통해 미리보는 모습.개발자들은 문서에서 URI scheme antdevtool-tiny://
를 통해 Alipay 개발자 도구 IDE로 바로 건너갈 수 있어요. 개발자들은 이를 통해 자신의 프로젝트로 컴포넌트를 바로 불러올 수 있어요.
커스텀 컴포넌트 #
제조사에서 제공하는 컴포넌트 외에도 다양한 커스텀 컴포넌트를 만들 수 있어요. 이런 개념은 WeChat, ByteDance, Alipay, Baidu, 그리고 QuickApp에도 존재해요.
예를 들어, Baidu의 커스텀 컴포넌트는 custom.swan
, custom.css
, custom.js
, 그리고 custom.json
4개의 파일을 동일한 폴더에 작성함으로써 만들 수 있어요.
custom.json
파일은 폴더에 있는 자료들이 커스텀 컴포넌트임을 나타내요.
{
"component": true
}
custom.swan
은 마크업을, custom.css
는 CSS를 나타내요.
<view class="name" bindtap="tap"
>{{name}} {{age}}</view
>
.name {
color: red;
}
그리고 custom.js
는 로직을 담당해요. 컴포넌트의 라이프사이클 함수로는 attached()
, detached()
, created()
, 그리고 ready()
등이 있어요. 컴포넌트는 또한 show()
그리고 hide()
등의 페이지 라이프 사이클 이벤트에도 반응할 수 있어요.
Component({
properties: {
name: {
type: String,
value: 'swan',
},
},
data: {
age: 1,
},
methods: {
tap: function () {},
},
lifetimes: {
attached: function () {},
detached: function () {},
created: function () {},
ready: function () {},
},
pageLifetimes: {
show: function () {},
hide: function () {},
},
});
커스텀 컴포넌트는 index.json
으로 불러올 수 있어요.그리고 import
의 key
로 index.swan
에서 사용할 컴포넌트의 이름을 지정할 수 있어요. 여기에서는 이름은 "custom"
이에요.
{
"usingComponents": {
"custom": "/components/custom/custom"
}
}
<view>
<custom name="swanapp"></custom>
</view>
감사의 말 #
이 글은 Joe Medley, Kayce Basques, Milica Mihajlija, Alan Kent, 그리고 Keith Gu에 의해 리뷰되었어요.