Vue 클래스와 스타일 바인딩

Vue 엘리먼트에 스타일 적용하기

데이터 바인딩은 일반적으로 엘리먼트의 클래스 목록과 인라인 스타일을 조작하기 위해 자주 사용되는데, 이 두 속성은 v-bind를 사용하여 처리할 수 있어. v-bind의 표현식으로 최종 문자열을 계산하지만, 문자열 연결에 직접 간섭하는 것은 오류가 발생하기 쉽기 때문에 Vue는 v-bind와 함께 classstyle을 사용할 수 있는 기능을 제공하고 있어.

class 바인딩

객체 구문

표현식은 문자열 이외에 객체 또는 배열을 이용할 수 있는데, Vue는 클래스를 동적으로 토글하기 위해 v-bind:class에 객체를 전달할 수 있어.

class 바인딩하기
<div v-bind:class="{ active: isActive }"></div>

위 코드는 active 클래스가 데이터 속성인 isActiveboolean 속성에 의해 결정된다는 것을 뜻하는데, 객체에 필드가 여러개 있는 경우에는 여러 클래스를 함께 토글 할 수 있어. 또 v-bind:class는 일반적인 class 속성과도 함께 사용할 수 있어.

클래스 바인딩과 클래스 속성 함께 사용하기
<div
  class="static"
  v-bind:class="{ active: isActive, 'text-danger': hasError }"
></div>
클래스 바인딩 데이터 샘플
data: {
  isActive: true,
  hasError: false
}

위의 코드와 데이터로 렌더링을 하면 다음과 같이 false 속성인 text-danger 문자열을 제외한 static, active 클래스를 가지는 엘리먼트가 생성되는 것을 확인할 수 있어.

렌더링 된 HTML 엘리먼트
<div class="static active"></div>

바인딩 데이터에서 isActive 또는 hasError가 변경되면 클래스 목록도 업데이트되는데, 만약 hasErrortrue가 되면 엘리먼트의 클래스 목록은 “static active text-danger”가 될꺼야.

v-bind:class에 바인딩하는 객체는 꼭 인라인으로 작성할 필요는 없어. 다음과 같이 데이터에서 객체를 직접 바인딩해도 같은 엘리먼트가 생성되는 것을 확인할 수 있어.

클래스에 객체 바인딩하기
<div v-bind:class="classObject"></div>
객체 데이터 샘플
data: {
  classObject: {
    active: true,
    'text-danger': false
  }
}

또한 객체를 반환하는 computed 속성에도 바인딩 할 수 있는데, 이것은 일반적이지만 강력한 패턴이야.

computed 속성에 바인딩하기
data: {
  isActive: true,
  error: null
},
computed: {
  classObject: function () {
    return {
      active: this.isActive && !this.error,
      'text-danger': this.error && this.error.type === 'fatal'
    }
  }
}

배열 구문

v-bind:class에는 다음과 같이 객체 뿐만 아니라 배열도 전달할 수 있어.

v-bind에 배열 전달하기
<div v-bind:class="[activeClass, errorClass]"></div>
v-bind 배열에 전달되는 데이터 샘플
data: {
  activeClass: 'active',
  errorClass: 'text-danger'
}

v-bind:class에 배열을 전달하는 경우에는 데이터에 boolean 속성의 값이 아닌 실제로 적용될 클래스 이름의 ‘문자열’ 값이 들어가게 돼. 위의 코드를 렌더링 하면 다음과 같이 activetext-danger 클래스를 가진 엘리먼트가 생성되는 것을 확인할 수 있어.

배열로 생성된 엘리먼트
<div class="active text-danger"></div>
삼항연산자 이용하기

만약 목록에 있는 클래스를 조건부로 토글하고 싶다면 ‘삼항 연산자’를 이용하면 돼.

삼항 연산자로 조건부 토글하기
<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>

위 코드는 항상 errorClass를 적용하지만, isActivetrue인 경우에는 activeClass라는 클래스를 적용하게 돼.

만약 여러개의 조건부 클래스를 사용해야 한다면, 다음과 같이 배열 구문 내에서 객체 구문을 사용할 수도 있어.

배열 구문 내에 객체 구문 사용하기
<div v-bind:class="[{ active: isActive }, errorClass]"></div>

이렇게 배열 구문 내에서 객체 구문을 사용하면 표현식이 불필요하게 복잡해지는 것을 방지할 수 있어.

컴포넌트에 사용하기

사용자 정의 컴포넌트로 class 속성을 사용하면, 클래스가 컴포넌트의 루트 엘리먼트에 추가되는데, 이 엘리먼트는 기존 클래스는 덮어쓰지 않아.

컴포넌트 선언하기
Vue.component('my-component', {
  template: '<p class="foo bar">Hi</p>'
})
컴포넌트 사용하기
<my-component class="baz boo"></my-component>

위의 코드와 같이 컴포넌트를 선언하면, 다음과 같이 렌더링된 HTML 엘리먼트를 확인할 수 있어.

렌더링된 컴포넌트
<p class="foo bar baz boo">Hi</p>

즉 컴포넌트 역시 일반적인 HTML 엘리먼드에 v-bind:class를 사용하는 것처럼 동일하게 사용할 수 있어.

컴포넌트에 클래스 바인딩하기
<my-component v-bind:class="{ active: isActive }"></my-component>

isActive가 true일 경우 HTML은 다음과 같이 렌더링 돼.

렌더링된 컴포넌트
<p class="foo bar active">Hi</p>

style 바인딩

객체 구문

Vue에서 CSS Style을 바인딩하는 객체 구문에는 CSS와 거의 동일한 형태의 JavaScript 객체가 사용돼. 속성의 이름은 camelCase의 형태 또는 "kebab-case"(따옴표 필수) 형태로 사용할 수 있어.

스타일 바인딩하기
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
스타일 바인딩 데이터 샘플
data: {
  activeColor: 'red',
  fontSize: 30
}

또 클래스 바인딩과 동일하게 객체를 직접 바인딩 할 수도 있고, computed 속성과 함께 사용할 수도 있어.

스타일에 객체 바인딩하기
<div v-bind:style="styleObject"></div>
바인딩 객체 샘플
data: {
  styleObject: {
    color: 'red',
    fontSize: '13px'
  }
}

배열 구문

CSS Style을 바인딩할 때 배열 구문을 사용하는 경우에는 같은 스타일의 엘리먼트에 여러 개의 스타일 객체를 사용할 수 있어.

스타일에 배열 바인딩하기
<div v-bind:style="[baseStyles, overridingStyles]"></div>

자동 접두사

접두사 자동 추가

v-bind:style-webkit-, -moz-, -ms-, -o-와 같이 브라우저의 벤더 접두사가 필요한 CSS 속성이 사용되는 경우, Vue는 자동으로 해당 접두사를 감지하여 스타일을 적용해줘.

접두어가 적용된 style 속성의 예
<div style="
    -webkit-transform: rotate(45deg);
    -moz-transform: rotate(45deg);
    -ms-transform: rotate(45deg);
    -o-transform: rotate(45deg);
    transform: rotate(45deg);
">TEST</div>
접두사 자동 선택

Vue는 2.3+버전 부터 스타일 속성에 접두사가 있는 여러 값을 배열로 전달할 수 있어. 이때 Vue는 브라우저가 지원하는 배열의 값만 렌더링하는데, 다음 코드의 경우 접두사가 붙지않은 flexbox를 지원하는 브라우저에서는 display: flex를 렌더링하게 돼.

<div v-bind:style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>

답글 남기기