VanillaFront 2026. 9. 20. 16:12

Va.Image — 이미지 표시 컴포넌트

<img> 태그를 감싸 shape, bordered, shadow, 로드 실패 대체 이미지 등의 실전 옵션을 제공하는 이미지 컴포넌트입니다. Va.Component를 직접 상속하며 va-image 클래스가 부여됩니다.

 

클래스 정보

Va.Image extends Va.Component
tagName: 'image' (실제 렌더링은 <img>)
isContainer: false

기본 사용법

{
    tagName: 'image',
    src: './assets/img/logo.png',
    style: { width: '200px', height: 'auto' }
}

또는 코드로:

let image = new Va.Image({
    src: './assets/img/photo.jpg',
    bordered: true,
    shadow: true
});
parent.append(image);

속성

속성타입기본값설명

src String 이미지 URL 또는 경로
shape String 'circular', 'rounded' — 모양
bordered Boolean false 테두리 추가
shadow Boolean false 그림자 효과
noImgSrc String 로드 실패 시 표시할 대체 이미지 URL
naturalSize Boolean false 이미지 원본 크기로 자동 조정
layout, style, class, hidden, attributes 공통 속성

shape 값

값결과

(기본) 각진 사각형 (border-radius 0)
'rounded' 둥근 모서리 (var(--sizeFieldBorderRadiusM))
'circular' 원형 (border-radius 50%) — 아바타/프로필에 최적

이벤트

이벤트발생 시점콜백 인자

click 클릭 시 (sender, element, evt)
contextmenu 우클릭 시 (sender, element, evt)

메서드

  • setValue(value) — 이미지 src 설정 (에러 카운트 리셋)
  • setSrc(src) — 이미지 src 설정 (setValue와 동일)
  • reset() — 이미지 초기화 (기본 아이콘 표시)
  • setNoImgSrc(src) — 대체 이미지 URL 설정

내부 구조

<img class="va-image" src="..." />

<!-- shape/bordered/shadow에 따라 추가 클래스 -->
<img class="va-image circular bordered shadow" src="..." />

자동 적용되는 CSS

.va-image {
    display: inline-block;
    box-sizing: border-box;
    border-color: var(--colorNeutralForeground);
}

.va-image.circular  { border-radius: 50%; }
.va-image.rounded   { border-radius: var(--sizeFieldBorderRadiusM); }
.va-image.bordered  { border: var(--sizeBorderM) solid var(--colorNeutralStroke); }
.va-image.shadow    { box-shadow: var(--shadowM); }

로드 실패 처리 — noImgSrc

이미지 로드 실패 시 자동으로 대체 이미지로 전환하는 실전 기능:

{
    tagName: 'image',
    src: './assets/img/user_profile.jpg',
    noImgSrc: './assets/img/default_avatar.png'
}
  • 첫 로드 실패 → noImgSrc로 자동 교체
  • 대체 이미지도 실패하면 무한 루프 방지 (errorCount로 관리)
  • 대체 이미지 표시 시 배경색을 gray로 처리

src가 아예 비어있으면 → ico_image_fill 아이콘 클래스 적용 (기본 이미지 아이콘 표시).

naturalSize — 원본 크기 자동 적용

{
    tagName: 'image',
    src: './photo.jpg',
    naturalSize: true  // 로드 완료 시 이미지 원본 크기로 width/height 설정
}
  • load 이벤트에서 naturalWidth/naturalHeight를 style에 자동 설정
  • CSS로 크기 강제하지 않을 때 유용

사용 시점 — 언제 쓰나

  • 로고 표시 — 페이지/헤더 로고
  • 프로필/아바타  shape: 'circular' 조합
  • 썸네일 갤러리 — 카드/리스트의 미리보기
  • 아이콘성 이미지  <i> 아이콘으로 표현 안 되는 커스텀 이미지
  • 로드 실패 방어 필요한 프로필/썸네일  noImgSrc 활용

사용하지 말아야 할 때

  • 테마 아이콘  <i class="ico_..."> (mask-image 방식이 색상 조정 유리)
  • 배경 이미지  Va.Div + style: { backgroundImage }
  • 이미지 업로드 UI  Va.ImageFile 또는 Va.FileField
  • SVG 인라인  Va.Div + innerHTML로 SVG 직접

자주 쓰는 조합 예시

로고 표시

{
    tagName: 'header',
    tags: [{
        tagName: 'image',
        src: './assets/img/logo.png',
        style: { height: '32px', width: 'auto' }
    }]
}

프로필 아바타 (원형)

{
    tagName: 'image',
    src: user.profileUrl,
    shape: 'circular',
    bordered: true,
    noImgSrc: './assets/img/default_avatar.png',
    style: { width: '48px', height: '48px' }
}

썸네일 카드

{
    tagName: 'div',
    style: { padding: '10px', border: '1px solid var(--colorNeutralStroke)' },
    tags: [{
        tagName: 'image',
        src: item.thumbnailUrl,
        shape: 'rounded',
        shadow: true,
        style: { width: '100%', height: '150px', objectFit: 'cover' }
    },{
        tagName: 'title',
        innerHTML: item.name
    }]
}

클릭 가능한 이미지 (모달 확대)

{
    tagName: 'image',
    src: photo.thumbUrl,
    style: { cursor: 'pointer', width: '100px' },
    onClick: 'onClickPhoto'
}

// View 안:
onClickPhoto(sender){
    this.openModal(sender.src);
}

동적으로 이미지 교체

config(){
    return {
        tagName: 'div',
        tags: [{
            ref: 'refImage',
            tagName: 'image',
            src: './default.png',
            noImgSrc: './placeholder.png'
        },{
            tagName: 'button',
            text: '이미지 변경',
            onClick: 'onClickChange'
        }]
    };
}
onClickChange(){
    this.getRef('refImage').setSrc('./new_image.jpg');
}

실전 예시 — 사용자 프로필 카드 리스트

config(){
    return {
        tagName: 'section',
        layout: 'ds-flex fd-row fw-wrap gap-m',
        tags: this.users.map(user => ({
            tagName: 'div',
            layout: 'ds-flex fd-column ai-center gap-s',
            style: {
                padding: '15px',
                width: '150px',
                border: '1px solid var(--colorNeutralStroke)',
                borderRadius: 'var(--sizeRadiusM)'
            },
            tags: [{
                tagName: 'image',
                src: user.avatarUrl,
                shape: 'circular',
                bordered: true,
                noImgSrc: './assets/img/default_avatar.png',
                style: { width: '80px', height: '80px' }
            },{
                tagName: 'title',
                innerHTML: user.name
            },{
                tagName: 'subTitle',
                innerHTML: user.department
            }]
        }))
    };
}

주의사항

  • <img> 자체이므로 isContainer: false — 자식 태그 넣을 수 없음
  • src가 빈 문자열이면 ico_image_fill 아이콘 자동 표시 — 초기 로딩 상태 힌트로 활용 가능
  • noImgSrc 무한 루프 방지 — errorCount 2회까지만 재시도 (내부 로직)
  • objectFit은 style로 직접  style: { objectFit: 'cover'|'contain' } 지정. 컴포넌트 속성으로는 없음
  • naturalSize 사용 시 큰 이미지 주의 — 원본이 4000px이면 화면 넘어감. 크기 캡 style 병행 권장
  • 테마 아이콘과 혼용 금지  ico_xxx 클래스로 표현 가능한 아이콘은 <i> 태그가 색상 조정 유리
  • 로드 실패 시 gray 배경 — 대체 이미지 표시 시 backgroundColor: 'gray' 자동 적용 (원하지 않으면 style로 override)

대안 비교

상황추천

일반 이미지 표시 Va.Image
테마 아이콘 <i class="ico_xxx">
배경 이미지 Va.Div + style: { backgroundImage }
이미지 업로드 UI Va.ImageFile / Va.FileField
SVG 인라인 Va.Div + innerHTML
이미지 편집기 별도 전용 컴포넌트 필요

참고