Vue.js 컴포넌트의 동적 클래스 및 스타일 바인딩 기법

동적 클래스 바인딩 (Dynamic Class Binding)

Vue.js에서는 v-bind:class (또는 단축형 :class)를 사용하여 HTML 요소의 클래스를 동적으로 조작할 수 있습니다. 이는 조건부 렌더링이나 상태에 따른 UI 변경을 선언적으로 처리하는 데 매우 유용합니다.

1. 객체 구문 (Object Syntax)

클래스 이름을 키로, 해당 클래스의 적용 여부를 결정하는 불리언 값을 값으로 갖는 객체를 전달합니다.

<template>
  <!-- 인라인 객체 사용 -->
  <button :class="{ 'btn-active': isClicked, 'btn-disabled': isDisabled }">
    제출
  </button>

  <!-- 데이터 속성에 정의된 객체 사용 -->
  <section :class="panelClasses">
    대시보드 패널
  </section>
</template>

<script>
export default {
  data() {
    return {
      isClicked: true,
      isDisabled: false,
      panelClasses: {
        'panel-dark': true,
        'panel-shadow': false
      }
    };
  }
};
</script>

2. 배열 구문 (Array Syntax)

여러 클래스를 동적으로 적용해야 할 때 배열을 사용하면 직관적입니다.

<template>
  <div :class="[baseClass, themeClass]">
    알림 메시지
  </div>
</template>

<script>
export default {
  data() {
    return {
      baseClass: 'notification',
      themeClass: 'notification-warning'
    };
  }
};
</script>

배열 내에서 조건부 클래스를 적용하기 위해 삼항 연산자를 함께 사용할 수도 있습니다.

<div :class="[baseClass, isImportant ? 'highlight' : '']"></div>

3. 삼항 연산자 및 메서드 활용

복잡한 조건에 따라 클래스를 결정해야 할 경우, 삼항 연산자나 컴포넌트 메서드를 활용하면 템플릿을 깔끔하게 유지할 수 있습니다.

<template>
  <!-- 삼항 연산자 -->
  <span :class="userRole === 'admin' ? 'text-red font-bold' : 'text-gray'">
    {{ userName }}
  </span>

  <!-- 메서드 호출 -->
  <div :class="getStatusClass(serverStatus)">
    서버 상태 표시등
  </div>
</template>

<script>
export default {
  data() {
    return {
      userRole: 'admin',
      userName: 'Alice',
      serverStatus: 'offline'
    };
  },
  methods: {
    getStatusClass(status) {
      const statusMap = {
        online: 'bg-green-500',
        offline: 'bg-red-500',
        maintenance: 'bg-yellow-500'
      };
      return statusMap[status] || 'bg-gray-500';
    }
  }
};
</script>

4. 정적 클래스와 동적 클래스의 공존

:class 디렉티브는 기존의 정적 class 속성을 덮어쓰지 않고 병합합니다.

<!-- 렌더링 결과: class="card card-elevated" -->
<div class="card" :class="{ 'card-elevated': isElevated }"></div>

동적 인라인 스타일 바인딩 (Dynamic Inline Style Binding)

v-bind:style (또는 :style)를 사용하면 CSS 인라인 스타일을 동적으로 바인딩할 수 있습니다. CSS 속성명은 카멜 케이스(camelCase) 또는 케밥 케이스(kebab-case, 따옴표 필수)로 작성할 수 있습니다.

1. 객체 구문 (Object Syntax)

JavaScript 객체와 매우 유사한 형태를 띠며, 동적 값과 단위를 결합하여 사용할 수 있습니다.

<template>
  <div :style="{ backgroundColor: themeColor, fontSize: textSize + 'px' }">
    스타일링된 텍스트
  </div>
</template>

<script>
export default {
  data() {
    return {
      themeColor: '#3498db',
      textSize: 18
    };
  }
};
</script>

객체를 직접 템플릿에 작성하는 대신, 데이터 속성에 정의하여 재사용성을 높이는 것이 좋습니다.

<template>
  <button :style="buttonStyles">저장</button>
</template>

<script>
export default {
  data() {
    return {
      buttonStyles: {
        backgroundColor: '#2ecc71',
        color: '#ffffff',
        padding: '10px 20px',
        borderRadius: '4px'
      }
    };
  }
};
</script>

2. 배열 구문 (Array Syntax)

배열 구문을 사용하면 여러 스타일 객체를 하나의 요소에 적용할 수 있습니다. 이는 기본 스타일과 조건부 스타일을 분리할 때 유용합니다.

<template>
  <div :style="[baseStyles, customOverrides]">
    멀티 스타일 적용 영역
  </div>
</template>

<script>
export default {
  data() {
    return {
      baseStyles: {
        display: 'flex',
        justifyContent: 'center',
        alignItems: 'center'
      },
      customOverrides: {
        backgroundColor: 'rgba(0, 0, 0, 0.8)',
        height: '200px'
      }
    };
  }
};
</script>

실전 활용 예시

1. 반응형 이미지 너비 설정

데이터의 상태나 배열의 길이에 따라 이미지의 너비를 동적으로 조절해야 하는 경우, :style을 활용할 수 있습니다.

<template>
  <img 
    :src="imageUrl" 
    :style="{ width: galleryItems.length > 1 ? '48%' : '100%' }" 
    alt="Gallery Image" 
  />
</template>

<script>
export default {
  data() {
    return {
      imageUrl: 'https://example.com/images/sample.jpg',
      galleryItems: ['item1', 'item2']
    };
  }
};
</script>

2. 무작위 테마 클래스 적용

사용자 이벤트에 따라 미리 정의된 여러 테마 중 하나를 무작위로 적용하는 로직을 구현할 수 있습니다.

<template>
  <div>
    <div :class="currentTheme">테마 테스트 박스</div>
    <button @click="randomizeTheme">테마 변경</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      currentTheme: 'theme-light'
    };
  },
  methods: {
    randomizeTheme() {
      const themes = ['theme-light', 'theme-dark', 'theme-solarized', 'theme-nord'];
      const randomIndex = Math.floor(Math.random() * themes.length);
      this.currentTheme = themes[randomIndex];
    }
  }
};
</script>

태그: Vue.js CSS v-bind DynamicClass InlineStyle

6월 23일 03:51에 게시됨