Vue.js 기초 (4) _ todo list 작성하기

yunazzi·2024년 11월 19일
post-thumbnail

➜ 인프런 코지코더 기초강의 듣고 적기
요약 :
① Vue.js 기초(3)의 ④번과 반대되는 props를 넣어 처리
② To-Do 삭제하기
③ emits
④ To-Do 검색

① Vue.js 기초(3)의 ④번과 반대되는 props를 넣어 처리

props는 단방향 바인딩, 자식 ➜ 부모 값 변경X
TodoList 컴포넌트 사용시, 속성으로 원하는 이름적고 바인딩을 하면 원한느 데이터를 보낼수 있음

<TodoList :todos="todos"></TodoList>

:todos - props로 보내는이름
"todos" - 보낼데이터

@ TodoList 컴포넌트

export default{
	props:["todos"]
}

props:["todos"] - props로 todos를 받아옴 (template에 todos 접근가능)

<script>
export default{
	props:{
    	todos:{
        	type:Array,
            required:true,
        }
    }
}
</script>

type : Array - todos가 array이기 때문에 받는 타입 array로 설정
required : true - TodoList에는 항상 todo array가 필요하여 required:true가 필요

∴ type : string, number, boolean, array, object, function, promise


② To-Do 삭제하기

// app.vue

<template>
	<div class="container">
		<h2>To-Do List</h2>
		<TodoSimpleForm @add-todo="addTodo"></TodoSimpleForm>
		<div v-if="!todos.length">추가된 Todo가 없습니다.</div>
		<TodoList
			:todos="todos"
			@delete-todo="deleteTodo"
		></TodoList>
	</div>
</template>

<script>
import { ref } from 'vue';
import TodoSimpleForm from "@/components/TodoSimpleForm.vue";
import TodoList from "@/components/TodoList.vue";

export default {
	components: {
		TodoSimpleForm,
		TodoList
	},
	setup(){
		// App.vue에서 모든 todos를 관리할 예정 - todos데이터를 TodosList로 패스하기
		const todos = ref([]);
		const addTodo = (todo) => {
			todos.value.push(todo);
		};

		const deleteTodo = (index) => {
			todos.value.splice(index,1);
		};

		return{
			todos,
			addTodo,
			deleteTodo,
		};
	}
}
</script>
// TodoList.vue

<template>
	<div
		v-for="(todo, index) in todos"
		:key="todo.id"
		class="card mt-2"
	>
		<div class="card-body p-2 d-flex align-items-center">
			<div class="form-check flex-grow-1">
				<input
					class="form-check-input"
					type="checkbox"
					v-model="todo.complated"
				>
				<label
					class="form-check-label"
					:class="{todo : todo.complated}"
				>
					{{ todo.subject }}
				</label>
			</div>
			<div>
				<button
					class="btn btn-danger btn-sm"
					@click="deleteTodo1(index)"
				>
					Delete
				</button>
			</div>
		</div>
	</div>
</template>
<script>
export default {
	// props:['todos'] // 앞에 있는 이름 (props로 보내는 이름) - 컴포넌트에서 props에서 todos로 받아오는구나를 알게됨, template에서 todos에 접근가능
	props:{
		todos:{
			type: Array, // todos가 array이기때문에 받는 타입을 array로 설정
			// type에는 string,number,boolean,array,object,function,promise
			required: true // todolist에는 항상 todo array가 필요하여 required : true
		}
	},
	setup(props,context){
		const deleteTodo1 = (index) => {
			context.emit('delete-todo',index)
		}
		return{
			deleteTodo1,
		}
	}
}
</script>

여기서 각 영역에 deleteTodo는 서로를 함수호출하여 사용한다.


③ emits

props:["todos"] 와 동일하게 작업처리하는 방법
emits:[ 이벤트 이름 ]
↪ 넣어주면 좋은점 : emit가 여러군데 퍼져있을 경우, 모아두면 한눈에 확인하기 쉽다.

<script>
export default{
	setup(prop,context){
    	const toggleTodo = (index) =>{
        	context.emit('toggle-todo',index);
        }
        const DeleteTodo = (index) =>{
        	context.emit('delete-todo',index);
        }
    }
}
</script>
	

context는 객체를 보내준다. 객체구조분해 emit만 빼오면 context사용하지않고 바로 emit 사용할 수 있음
↓ 해당 내용처럼 바꿔어 사용해줄 수 있음

<script>
export default{
	setup(prop,{ emit }){
    	const toggleTodo = (index) =>{
        	emit('toggle-todo',index);
        }
        const DeleteTodo = (index) =>{
        	emit('delete-todo',index);
        }
    }
}
</script>
	

④ To-Do 검색

<template>
	<div class="container">
		<h2>To-Do List</h2>
		<input
			class="form-control"
			type="text"
			v-model="searchText"
			placeholder="Search"
		>
		<hr>
		<TodoSimpleForm @add-todo="addTodo"></TodoSimpleForm>
		<div v-if="!filteredTodos.length">
			There is nothing to display.
		</div>
		<TodoList
			:todos="filteredTodos"
			@toggle-todo="toggleTodo"
			@delete-todo="deleteTodo"
		></TodoList>
	</div>
</template>

<script>
import { ref, computed } from 'vue';
export default {
	setup(){
		const todos = ref([]);
		const searchText = ref('');
		const filteredTodos = computed(() => {
			if(searchText.value.length > 0){// 만약에 searchText가 빈칸이 아니라면,
				return todos.value.filter(todo => {
					return todo.subject.includes(searchText.value)
				});
			}else{ // 빈칸일 경우
				return todos.value;
			}
		});

		return{
			todos,
			searchText,
			filteredTodos,
		};
	}
}
</script>

const filteredTodos = computed(() => {}
↪ filteredTodos는 계산된 속성 | computed속성은 내부값이 변화할때 자동으로 재계산되며, 캐싱기능이 있어 성능최적화에 유리함

if(searchText.value.length > 0){} // 빈칸이 아닐경우
↪ 사용자가 searchText라는 입력필드에 텍스트 입력여부를 확인하고,
searchText.value.length는 searchText의 길이를 반환 | 길이가 0보다 크면 if값이 실행됨

return todos.value.filter(todo => {})
↪ todos는 반응형 배열, 여러할일(todo)객체를 담고있음
특정조건을 만족하는 항목만 필터링하여 새로운 배열로 반환, filter메서드는 배열의 각요소를 검사하여 true만 반환

return todo.subject.includes(searchText.value)
↪ 각 todo객체의 subject가 searchText를 포함하는지 검사한다.
includes메서드는 특정문자열이 포함되어 있으면 true를 반환한다.
searchText.value의 내용이 subject안에 포함된 항목만 필터링함

해당내용이 없을경우

↪ 해당내용이 없을경우

↪ 검색입력창이 공란일 경우

else { return todos.value; }
↪ 만약 searchText가 빈문자열이라면, 모든 todos를 그대로 반환한다.
즉, 검색어가 없을경우 필터링없이 전체목록을 보여준다.

profile
뚝딱뚝딱 열심히 공부 중 이예요!

0개의 댓글