
[ Reference ]
https://vuejs.org/guide/essentials/class-and-style.html
Class and Style Bindings | Vue.js
vuejs.org
데이터 바인딩이 필요한 일반적인 이유는 Element 의 클래스와 인라인 Style 을 조작하기 위함이다. 둘 다 속성(attribute) 이기 때문에 ** v-bind ** 를 이용해서 조작할 수 있다. 식을 사용해 마지막 문자열만 계산만 하면 된다. 하지만, 문자열만 가지고 계산하는 과정에서 생기는 간섭은 귀찮고 에러를 쉽게 유발한다. 이런 이유들로 Vue 에서는 ** v-bind ** 를 class 와 style 에 접목시킬 때 특별한 기능을 추가했다.문자열 뿐만 아니라 ** v-bind ** 로 표현할 때는 객체나 배열을 접목시킬 수 있다.
1. Binding HTML Classes
Binding to Objects
** :class (= v-bind: class) ** 를 이용하면 클래스를 동적으로 전환해줄 수 있다. **
<div :class="{ active: isActive }"></div>
위의 문장의 의미는 isActive 가 true 값이면 active 클래스가 생긴다는 의미다. 객체에 더 많은 값들을 지정해서 여러 클래스들을 설정해줄 수 있다.
const isActive = ref(true)
const hasError = ref(false)
만약 ** script ** 문 내에 다음과 같이 isActive 와 hasError 가 정의되었다고 하면
<div
class="static"
:class="{ active: isActive, 'text-danger': hasError }"
></div>
이 값은
<div class="static active"></div>
이렇게 렌더링될 것이다. (* static 의 경우, ** :class ** 에서 동적으로 클래스를 바인딩 하는 것이 아니라, 일반 HTML 문처럼 정적으로 클래스를 지정해준 것이기에 바로 렌더링 된다. active 와 text-danger 클래스는 각각 isActive, hasError 가 true 일 때 클래스 리스트에 올라가는데, isActive 는 true 값이지만 text-danger 는 false 값이므로 active 클래스만 렌더링된다.
참고로 위와 같이 인라인으로 객체를 지정해줄 필요없다. script 문에서 객체를 만들고 그 객체를 바인딩해주면 된다. 위에서 정의된 ** :class ** 는 아래와 같이 표현할 수 있다.
const classObject = reactive({
active: true,
'text-danger': false
})
<div :class="classObject"></div>
** computed ** 로 계산된 값도 반환할 수 있다. 이렇게 사용하는 방법이 가장 일반적이고 퍼포먼스가 좋은 패턴이다.
const isActive = ref(true)
const error = ref(null)
const classObject = computed(() => ({
active: isActive.value && !error.value,
// camelCase 를 사용하지 않고 kebab-case 를 사용해야 한다
// kebab-case 를 사용할 때는 작은 따옴표로 묶어줘야 한다
'text-danger': error.value && error.value.type === 'fatal'
}))
<div :class="classObject"></div>
Binding to Arrays
** :class ** 를 이용해서 array 를 클래스에 접목할 수 있다.
const activeClass = ref('active')
const errorClass = ref('text-danger')
<div :class="[activeClass, errorClass]"></div>
이렇게 설정을 할 경우, 렌더링 되는 방식은 아래와 같다
<div class="active text-danger"></div>
만약 true, false 의 조건부로 렌더링을 하고 싶다면 삼항 연산자를 이용할 수 있다.
<div :class="[isActive ? activeClass : '', errorClass]"></div>
(* 위의 구문을 해석하면 isActive 가 ture 라면 activeClass 값, 'active' 가 렌더링되고, isActive 가 false 가 되면 빈 문자열, 즉 아무것도 렌더링 되지 않는 것이다. 즉, isActive 가 ture 일 때 <div class= "active text-danger"> 가 되고 false 라면 <div class="text-danger"> 가 된다.
그런데 만약에 이렇게 조건을 달아서 렌더링 해야할지 말아야할지 결정하는 클래스가 많은 경우에는 배열에 객체를 넣어서 사용할 수도 있다. 위의 문장은 아래와 동일하다.
<div :class="[{ active: isActive }, errorClass]"></div>
With Components
Root Component 에 클래스를 추가하는 경우, 그 클래스는 컴포넌트의 최상위 Element 에 추가된다.
예를 들어서 my-component 라는 컴포넌트 template 에 다음과 같은 문장을 넣었다. (* 조금 더 쉬운 설명을 위해서 기존의 예제에서 약간의 변형을 가했다)
<div class="greeting">
<p class="foo bar">Hi!</p>
</div>
그리고 이 my-component 의 부모 컴포넌트에 다음과 같이 template 내에 컴포넌트를 사용하고 class 값을 추가했다고 하면
<!-- when using the component -->
<my-component class="baz boo"></my-component>
실제 렌더링되는 태그는 다음과 같이 컴포넌트에 넣어준 클래스가 모두 들어가게 된다.
<div class="greeting baz boo"
<p class="foo bar">Hi</p>
</div>
최상위 요소는 가장 밖에서 모든 것을 감싸고 있는 태그라고 편하게 생각하면 좋다. 위의 코드에서는 div 태그가 최상위 요소이기에 div 태그로 컴포넌트에서 지정해준 태그가 들어갔다.
물론, 이 최상위 요소는 여러 개가 될 수 있다. 그럴 경우에는 컴포넌트에서 부여한 클래스를 받고자 하는 태그에 표시( $attrs.class )를 남겨야 한다. (* $attrs 에는 많은 것이 담겨 있다. 그 속성 중 하나로 class 가 존재하는 것.)
<p :class="$attrs.class">Hi!</p>
<span>This is a child component</span>
이렇게 되면 위의 코드에서는 최상위 요소가 두 개(p, span 태그)다. 여기에서 컴포넌트에 부여한 태그를 받겠다고 하는 표시로 ** $attrs.class ** 를 넣어준 것이다. 그러면 이 컴포넌트에 class 로 baz 를 추가하게 되면 렌더링 되는 것은
<p class="baz">Hi!</p>
<span>This is a child component</span>
이 된다.
2. Binding Inline Styles
Binding to Objects
** :style ** 이 javascript 객체의 값을 바인딩해서 HTML 태그의 style 속성으로 만들어준다.
const activeColor = ref('red')
const fontSize = ref(30)
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
key 값으로 camelCase 가 권장되지만, ** :style ** 은 CSS 에서 kebab-case 도 지원을 해주고 있다. (* kebab-case 가 실제 CSS 에서 사용하는 것과 동일하기 때문에 더 직관적이다.)
<div :style="{ 'font-size': fontSize + 'px' }"></div>
좀 더 명쾌하게 사용하는 방법은 객체를 만들고 할당하는 방식이다.
const styleObject = reactive({
color: 'red',
fontSize: '13px'
})
<div :style="styleObject"></div>
물론, ** computed ** 를 이용해서 사용할 수 있다.
Binding to Arrays
: style 로 여러 스타일 객체를 바인딩할 수 있다. (* 이런 방식은 아마 스타일을 모듈화 해서 재사용한다 하면 좋을 것 같기는 하나 그렇게 유용하게 사용할 수 있을 거 같지는 않다)
<div :style="[baseStyles, overridingStyles]"></div>
Auto-prefixing
** : style ** 은 vendor 접두사 (* 예를 들면 -webkit-, -ms- 같은 거) 를 사용할 때, Vue 가 적절한 접두사를 자동으로 추가한다. Vue 는 현재 브라우정레서 지원되는 스타일 속성을 런타임에서 확인을 하고 이 작업을 수행한다. 만약에 브라우저가 그 CSS 속성을 지원하지 않으면 지원되는 속성을 찾기 위해서 접두사 변형을 한다.
Multiple Values
스타일의 특성에 여러 값을 사용하기 위해서 배열을 사용할 수 있다.
<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>