<style>
.active {
color: red;
}
.title--small {
font-size: 40px;
}
.color--orange {
color: orange;
}
</style>
<div id="app">
<button @click="toggle">Toggle</button>
<h1 :class="{ active, 'title--small color--orange':small}" class="title">{{ msg }}</h1>
</div>
<script>
const App = {
data() {
return {
msg: 'Hello Vue!',
active: false,
small:true,
}
},
active:active
는 active로 생략가능
title—small
은 html표기법으로, 'title—small': small
으로 해줘야함
'title--small color--orange':small''
처럼 안에서는 띄어쓰기로 여러개의 클래스 사용가능
<h1 :class="{ active, 'title--small color--orange':small}" class="title">{{ msg }}</h1>
return {
msg: 'Hello Vue!',
active: false,
small:true,
classObject: {
active: false,
'title--small color--orange': true
}
}
},
methods: {
toggle() {
this.active = !this.active
this.small = !this.small
}
}
}
<h1 :class="classObject" class="title">{{ msg }}</h1>
return {
msg: 'Hello Vue!',
classObject: {
active: false,
'title--small color--orange': true
}
}
classObject로 묶어서 사용 가능
return {
msg: 'Hello Vue!',
active: false,
small:true,
}
},
computed: {
classObject: {
active: this.active,
'title--small color--orange': this.small
}
},
methods: {
toggle() {
this.active = !this.active
this.small = !this.small
}
}
}
반응형 데이터로 활용하려면 computed로 계산된 데이터로 만들어줘야함
<h1 :class="[active, title]">Hello Vue!</h1>
대괄호를 이용해 2가지 class 적용
<h1 *v-if*="isShow">Hello Vue!</h1>
, <h2 *v-else*>Good Morning~</h2>
연결가능
<template v-else-if="[]">
<h2>Hi</h2>
</template>
template 요소는 html에서 보이지 않고 컨테이너로 묶을 수 있음
v-show
디렉티브는 display: none
속성을 다룸
v-if="false" or "true"
를 통해 화면표기를 다루면 <!—v-if—>으로 구조적으로 없앰
따라서 v-if는 초기렌더링 비용이 낮은 반면 전환비용이 높고, v-show는 그의 역을 가짐
일반적으로는 v-if를 작성하며 v-show를 사용할 땐 v-cloak
디렉티브, [v-cloak] { display: none;}
을 사용하는 것을 권장
※ v-clock
: 연결된 인스턴스의 컴파일이 완료되기 전까지 존재하며, 생성되면 사라짐
v-if
의 실행 우선순위가 v-for
의 우선순위보다 높기 때문에 v-if
는 v-for
범위의 변수에 접근하지 못한다. 즉, v-if
와 v-for
는 같은 동시에 사용하면 안되며, 사용하려면 template를 통해 분리하여야 한다.
<li v-for="(item, index) in items"> {{ parentMsg }} - {{ index }} - {{item.msg }} </li>
item과 index는 원하는 인자이름으로 사용 가능
<li v-for="value in myObject">{{ value }}</li>
myObject라는 객체의 값을 가져온다.
<li v-for="(value, name, index) in myObject">{{index}}. {{ name }} :{{ value }}</li>
<span v-for="n in 10">{{ n }} </span>
: 12345678910
❗v-for의 렌더링은 데이터 순서가 바뀔 때 DOM요소를 항목의 순서대로 이동시키지 않고, 각 요소를 적절한 위치에 패치하고 해당 인덱스에서 렌더링할 내용을 반영하는지 확인한다.
따라서 v-for를 사용할 때에는 key를 통해 고유값을 추가하는 것이 권장된다.
❗ v-for 객체의 index는 객체를 반복할 때 순서는 Object.keys()의 순서대로 결정되며, 자바스크립트 엔진과 일관적이지 않기 때문에 사용시 주의를 요하며, 반복순서 정도로만 사용하는 것을 권장한다.
<div id="app">
<form @submit="addNewTodo">
<label for="new-todo">Add a todo</label>
<input v-model="newTodoText"
id="new-todo"
placeholder="E.g. Feed a cat">
<button>Add</button>
</form>
<ul>
<todo-item v-for="todo in todos"
:key="todo.id"
:todo="todo"
@remove="removeTodo" />
<!-- @romove를 통해 $emit으로 정의했던 removeTodo 함수를 받는다. -->
</ul>
</div>
<script>
function generateId() {
return `${Date.now()}${Math.random()}`
}
const TodoItem = {
template: `
<li >
{{ todo.title }}
<button @click="$emit('remove', todo.id)">Remove</button>
</li>
`,
props: ['todo'] // 컴포넌트 밖에서 todo 데이터를 받는다.
}
const App = {
components: {
TodoItem
},
data () {
return {
newTodoText: '',
todos: []
}
},
methods: {
addNewTodo(e) {
e.preventDefault()
this.todos.push({
id: generateId(),
title: this.newTodoText
})
this.newTodoText = ''
console.log(this.todos);
},
removeTodo(todoId) {
this.todos = this.todos.filter(todo => {
return todo.id !== todoId
})
}
}
}
const vm = Vue.createApp(App).mount('#app')
<button @click="$emit('remove(사용자정의함수)', todo.id)">Button</button>
@click시, $emit으로 todo.id값을 사용자정의함수에 담아 보낸다.
todo-item의 @remove="removeTodo"으로 @click 이벤트와 $emit했던 todo.id값을 받는다.
<h1 @click="say('Hello~', $event)">{{ msg }}</h1>
say(*message*, *event*) { console.log(message); console.log(event); }
$event로 event를 받을 수 있다.
<h1 @click="a(), b(), c()"> ... </h1>
or <h1 @click="a(); b(); c();"> ... </h1>
event.preventDefault() 또는 event.stopPropagation() 대신 Vue의 이벤트 수식어 사용가능
<a href="https://google.com" target="_blank" @click.prevent="method">Google</a>
@click.prevnet=""
은 @click.prevent
으로 줄일 수 있음
@click.stop
: event.stopPropagation()
의 역할로 이벤트 버블링 정지@submit.prevent
: event.preventDefault()
의 역할.once
한번만 동작.capture
하위 이벤트 실행시, capture가 있는 최상위 개체부터 하위 이벤트까지 내려오며 각각 실행되며, capture 수식어가 있는 디렉티브에서만 실행된다..self
event.currentTarget는 이벤트가 연결된 곳, evnet.target은 이벤트를 실행한 곳인데, .self
는 이벤트가 연결된 곳과 실행된 곳이 같아야 실행된다..passive
화면의 렌더링과 로직의 동작처리를 분리시켜서 사용경험을 높임@keydown.meta
: 윈도우키 혹은 맥의 command키, keyup에서는 실행되지 않음
<input @keyup.alt.enter="clear" />
alt+enter 같이 체이닝가능
@keydown.arrow-down.exact
다른 키를 같이 누르면 동작하지 않음
@click.middle.exact
휠클릭과 다른 키를 같이 누르면 동작하지 않음
<h1>{{ msg }}</h1>
<input type="text"
:value="msg"
@input="msg = $event.target.value" />
<input type="text" v-model="msg" />
인풋의 값으로 msg값이 변하고, 변화된 msg가 <h1>으로 업데이트된다.
:value="msg" @input="msg = $event.target.value"
을 v-model="msg"
으로 단축할 수 있다.
v-model
은 text, 체크박스, Select태그별로 달라지는 이벤트를 통합하여 신경쓰지 않아도 된다.
주의할점은 v-model
은 IME(문자조합 ex 한글자모결합) 중 v-model이 업데이트되지 않으며, input type의 속성값보다 v-model의 데이터를 우선한다.
textarea에서 v-model 사용시 style="white-space: pre-line;
을 넣어줘야 줄바꿈 된다.
<textarea v-model="msg" @change="log"></textarea>
<h1 style="white-space: pre-line;">{{ msg }}</h1>
<div id="app">
<input type="checkbox" value="떡볶이" v-model="checked" />
<input type="checkbox" value="라볶이" v-model="checked" />
<input type="checkbox" value="계란튀김" v-model="checked" />
</div>
<script>
const App = {
data() {
return {
checked: []
}
},
watch: {
checked(newValue) {
console.log(newValue);
}
}
}
// <input type="radio" v-model="picked" value="연어덮밥" /> ,
// picked: '', picked(newValue) { console.log(newValue); }
v-model의 checked 값을 빈배열 []으로 넣으면 어떤 checkbox에 체크했는지 알 수 있다.
비슷한 방식으로 ratio
는 단일선택이므로 picked 값을 빈값 ''으로 넣으면 어떤 ratio에 체크했는지 알 수 있으며, select
는 v-model="selected"
, selected: ''
으로 사용할 수있다.
<input v-model.lazy="msg">
일 때 input 대신 change 이후 동기화된다.