ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Do it! Vue.js 입문] Todo List 수정기능추가 ver2
    VueJs공부 2024. 2. 2. 23:42
    반응형

    오랜만에 뷰를 다시 공부할 겸 TodoList를 만들면서,

    이전에 만들었던 수정기능보다 간단한 방법이 생각나서 기록으로 남긴다.

     

    - 모든 데이터의 처리는 App.vue에서 담당하며 하위 컴포넌트들은 데이터 처리를 App.vue로 $emit() 으로 요청한다.

    - todoItems에 데이터를 담을 때,  Date().getTime()을 id로 관리하여 처리하도록 하였다.

    - 등록시간으로 sort하여 등록순으로 리스트가 출력되도록 처리하였다.

    - 샘플 소스는 페이지 하단에 기재함.

    [App.vue] 수정method

    - TodoList.vue에서 modifyItem 이벤트를 받으면 modifyItem 을 수행하여 변경사항을 저장한다.

    - localStorage에 기존과 같은 key로 setItem할 경우 기존 값 위에 덮어씌우는 것을 이용했다.

     

    [TodoList.vue]

     

    - 수정모드일 때 input 태그로 변환하여 값을 수정하고 다시 연필버튼을 클릭하거나 엔터를 입력하면

    App.vue로 $emit 전송

     

    샘플 소스 :

    1.[App.vue]

    <template>
      <div id="app">
        <TodoHeader/>
        <TodoInput
          @addTodo="addTodo"
        />
        <TodoList
          @toggleComplete="toggleComplete"
          @modifyItem="modifyItem"
          @removeItem="removeItem"
          :todoItems="todoItems"
        />
        <TodoFooter @removeAll="removeAll"/>
      </div>
    </template>
    
    <script>
    import TodoHeader from './components/TodoHeader.vue'
    import TodoFooter from './components/TodoFooter.vue'
    import TodoList from './components/TodoList.vue'
    import TodoInput from './components/TodoInput.vue'
    export default {
      name: 'app',
      components:{
        TodoHeader,TodoFooter,TodoList,TodoInput
      },
      data() {
        return {
          todoItems : new Array(),
        }
      },
      created() {
        this.readData();
      },
      methods: {
        readData(){
          for(let i = 0; i < localStorage.length; i++){
            try{
              let data = localStorage.getItem(localStorage.key(i));
              let isValid = this.isValidJson(data);
              if(isValid){
                let todoItem = JSON.parse(data);
                this.todoItems.push(todoItem);
                this.todoItems.sort((i1, i2) => i1['id'] - i2['id']);
              }
            }catch(e){
              return false;
            }
          }
        },
        addTodo(todoItem){
          let obj = new Object();
          obj['completed'] = false;
          obj['item'] = todoItem;
          obj['id'] = new Date().getTime();
    
          //localStorage에 추가
          localStorage.setItem(obj['id'], JSON.stringify(obj));
          this.todoItems.push(obj);
          
        },
        isValidJson(str){
          try{
            JSON.parse(str);
            return true;
          } catch(e){
            return false;
          }
        },
        toggleComplete(idx){
          this.todoItems[idx]['completed'] = !this.todoItems[idx]['completed'];
          localStorage.setItem(this.todoItems[idx]['id'], JSON.stringify(this.todoItems[idx]));
        },
        modifyItem(object){
          let newTodoItem = object['newText'];
          let idx = object['idx'];
          let target = this.todoItems[idx];
          target['item'] = newTodoItem;
          localStorage.setItem(target['id'], JSON.stringify(target));
        },
        removeItem(idx){
          localStorage.removeItem(this.todoItems[idx]['id']);
          this.todoItems.splice(idx, 1);
        },
        removeAll(){
          localStorage.clear();
          this.todoItems = new Array();
        }
      }
    }
    </script>
    
    <style>
    body {
      text-align: center;
      background-color: #f6f6f6;
    }
    input{
      border-style: groove;
      width: 200px;
    }
    button {
      border-style: groove;
    }
    .shadow {
      box-shadow: 5px 10px 10px rgba(0,0,0, 0.03);
    }
    </style>

     

    2. [TodoList.vue]

    <template>
      <div>
          <TransitionGroup name="list" tag="ul">
            <li v-for="(todoItem, idx) in todoItems" :key="idx" class="shadow">
              <input 
                v-if="isModify && modifIdx === idx"
                type="text" 
                v-model="modifyText" 
                @keyup.enter="toggleInputMode(todoItem, idx)"
                placeholder="수정할 내용을 입력하세요."
              />
              <div v-else>
                <span class="chkBtn">
                  <i class="fa-solid fa-check" @click="toggleComplete(idx)"></i>
                </span>
                <span :class="{textCompleted : todoItem['completed']}">
                  {{ todoItem['item'] }}
                </span>
              </div>
              
            
            <span class="btnGroup">
              <i class="fa-solid fa-pencil modifyBtn" @click="toggleInputMode(todoItem, idx)"/>
              <i class="fa-solid fa-trash removeBtn" @click="removeItem(idx)"></i>
            </span>
          </li>
          </TransitionGroup>
      </div>
    </template>
    
    <script>
    export default {
      data() {
        return {
          isModify : false,
          modifIdx : 0,
          modifyText : "",
        }
      },
      props:{
        todoItems : Array
      },
      methods: {
        toggleInputMode(todoItem, idx){
          this.isModify = !this.isModify;
          this.modifIdx = idx;
          if(this.isModify){
            this.modifyText = todoItem['item'];
          } else {
            this.$emit('modifyItem', {'newText' : this.modifyText, 'idx':idx});
          }
        },
        toggleComplete(idx){
          this.$emit('toggleComplete', idx);
        },
        removeItem(idx){
          this.$emit('removeItem', idx);
        }
      },
    }
    </script>
    
    <style>
      ul {
        list-style-type: none;
        padding-left: 0px;
        margin-top: 0;
        text-align: left;
      }
      li {
        display: flex;
        min-height: 50px;
        height: 50px;
        line-height: 50px;
        margin: 0.5rem;
        padding: 0 0.9rem;
        background:white;
        border-radius: 5px;
      }
      .chkBtn {
        line-height: 45px;
        color: #62acde;
        margin-right: 5px;
      }
      .chkBtnCompleted {
        color: #b3adad;
      }
      .textCompleted {
        text-decoration: line-through;
        color: #b3adad;
      }
      .btnGroup {
        margin-left: auto;
      }
      .btnGroup .removeBtn {
        color: #de4343;
      }
      .btnGroup .modifyBtn {
        color: #43de84;
        margin-right: 5px;
      }
      input {
        border-style: none;
      }
      
      .list-enter-active,
      .list-leave-active {
        /* transition: opacity 1s ease; */
        transition: opacity 1s;
      }
      /* .list-enter-from, */
      .list-enter,
      .list-leave-to {
        opacity: 0;
        transform: translateX(30px);
      }
    </style>
    반응형

    'VueJs공부' 카테고리의 다른 글

    Vue SpringBoot 연동하기  (0) 2024.01.21
    Doit Vue.js입문 todolist 수정기능 추가하기  (0) 2022.02.12

    댓글

Designed by Tistory.