목표
선택된 필터에 타입에 맞게 다른 리스트를 보여준다.
실습
하단에 아래와 같이 아이템의 갯수와 아이템을 필터링 할 수 있는 필터들이 있습니다.
먼저 필터를 구성해보겠습니다.
filter 를 구성하기 위한 state 를 추가합니다.
filter 의 종류는 전체, 진행중, 진행완료 세가지로 이뤄집니다.
Copy // components/Footer.vue
< template >
< footer class = "footer" >
< span class = "todo-count" >
< strong >10</ strong > items left
</ span >
< ul class = "filters" >
< li v-for = "(filter, idx) in filters" :key="idx">
<a href = "javascript:;" class = "selected" >{{ filter }}</ a >
</ li >
</ ul >
</ footer >
</ template >
< script >
export default {
data () {
return {
filters : [ "All" , "Active" , "Completed" ]
};
}
};
</ script >
아래와 같이 filter 들이 추가되는 것을 볼 수 있습니다.
selected
라는 class 는 선택된 filter 에만 적용이 되어야 합니다.
선택된 filter 값은 누가 들고 있는것이 좋을까요?
filter 의 역할을 생각해보면 간단합니다. 선택된 filter 에 따라서 todo list 에 변화가 일어납니다.
todo list 는 App.vue
에서 가지고 있는 state 입니다. 해당 state 에 변화를 주어야되니 App.vue 에 선택된 filter 값을 들고 있어야합니다.
Copy // App.vue
export default {
// ...,
data () {
return {
todos : [
{
id : new Date () ,
text : "Vue 공부하기" ,
isDone : true
} ,
{
id : new Date () + 1 ,
text : "치킨 먹기" ,
isDone : false
}
] ,
filterType : 'All' // 기본 필터는 All 로 지정하겠습니다.
}
} ,
// ...
}
이제 이 필터값을 Footer.vue
에게 넘겨주면됩니다.
Footer.vue
에서는 이 필터 값을 바탕으로 선택된 필터인지 판단합니다.
Copy // App.vue
< template >
< div id = "app" >
< section class = "todoapp" >
< Header @insertTodo="insertTodo" />
< Todo
:todos="todos"
@removeTodo="removeTodo"
@updateDone="updateDone"
@updateTodo="updateTodo"
/>
< Footer :filterType="filterType"/>
</section>
</div>
</template>
App.vue 에서 넘겨받은 filterType 을 바탕으로 selected class 를 제어합니다.
Copy // components/Footer.vue
< template >
< footer class = "footer" >
< span class = "todo-count" >
< strong >10</ strong > items left
</ span >
< ul class = "filters" >
< li v-for = "(filter, idx) in filters" :key="idx">
<a href = "javascript:;" :class="{selected: filterType === filter}">{{ filter }}</a>
</li>
</ul>
</footer>
</template>
<script>
export default {
props: {
filterType : { type : String , default : 'All' }
} ,
data () {
return {
filters : [ "All" , "Active" , "Completed" ]
};
}
};
</script>
이제 눌린 filter 로 filterType 을 변경해보겠습니다.
handleFilterType
함수는 type 을 받아 filterType 을 업데이트 합니다.
Copy // App.vue
< template >
< div id = "app" >
< section class = "todoapp" >
< Header @insertTodo="insertTodo" />
< Todo
:todos="todos"
@removeTodo="removeTodo"
@updateDone="updateDone"
@updateTodo="updateTodo"
/>
< Footer :filterType="filterType" @onFilterType="handleFilterType"/>
</section>
</div>
</template>
export default {
// ...
methods: {
// ...,
handleFilterType (type) {
this .filterType = type
}
}
};
</script>
Footer.vue
에서는 filter 가 클릭되었을 때 눌린 filter 의 값을 onFilterType
으로 넘겨줍니다.
Copy // components/Footer.vue
< template >
< footer class = "footer" >
< span class = "todo-count" >
< strong >10</ strong > items left
</ span >
< ul class = "filters" >
< li v-for = "(filter, idx) in filters" :key="idx" @click="handleFilterType(filter)">
<a href = "javascript:;" :class="{selected: filterType === filter}">{{ filter }}</a>
</li>
</ul>
</footer>
</template>
<script>
export default {
props: {
filterType : { type : String , default : 'All' }
} ,
data () {
return {
filters : [ "All" , "Active" , "Completed" ]
};
} ,
methods: {
handleFilterType (type) {
this .$emit ( 'onFilterType' , type)
}
}
};
</script>
이제는 바뀐 filterType 에 따라 다른 리스트만 보여주면 됩니다.
computed
를 이용해서 필터링을 할거에요
Active: isDone 이 false 인 완료되지 않은 리스트
Completed: isDone 이 true 인 완료된 리스트
그리고 Todo.vue 로 넘겨주던 데이터를 필터링된 리스트로 내려주면됩니다.
아이템 갯수 또한 필터링된 리스트의 사이즈로 내려줍니다
Copy // App.vue
< template >
< div id = "app" >
< section class = "todoapp" >
< Header @insertTodo="insertTodo" />
< Todo
:todos="filteredList"
@removeTodo="removeTodo"
@updateDone="updateDone"
@updateTodo="updateTodo"
/>
< Footer
:filterType="filterType"
:size="filteredList.length"
@onFilterType="handleFilterType"
/>
</ section >
</ div >
</ template >
export default {
// ...
computed : {
filteredList () {
switch ( this .filterType) {
case "All" : {
return this .todos
}
case "Active" : {
return this . todos .filter ((todo) => ! todo .isDone)
}
case "Completed" : {
return this . todos .filter ((todo) => todo .isDone)
}
default : {
return []
}
}
}
} ,
// ...
}
Footer.vue 에서는 size prop 을 받아서 보여줍니다.
Copy // components/Footer.vue
< template >
< footer class = "footer" >
< span class = "todo-count" >
< strong >{{ size }}</ strong > items left
</ span >
< ul class = "filters" >
< li v-for = "(filter, idx) in filters" :key="idx" @click="handleFilterType(filter)">
<a href = "javascript:;" :class="{selected: filterType === filter}">{{ filter }}</a>
</li>
</ul>
</footer>
</template>
<script>
export default {
props: {
filterType : { type : String , default : 'All' } ,
size : { type : Number , default : 0 }
} ,
// ...
};
</script>