10/20

김승우·2020년 10월 20일
0

Vue 인프런 강의 복습

Ref : https://www.inflearn.com/course/vuejs/

1. $nextTick()

: 다음 DOM 업데이트 사이클 이후 실행하도록 콜백함수를 인자로 전달한다. 데이터 변경한 직후에 사용해야한다.

  • 사용 소스
//Card.vue
 <header slot="header" class="cardView__header">
   		//1. isEditTitle === true
                <b-form-input
                    v-model="inputTitle"
                    placeholder="타이틀을 입력하세요:-)"
                    class="cardView__inputTitle"
                    v-if="isEditTitle"
                    ref="inputTitle"
                ></b-form-input>
		//2. isEditTitle === false
                <span class="cardView__title" v-else @click="setEditTitle">
			{{card.title}}
              	</span>
</header>
  1. v-if 디렉티브와 isEditTitle 변수를 이용해서 "input"과 "span"태그를 번갈아가면서 렌더링한다.
//Card.vue methods
setEditTitle() {
            this.isEditTitle = true;
            this.inputTitle = this.card.title.trim();
            //this.$refs.inputTitle.focus(); //1.
            this.$nextTick(() => {	     //2.
                this.$refs.inputTitle.focus();
            });
}
  1. $nextTick을 사용하지 않았을 경우, "$refs"를 통해서 input 태그를 참조하지 못햇다. => "isEditTitle"이 변경되어 DOM이 렌더링되는 것보다 //1.번 라인이 더 먼저 실행되는 것이 이유!!
  2. 따라서 this.$nextTick()에 해당 라인을 콜백함수으로 전달하여, 다음 DOM이 업데이트된 이후 실행하도록한다.
  1. Card 수정 로직
  • 소스
//Card.vue
onEditCard() {
            const listId = this.card.listId;
            const title = this.inputTitle.trim();
  	   //1.
            const description = this.inputDesc.length ? this.inputDesc.trim() : null;
            const id = this.cid;

  	   //2.
            if (!this.inputTitle.length) {
                alert("카드 제목을 입력해주세요!");
              	//3.
                this.inputTitle = this.card.title;
                this.$nextTick(() => this.$refs.inputTitle.focus());
                return false;
            }

  	    //4. 
            this.UPDATE_CARD({ id, title, listId, description })
                .catch((err) => console.error(err))
                .finally(() => {
             	 this.restoreEdit();
              	 //7.
              	 this.fetchData();
            });
        },

//actions.js
UPDATE_CARD({ dispatch, state }, { id, title, description, listId, pos }) {
  	//5.
        const payload = { title, description, listId, pos };
  
        return api.card
            .update({ id, payload })
            .then(() => {
          	//6.
                dispatch("FETCH_BOARD", { id: state.board.id });
            })
            .catch((err) => Promise.reject(err));
    },
          
  1. description의 경우 payload를 구성할 때, 입력된 값이 빈 공백일 경우에 Null값으로 전달하기위해 작성한 라인입니다.
  2. 제목이 없을 경우를 예외처리했습니다.
  3. inputTitle에 기존 데이터의 title을 할당하고, 데이터가 변했으므로 DOM이 업데이트 된 이후, nextTick()을 이용해서 focus를 이동시켰습니다.
  4. Store의 메서드를 이용해서 수정 API를 호출합니다.
  5. 전달받은 데이터로 payload객체를 구성해서 데이터 전달 하는 부분을 간결하게만들었습니다
  6. 카드 수정이 완료되면, dispatch()를 이용해서 보드 데이터를 다시 서버로부터 가져와 Board 컴포넌트를 업데이트합니다.
  7. 마찬가지로, 현재 카드 컴포넌트에서도 데이터를 다시 서버로 부터 가져와서 업데이트합니다.

3. 카드 드래그 앤 드롭 구현

//List.vue
 <draggable
            class="list-item__cardList list-group" //1.
            :list="data.cards"			   //2.
            :data-list-id="data.id"
            draggable=".card-item"		   //3.
            group="cardItem"			   //4.
            @end="onEnd"			   //5.
        >
            <card-item
                v-for="card in data.cards"
                :data="card"
                :key="card.pos"
            />
        </draggable>
  1. 라이브러리에서 제공하는 "list-group" 클래스를 적용한다.
  2. :list에 배열 형태의 데이터를 바인딩한다.
  3. draggable 속성으로 드래그할 클래스를 설정한다.
  4. group 잘 모르겠지만 적용안할 경우, 드래그 앤 드롭이 안된다..!!
  5. @end이벤트와 이벤트 핸들러 onEnd
  • 이벤트 핸들링, 이벤트 핸들러에 전달되는 객체

: https://github.com/SortableJS/sortablejs#event-object-demo

onEnd(event) {
  	    //1. 2.
            const { to, item } = event;

            const listId = to.dataset.listId;

            const currentCard = {
                id: item.dataset.cardId * 1,
                pos: 65535,
                listId: listId * 1,
            };
        },
  1. to : 드롭된 draggable 컴포넌트 엘리먼트
  2. item : 드래그된 엘리먼트(여기서는 ".card-item")
    => *주의 사항 : ".card-item", 드래그할 엘리먼트의 :key가 중복되어서 duplicate에러가 발생할 경우, item이 제대로 선택되지 않는다!!!
  3. from : 리스트 간 이동시 기존에 있던 draggable 컴포넌트 엘리먼트
  4. newIndex : to 엘리먼트를 기준으로 엘리먼트의 인덱스 값
  • card-item :key 중복에러 방지를 위해 카드 생성 로직을 수정
//AddCard.vue
const pos = this.getPos();

getPos() {
  	    //1.
            const list = this.board.lists.filter(
                (b) => b.id === this.listId
            )[0];
  	    //2.
            const lastCard = list.cards[list.cards.length - 1];
  	    //3.
            return lastCard ? lastCard.pos * 2 : 65535;
        }
  1. store에서 board데이터를 가져오고, 현재 속한 list의 id값을 통해 list데이터를 가져온다.
  2. 가져온 list의 cards프로퍼티에서 마지막 카드 데이터를 가져온다.
  3. 2번에서 가져온 카드가 있으면 가져온 카드의 pos 값에 2를 곱한 값을 리턴하고, 없으면 기본 pos 값인 65535를 리턴한다.

느낀점 : 강의에서 사용한 drag 라이브러리를 사용하지않고, 혼자 새로운 라이브러리를 사용하면서 기능을 익히는게 재미있기도 하고, 어렵지만 뿌듯했다 :-)
강의에서 사용한 방법을 현재 라이브러리에 맞춰서 사용할 계획이다.


* Reference

1. Vue.nextTick : https://kr.vuejs.org/v2/api/index.html#Vue-nextTick

profile
사람들에게 좋은 경험을 선사하고 싶은 주니어 프론트엔드 개발자

0개의 댓글