SFC 작성 규칙
10.4.1. 블록 순서
SFC(Single File Component) 내 블록은 다음 순서를 따릅니다.
<script setup lang="ts">— 로직<template>— 마크업<style scoped>— 스타일
vue
<script setup lang="ts">
import { ref } from 'vue'
const message = ref('Hello')
</script>
<template>
<p>{{ message }}</p>
</template>
<style scoped>
p {
color: inherit;
}
</style>필수
ESLint vue/block-order 규칙이 이 순서를 강제합니다. 위반 시 린트 에러가 발생합니다.
10.4.2. template 작성 규칙
v-html은 사용하지 않습니다. XSS 공격에 취약합니다. 불가피한 경우 DOMPurify로 새니타이즈한 후 사용합니다.v-for에는 반드시:key를 바인딩합니다.index를 key로 사용하지 않습니다.v-if와v-for를 같은 요소에 동시에 사용하지 않습니다.<template>태그로 분리합니다.
vue
<!-- 올바른 예 -->
<template v-for="item in items" :key="item.id">
<div v-if="item.isActive">
{{ item.name }}
</div>
</template>
<!-- 잘못된 예 -->
<div v-for="item in items" v-if="item.isActive" :key="item.id">
{{ item.name }}
</div>10.4.3. 속성 바인딩 규칙
- 정적 속성은 일반 HTML 속성으로, 동적 속성은
v-bind(:) 약어로 작성합니다. - boolean 속성은 값 없이 선언하여
true를 전달합니다. - 속성이 3개 이상이면 한 줄에 하나씩 배치합니다.
vue
<!-- 속성이 3개 이상 — 한 줄에 하나씩 -->
<UserCard
:user="currentUser"
:editable="isAdmin"
:loading="isLoading"
@update="handleUpdate"
/>
<!-- boolean 속성 -->
<BaseButton
primary
disabled
@click="handleClick"
/>10.4.4. 이벤트 핸들링
- 이벤트 핸들러는
@약어를 사용합니다.v-on은 사용하지 않습니다. - 인라인 핸들러는 단순 표현식(1줄)에만 허용합니다.
- 복잡한 로직은 별도 함수로 분리합니다.
vue
<script setup lang="ts">
function handleSubmit() {
// 복잡한 로직
}
</script>
<template>
<!-- 올바른 예: 단순 표현식 -->
<button @click="count++">증가</button>
<!-- 올바른 예: 함수 참조 -->
<form @submit.prevent="handleSubmit">
<!-- ... -->
</form>
</template>10.4.5. style 규칙
<style>태그에는 반드시scoped를 사용합니다. 글로벌 스타일은src/styles/디렉토리에서 관리합니다.:deep()선택자는 자식 컴포넌트 스타일 오버라이드 시에만 제한적으로 사용합니다.- Tailwind CSS 유틸리티 클래스를 우선 사용하며, 커스텀 CSS는 최소화합니다.
vue
<style scoped>
/* scoped 스타일 */
.container {
@apply flex items-center gap-4;
}
/* 자식 컴포넌트 스타일 오버라이드 (제한적 허용) */
:deep(.child-class) {
color: inherit;
}
</style>