TIL | Vue 10일 (TodoApp 할 일 모두 제거, 빈 데이터를 보낼 때의 Modal)

space's pace·2022년 10월 10일
0

Vue

목록 보기
9/9

할 일 모두 제거

App.vue

<script>
export default {
  data: function () {
    return {
      todoItems: []
    }
  },
  methods: {
    // 각각의 컴포넌트에서는 표현만 하고, 실질적인 데이터 처리는 App.vue 에서 하고 있다.
    /..
    clearAllItems: function () {
      localStorage.clear()
      // todoItems의 배열을 초기화해서 버튼을 누르는 순간, 화면에 리스트가 사라짐
      this.todoItems = []
    },
    sortLatest () {
      this.todoItems.sort(function (a, b) {
        return b.time - a.time
      })
    },
    sortOldest () {
      this.todoItems.sort(function (a, b) {
        return a.time - b.time
      })
    },
    sortAllItem (selectedSort) {
      console.log(selectedSort)
      if (selectedSort.value === 'date-desc') {
        this.sortLatest()
      } else if (selectedSort.value === 'date-asc') {
        this.sortOldest()
      }
    }
  },
  ../
  mounted () {
    this.sortOldest()
  },
  components: {
    'TodoHeader': TodoHeader,
    'TodoInput': TodoInput,
    'TodoList': TodoList,
    'TodoFooter': TodoFooter
  }
}
</script>

TodoFooter.vue

<script>
export default {
  data () {
    return {
      selected: 'date-asc'
    }
  },
  methods: {
    sortTodo () {
      this.$emit('sortItem', {value: this.selected})
    },
    clearTodo: function () {
      this.$emit('clearAll')
    }
  }
}
</script>

인자를 같이 보내지는 않음 이벤트만 발생시키면 App.vue에서

<todo-footer v-on:sortItem="sortAllItem" v-on:clearAll="clearAllItems"></todo-footer>
v-on으로 이벤트를 받아서 현재 컴포넌트 메서드에서 실행시키면 됌.

여기서 문제는 화면을 업데이트 해주는 로직이 빠짐.

this.todoItems = []

를 추가해주면 todoItems 를 빈 배열로 만들어준다 (할 일 목록 모두 제거)

모달은 한군데서만 쓰는게 아니라 여러군데서 쓸 거임.
특정 컴포넌트를 모듈화하는 방법을 배워보자.

먼저 우리가 모달을 사용할 부분은 인풋창에 입력값이 없을 때 경고 모달창을 띄우는 거다!

vue 2 모달 코드 안내
https://v2.vuejs.org/v2/examples/modal.html

/src/components 안에 common 이라는 새 폴더를 생성해 MyModal.vue 생성한다

그 안에 template 부분에 위 링크의 html 코드 transition 태그를 복붙한다.
css도 style태그 안에 넣어준다.

MyModal.vue

<template>
  <transition name="modal">
    <div class="modal-mask">
      <div class="modal-wrapper">
        <div class="modal-container">

<!--          모달 헤더-->
          <div class="modal-header">
            <slot name="header">
              default header
            </slot>
          </div>

<!--          모달 바디-->
          <div class="modal-body">
            <slot name="body">
              default body
            </slot>
          </div>

<!--          모달 푸터-->
          <div class="modal-footer">
            <slot name="footer">
              default footer
              <button class="modal-default-button" @click="$emit('close')">
                OK
              </button>
            </slot>
          </div>
        </div>
      </div>
    </div>
  </transition>
</template>

TodoInput.vue

<template>
  <div class="inputBox shadow">
    <input type="text" v-model="newTodoItem" v-on:keyup.enter="addTodo">
<!--    <button v-on:click="addTodo">add</button>-->
    <span class="addContainer" v-on:click="addTodo">
      <i class="fa-solid fa-plus addBtn"></i>
    </span>

    <MyModal v-if="showModal" @close="showModal = false">
      <!--
    you can use custom content here to overwrite
    default content
  -->
      <h3 slot="header">custom header</h3>
    </MyModal>
  </div>
</template>

vue 에서 지양하는 template의 구조에는 템플릿 태그안에 무조건 한 개의 루트만 가질 수 있다.

<script>
import MyModal from './common/MyModal.vue'
export default {
  data: function () {
    return {
      newTodoItem: '',
      showModal: false
    }
  },
  methods: {
    addTodo: function () {
      if (this.newTodoItem !== '') {
        // this.$emit('이밴트이름', 인자1, 인자2...)
        this.$emit('addTodoItem', this.newTodoItem)
        this.clearInput()
      } else {
        this.showModal = !this.showModal
      }
    },
    clearInput: function () {
      this.newTodoItem = ''
    }
  },
  components: {
    MyModal: MyModal
  }
}
</script>

Slot

: 특정컴포넌트의 일부 ui들을 재사용할 수 있는 기능

TodoInput.vue

<template>
  <div class="inputBox shadow">
    <input type="text" v-model="newTodoItem" v-on:keyup.enter="addTodo">
<!--    <button v-on:click="addTodo">add</button>-->
    <span class="addContainer" v-on:click="addTodo">
      <i class="fa-solid fa-plus addBtn"></i>
    </span>

<!--    showModal 이 true여야 보임-->
    <MyModal v-if="showModal" @close="showModal = false">
      <!--
    you can use custom content here to overwrite
    default content
  -->
<!--      = 너가 원하는 컨텐츠로 재정의해서 쓸 수 있다-->
      <h3 slot="header">
        경고!
      </h3>
    </MyModal>
  </div>
</template>
<script>
import MyModal from './common/MyModal.vue'
export default {
  data: function () {
    return {
      newTodoItem: '',
      // 기본값을 false로 해줘야 처음에 화면에 떴을 때 모달이 보이지 않음
      showModal: false
    }
  },
  methods: {
    addTodo: function () {
      if (this.newTodoItem !== '') {
        // this.$emit('이밴트이름', 인자1, 인자2...)
        this.$emit('addTodoItem', this.newTodoItem)
        this.clearInput()
      } else {
        this.showModal = !this.showModal
      }
    },
    clearInput: function () {
      this.newTodoItem = ''
    }
  },
  components: {
    MyModal: MyModal
  }
}
</script>

우리가 여기서 눈여겨 봐야할 것은 modal 컴포넌트에서 정의한 값을 TodoInput 컴포넌트에서 Modal을 불러와서(컴포넌트 등록) 재정의 했다는 점이다.

Modal을 불러온 컴포넌트에서 태그 안에 slot을 쓰고 MyMoal에 정의해놓은 slot 이름을 써서 재정의한다.

<h3 slot="header">Error!</h3>
<div slot="body">아무 내용도 입력하지 않았습니다!</div>

경고창 닫기 버튼 추가

<i class="closeModalBtn fas fa-times" @click="showModal = false"></i>

@click은 풀어쓰면 v-on:click="showModal = false" 인데 @는 v-on의 축약어이다.
showModal의 값을 다시 기본값인 false로 바꿔주면 부드럽게 사라진다 (트랜지션)

할 일 목록 트랜지션 효과

TodoList.vue

<template>
  <div>
    <transition-group name="list" tag="ul">
      <li v-for="(todoItem, index) in propsdata" v-bind:key="todoItem.item" class="shadow">
        <i class="checkBtn fa-solid fa-check" v-bind:class="{checkBtnCompleted: todoItem.completed}" v-on:click="toggleComplete(todoItem, index)"></i>
        <span v-bind:class="{textCompleted: todoItem.completed}">{{ todoItem.item }}</span>
        <span class="removeBtn" v-on:click="removeTodo(todoItem, index)">
          <i class="fa-solid fa-trash-can"></i>
        </span>
      </li>
    </transition-group>
  </div>
</template>

트랜지션 그룹에 name이 CSS랑 연관된 속성이고 태그는 말 그대로 html태그를 말함
우리는 ul태그 안에 넣을 거기 때문에 ul로 쓰면 된다.

<style scoped>
  /* 리스트 아이템 트랜지션 효과 */
  .list-enter-active, .list-leave-active {
    transition: all 1s;
  }
  .list-enter, .list-leave-to {
    opacity: 0;
    transform: translateY(30px);
  }
</style>
profile
블로그 이사 준비중!

0개의 댓글