v-for=”구성요소 in 대상”
⇒ 해당 셀렉터를 반복한다
대상이 배열일 때
(item, index) in items
도 가능 ⇒ 0부터 시작
대상이 객체일 때
(value, key, index) in obj
도 가능
- 구성 요소의 순서와 정의된 순서가 동일하다는 것을 보장하지 않는다 ⇒ 따라서 index와 같이 쓰는 것은 권장x
상태 유지
- 가능하면 v-for와 v-bind:key를 함께 사용하는 것이 좋다
- key: 노드를 식별할 수 있는 아이디
- 각 요소가 고유하다는 것을 뷰에게 알려서, 최적화를 가능하게 한다
배열 변경 감지
- 대상이 배열일 때, 기존 JS처럼 배열을 조작(ex. splice 등)하는 메서드들을 변이 메소드라고 한다
- filter, slice 등 기존 배열을 조작하지 않고 새로운 배열을 리턴하는 비변이 메소드도 있다
- 뷰는 최대한 배열의 아이템을 재사용하려고 해서, 내용을 비교했을 때 요소가 같진 않더라도 기본적인 구조가 같으면(filter, slice등 후) 화면을 재렌더링 하지 않는 최적화를 한다.
필터링/정렬된 결과 표시
- computed 등에서 기존 배열 data를 조작하여 그 조작된 배열을 for문으로 순회할 수도 있다.
범위가 있는 v-for
n in 숫자
처럼 사용할 수도 있다. n은 1~숫자까지다
- v-for에서도 template를 사용할 수 있다
단방향 데이터 바인딩
- input에 반응형 데이터를 v-bind:value 속성으로 넣으면, data가 변경 될 때는 input에 영향을 미치지만, input에서 직접 value를 수정하면 data에는 영향일 미치지 않는다 ⇒ 단방향 데이터 바인딩
- 양방향 ⇒ v-bind대신 v-model로 value 속성을 지정하면 된다
<div id="app">
<form @submit="addTodo">
<label for="todo-input">Add a todo</label> <!-- 라벨로 input과 텍스트가 한몸-->
<input v-model="todo" id="todo-input" placeholder="E.g Feed the cat"/>
<!-- v-bind:value 대신에 v-model을 씀에 주의-->
<button>Add</button>
<ul> <!-- key를 꼭 써줘야 개별로 잘 구분됨-->
<todo-item v-for="todo in todos" :key="todo.id" :todo="todo" @remove="removeTodo"></todo-item>
<!-- * 컴포넌트로 빼주기
* 커스텀 이벤트 remove
* $emit으로부터 넘어오는 props는 알아서 메서드에 들어감
-->
</ul>
</form>
</div>
<script>
const generateId = () => `${Date.now()}${Math.random()}`
const TodoItem = {
template: `
<li>
{{todo.text}}
<button @click="$emit('remove',todo.id)">Remove</button>
</li>
`,
props: ['todo']
}
// 컴포넌트 형태
// 여기 컴포넌트에서는 app의 data나 method를 알지 못함에 주의 => data는 props로, 이벤트 method는 emit으로
// $emit => 커스텀 이벤트를 트리거, $emit(이벤트이름, 매개변수)
const app = {
components: {
TodoItem
},
data() {
return {
todo: '',
todos: []
}
},
methods: {
addTodo(event) { //v-on에서 쓰이는 메서드는 매개변수에 event를 받을 수 있고, 이벤트가 ㅂ라생하면 알아서 넘어온다
event.preventDefault() //제일 처음 써줘야 함에 주의
this.todos.push({
id: generateId(),
text: this.todo
})
this.todo = ''
},
removeTodo(removedId) {
const removedIdx = this.todos.findIndex(todo => todo.id === removedId)
this.todos.splice(removedIdx, 1)
}
}
}
const vm = Vue.createApp(app).mount('#app')
</script>