Vue 문법 정리 1 / Vue 3 템플릿 문법 (인터폴레이션, 디렉티브)

인터폴레이션 (Interpolation)

템플릿에서 데이터를 HTML이 아닌 일반 텍스트로 간단히 출력할 때 사용합니다.
Vue 데이터 바인딩 문법 중 하나이며, 데이터가 변경되면 템플릿이 다시 렌더링됩니다.

{{ data변수명 }}

아래와 같이, 간단한 JS 표현식도 사용 가능합니다.

<p>{{ count + 1 }}</p>
<p>{{ isTrue ? '참' : '거짓' }}</p>
<p>{{ data변수명.split('').reverse().join('') }}</p>

디렉티브 (Directive)

v- 접두사로 시작하는 Vue 내장 HTML 속성입니다.
컴포넌트 또는 DOM 요소에 특정 동작을 지시할 수 있습니다.

디렉티브 구성요소

디렉티브명:전달인자.수식어="값"

전달인자, 수식어가 없으면 생략 가능합니다.
수식어가 여러 개면 연결해서 입력할 수 있습니다.

v-text

<span v-text="data변수명"></span>

데이터를 텍스트로 렌더링하는 아래 인터폴레이션과 동일한 역할을 합니다.

<span>{{ data변수명 }}</span>

v-html

<span v-html="data변수명"></span>

데이터를 일반 텍스트가 아닌 HTML로 렌더링합니다.
HTML 동적 렌더링 시 XSS (스크립트 삽입 공격) 이슈에 주의해야 합니다.
일반 사용자가 작성하거나 제공한 콘텐츠를 렌더링하면 안 됩니다.

v-once

<p v-once>{{ data변수명 }}</p>

데이터가 변경되어도 다시 렌더링되지 않는 일회성 바인딩입니다.

v-bind (:)

<div v-bind:title="data변수명">마우스오버</div>
또는
<input type="text" :disabled="data변수명"/>

이중 중괄호와 달리, HTML 속성에 동적으로 값을 바인딩할 수 있는 단방향 속성 바인딩입니다.
data가 변경되면 바인딩 된 DOM도 변경되지만, 사용자 입력으로 DOM이 변경되면 data는 변경되지 않습니다.

다중 속성 바인딩 예시

<template>
  <input v-bind="attrs">
</template>

<script>
import { ref } from 'vue'; 

export default {
  setup() {
    const attrs = ref({
      type: "text",
      value: '123456',
      disabled: false,
    });

    return {
      attrs
    }
  }
}
</script>

위와 같이, 여러 속성을 가진 data 객체로 한 번에 다중 속성 바인딩이 가능합니다.

다중 클래스 바인딩 예시

<template>
  // :class="클래스명: 조건"
  <div class="기존클래스" :class="{ active: isActive, 'text-danger' : hasError }">텍스트</div>
  
  // :class="클래스객체명"
  <div class="기존클래스" :class="classObject">텍스트</div>
  또는
  <div class="기존클래스" :class="classObjectComputed">텍스트</div>
  
  // :class="[클래스1, 클래스2, 클래스3]"
  <div class="기존클래스" :class="[isActive ? 'active-class' : 'class', errorClass, classObject]">텍스트</div>
</template>

<script>
import { ref, reactive, computed } from 'vue';

export default {
  setup() {
    const isActive = ref(true);
    const hasError = ref(false);

    const classObject = reactive({
      active: isActive.value,
      'text-danger': hasError.value
    });

    // 각 class 조건이 여러개인 경우
    const classObjectComputed = computed(() => {
      return {
        active: isActive.value,
        'text-danger': hasError.value,
        highlight: isActive.value && !hasError.value,
        'bg-gray': !isActive.value && hasError.value
      }
    });

    const errorClass = ref('error');

    return { isActive, hasError, classObject, classObjectComputed };
  }
}
</script>

<style>
.active {
  font-weight: 900;
}
.text-danger {
  color: red;
}
.highlight {
  background-color: yellow;
  color: black;
  font-weight: bold;
}
.bg-gray {
  background-color: #d3d3d3;
  color: white;
}
</style>

위와 같이, 다양한 스타일을 입힐 수 있는 다중 클래스 바인딩도 가능합니다.
v-bind:class 내 클래스명에 특수문자가 있으면 ‘‘로 감싸야 합니다.

인라인 스타일 바인딩 예시

<template>
  <div :style="styleObject">텍스트</div>

  <button v-on:click="fontSize--">-</button>
  <button v-on:click="fontSize++">+</button>
</template>

<script>
import { ref, computed } from 'vue';

export default {
  setup() {
      const fontSize = ref(13);

      const styleObject = computed(() => {
        return {
          color: 'red',
          fontsize: fontsize.value + 'px',
        }
      });

      return {
        styleObject
      }
  }
}
</script>

위와 같이, 인라인 스타일을 정의하고 바인딩 할 수도 있습니다.

동적 컴포넌트 (Dynamic Component)

<component :is="현재보여줄컴포넌트명"></component>

v-bind:is 속성을 사용하면 동적으로 컴포넌트를 전환할 수 있습니다.
현재 컴포넌트명을 저장하는 변수를 shallowRef 함수로 정의하면 성능이 더 좋습니다.
shallowRef는 객체 내부 값 변동을 추적하지 않기 때문입니다.

v-model

<input type="text" v-model="data변수명" />

<textarea v-model="data변수명"></textarea>

<select v-model="data변수명">
  <option value="값1">값1<option>
  <option value="값2">값2<option>
</select>

<label>
  <input type="radio" name="라디오분류" value="값1" v-model="data변수명" />
  <input type="radio" name="라디오분류" value="값2" v-model="data변수명" />
<label>

<input type="checkbox" v-model="data변수명" true-value="체크" false-value="미체크" />

<label>
  <input type="checkbox value="값1" v-model="배열data변수명" />
  값1
</label>
<label>
  <input type="checkbox value="값2" v-model="배열data변수명" />
  값2
</label>
<label>
  <input type="checkbox value="값2" v-model="배열data변수명" />
  값2
</label>

Vue에서 반응형 상태와 DOM 입력을 동기화 할 수 있는 양방향 바인딩 디렉티브입니다.
data가 변경되면 바인딩 된 DOM도 변경되고, 사용자 입력으로 DOM이 변경되면 data가 변경됩니다.

<input type="text" :value="data변수" @input="event => { data변수 = event.target.value }" />

텍스트 인풋 v-model 예시의 경우, 위 코드와 동일한 효과입니다.

v-model 수식어 종류

.lazy 기본적으로 v-model은 input 이벤트 후 입력과 데이터를 동기화합니다.
lazy 수식어를 사용하면 change 이벤트 후 (인풋에서 포커스가 나갔을 때) 동기화합니다.
.number 사용자 입력 시 number 타입으로 형변환 처리
.trim 사용자 입력 시 앞, 뒤 공백 제거 처리

v-on (@)

<button v-on:click="이벤트함수명">Click</button>
또는
<button @click="이벤트함수명">Click</button>

<script>
const 이벤트함수명 = (event) => {
  console.log(event.target);
  console.log(event.target.tagName);
}
</script>

v-on 디렉티브는 클릭, 마우스 오버, 키다운 등 다양한 이벤트 처리를 위해 사용됩니다.
이벤트 핸들러 함수 실행 시, 매개변수로 event 객체를 받을 수 있습니다.

<button @click="이벤트함수명('매개변수', $event)">Click</button>

<script>
const 이벤트함수명 = (변수명, event) => {
  console.log(event.target);
  console.log(event.target.tagName);
}
</script>

위와 같이, 다른 매개변수와 함께 이벤트 객체를 넘길 수도 있습니다.

v-on 이벤트 수식어 종류

</tbody> </table> v-on 키 수식어 종류
.stop 겹쳐있는 요소들에 이벤트 전파를 방지하는 e.stopPropagation() 기능
.prevent 요소가 가진 기본 기능 동작을 방지하는 e.preventDefault() 기능
.capture 이벤트 리스너를 캡처링 모드로 실행 (캡처링 단계에서 이벤트 감지)

캡처링 : 요소들이 겹친 경우, 최상위 요소부터 하위 요소까지 내려가며 이벤트 전파
버블링 : 요소들이 겹친 경우, 하위 요소부터 최상위 요소까지 올라가며 이벤트 전파
.self 겹친 요소가 클릭되어도, 이벤트 타겟이 본인 요소일 때만 동작
.once 이벤트 함수가 한 번만 실행되고, 이후부터는 동작하지 않음</tr>
.passive 스크롤 등 모바일 터치 이벤트의 성능을 높이기 위해 사용
이벤트 리스너가 preventDefault()를 호출하지 않도록 DOM 이벤트에 { passive: true } 속성 추가
v-on:scroll.passive="onScroll" 형태로 자주 사용됨
.enter Enter 키 입력 시 동작
.tab Tab 키 입력 시 동작
.delete Delete 키 입력 시 동작
.esc Esc 키 입력 시 동작
.space Space 키 입력 시 동작
.up PgUp 키 입력 시 동작
.down PgDn 키 입력 시 동작
.left 왼쪽 방향키 입력 시 동작
.right 오른쪽 방향키 입력 시 동작
v-on:keyup 등 키보드 이벤트 수신 시, 특정 키 입력 시에만 동작하도록 하는 수식어들입니다. 시스템 키 수식어 종류
.ctrl Ctrl 키 입력 시 동작
.alt Alt 키 입력 시 동작
.shift Shift 키 입력 시 동작
.meta Mac의 커맨드 키 또는 Windows의 윈도우 키 입력 시 동작
v-on:keyup 등 키보드 이벤트 수신 시, 특정 시스템 키 입력 시에만 동작하도록 하는 수식어들입니다. 키 수식어 등과 함께 이어붙여서 사용하는 것도 가능합니다. 마우스 버튼 수식어 종류
.left 마우스 왼쪽 버튼 클릭 시 동작
.right 마우스 오른쪽 버튼 클릭 시 동작
.middle 마우스 스크롤 버튼 클릭 시 동작
v-on:click 등 마우스 이벤트 수신 시, 특정 버튼 입력 시에만 동작하도록 하는 수식어들입니다. 토글 버튼 클릭 이벤트 예시 ``` ``` 위와 같이, 토글 버튼 클릭 이벤트도 바인딩 할 수 있습니다. keyup 이벤트 처리 예시 ``` ``` 인풋에 v-on:keyup으로 키보드 입력 시 어떤 키가 눌렸는지 확인 가능합니다. ### v-slot (#) ``` // 부모 컴포넌트 예시 // 자식 컴포넌트 예시 ``` 자식 컴포넌트 템플릿 빈 자리 (Slot) 에 부모 컴포넌트 콘텐츠를 삽입할 수 있습니다. 부모 컴포넌트에서 슬롯 콘텐츠가 제공되지 않으면 보여줄 폴백 콘텐츠도 지정할 수 있습니다. Named Slots 사용 예시 ``` // 부모 컴포넌트 예시 // 자식 컴포넌트 예시 ``` v-slot 디렉티브를 통해 특정 콘텐츠가 들어갈 slot 이름을 지정할 수 있습니다. ``` ``` 위와 같이, 부모 컴포넌트에서 동적으로 슬롯명 지정도 가능합니다. 부모 컴포넌트에 슬롯 콘텐츠를 지정하지 않으면, 자식 컴포넌트에 작성된 기본 콘텐츠가 렌더링됩니다. Scoped Slots 사용 예시 ``` // 부모 컴포넌트 예시 // 자식 컴포넌트 예시 ``` 자식 컴포넌트 변수를 부모 컴포넌트에서 사용할 수 있도록 슬롯 콘텐츠에 전달합니다. 객체로 받아도 되고, 위와 같이 구조분해 할당으로 받아도 됩니다. 부모 슬롯 미정의 시 미렌더링 처리 ``` // 부모 컴포넌트 예시 // 자식 컴포넌트 예시 ``` 부모 컴포넌트에 header 슬롯만 정의해서, 자식 컴포넌트에서 header 슬롯 div만 렌더링 됩니다. ### v-pre ```
{{ data변수명 }}
``` 템플릿 컴파일을 하지 않고, 바인딩 문법도 일반 텍스트 그대로 렌더링합니다. ### v-memo ```
``` 반응형 데이터 값이 변경될 때만 다시 렌더링합니다. Vue 3.2 이상에서 추가된 디렉티브입니다. ### v-if ``` ``` 조건에 따라 엘리먼트를 렌더링 할 때 사용합니다. template v-if ``` ``` 템플릿을 사용하면 여러 HTML 요소를 조건에 따라 렌더링 할 수 있습니다. template은 div와 달리 렌더링 결과에 포함되지 않습니다. ### v-else ```

텍스트1

텍스트2

``` 조건에 따라 다른 엘리먼트를 렌더링 할 때 사용합니다. ### v-else-if ``` ``` ### v-show ``` ``` v-show는 엘리먼트 표시 여부를 지정할 때 사용합니다. v-if와 달리, 조건이 false 시 엘리먼트를 렌더링하고 display:none 스타일을 부여합니다. ### v-for ``` ``` 배열/객체 항목을 반복 렌더링 할 수 있습니다. v-for 사용 시에는 :key 옵션으로 반복 항목의 고유 식별자를 지정해야 합니다. template v-for ``` ``` 하나의 엘리먼트에 v-for, v-if를 함께 사용하는 것은 권장되지 않습니다. 위와 같이, 템플릿을 사용하면 권장되는 형태로 출력할 수 있습니다. ### v-cloak ```

{{ data변수명 }}

``` 컴포넌트가 마운트되기 전, 데이터가 바인딩되지 않은 미완성 화면을 숨길 때 사용합니다. 마운트 시 v-cloak 속성이 제거되어 숨겨졌던 요소가 다시 보이게 됩니다.