10/16,17

김승우·2020년 10월 16일
0

TIL

목록 보기
28/68

Vue 인프런 강의 복습

- ref : https://www.inflearn.com/course/vuejs/

* Board 생성

  • Idea : Board를 생성하려면, 서버에 데이터를 전송해야한다.
    => Api를 호출해서 서버에 데이터를 전송하고, 다시 서버로부터 보드 리스트에 대한 데이터를 호출해서 화면을 렌더링한다.

* Modal.vue 컴포넌트 생성

  • Slot : 컨텐츠가 대체되는 영역

: 하위 컴포넌트의 템플릿을 부모 컴포넌트에서 작성한 템플릿으로 대체하기위한 방법

  • 이름을 가지는 Slot

    : 부모 컴포넌트의 템플릿을 자식 컴포넌트의 Slot가 더 명확히 매칭하기 위해서 사용한다.

  1. 자식 컴포넌트 예(Modal.vue)
//Modal.vue
<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>
  1. 부모 컴포넌트 예(AddBoard.vue)
<Modal>
    <div slot="header">
      <h2>
        Create new board
        <a href="" class="modal-default-button" 
          @click.prevent="SET_IS_ADD_BOARD(false)">&times;</a>
      </h2>
    </div>
    <div slot="body">
      <form id="add-board-form" 
        @submit.prevent="addBoard">
        <input class="form-control" type="text" v-model="input" ref="input">
      </form>
    </div>
    <div slot="footer">
      <button class="btn" :class="{'btn-success': valid}" type="submit" 
        form="add-board-form" :disabled="!valid">
        Create Board</button>
    </div>
  </Modal>

: 부모 컴포넌트의 태그 slot속성의 값과 자식 컴포넌트의 slot태그의 name 속성이 같은 부분이 대체된다.
: AddBoard.vue의 <div slot="header">가 Modal.vue의 <slot name="header"></slot>을 대체해서 렌더링된다.

* Vue Store

  • 애플리케이션의 데이터를 하나의 저장소에서 관리하기 위해서 사용

- Store 사용 안할경우

  1. Addboard에서 보드 생성 로직 실행 => $emit("submit")을 통해 submit 이벤트를 트리거하고, Home 컴포넌트에서 다시 Board
    데이터를 fetch하는 로직으로 구성,
//Homde.vue
data() {
  return {
    boards : [],
  }
}

- Store를 사용할 경우

  1. AddBoard컴포넌트에서 바로 보드를 생성한 후, Store의 actions에 등록한 메서드를 통해서 바로 Board 데이터를 fetch할 수 있다.

  2. AddBoard가 보여지는지 여부를 설정하는 데이터도 store에서 관리하면 토글하기 편하다.

  • actions로 비동기 로직, mutations => state 갱신 => state를 통해서 데이터를 가져온다.
  1. mapState, mapGetters, mapActions, mapMutations

    : store의 프로퍼티들을 편리하게 가져올 수 있게 도와주는 역할.

    • "mapState, mapGetters" : Vue인스턴스의 computed 속성
    • "mapMutations, mapActions" : methods속성에 객체 전개 연산자 (Object Spread Operator)를 통해 Store에 접근한다.
  2. 객체 전개 연산자를 이용해 Store 사용하는 이유

    • 현재 Vue 인스턴스의 다른 속성들과 같이 사용하는데 용이하다.
//Homde.vue
//1. vuex의 속성들을 import 한다.
import { mapState, mapActions, mapMutations } from "vuex";

//2. 객체 전개 연산자를 이용해 속성을 가져온다.
computed: {
        ...mapState(["boards", "showAddBoard"]),
    },
methods: {
        ...mapMutations(["SET_IS_ADD_BOARD"]),
        ...mapActions(["FETCH_BOARDS"]),
        fetchData() {
            this.isLoading = true;
            this.FETCH_BOARDS().then(() => (this.isLoading = false));
        },
        onCreateBoard() {
            this.showAddBoard = false;
            this.fetchData();
        },
    },
		
  • mapState, mapActions...를 이용해 가져온 속성들은 Vue 인스턴스 내에서 this.를 통해 접근이 가능하다.
  1. commit, dispatch
    • 각각, store의 mutations와 actions에 등록되어있는 메소드를 호출할때 사용
//1. commit => mutations
this.$store.commit("LOGIN", token);

//2. dispatch => actions
//2.1 mapActions에 등록되어있을 경우, this를 통해서 접근이 가능
this.FETCH_BOARDS().then(() => (this.isLoading = false));

//2.2 Vue인스턴스에서 $store를 통해서 store에 접근할 수 있고, dispatch()를 이용해서 actions에 등록된 메서드를 사용한다.
this.$store
.dispatch("FETCH_BOARDS")
.then(() => (this.isLoading = false));

* Modal창 Esc키 입력 및 바깥 클릭 시 사라지게 만들기

  • 소스
//AddBoard.vue
mounted() {
	//0.
        this.$refs.boardTitle.focus();
	//1.
        this.setKeyupEvent();
        this.setClickcOutSideEvent();
},

methods : {
//2.
setKeyupEvent() {
	const self = this;
	window.onkeyup = function(e) {
		if (e.keyCode !== KEYCODE.esc) return;
			self.SET_IS_ADD_BOARD(false);
			window.onkeyup = null;
		};
	},
//3.
setClickcOutSideEvent() {
	const self = this;
	window.onclick = function(e) {
		const $target = e.target;
		if ($target.className === "modal-wrapper") {
			self.SET_IS_ADD_BOARD(false);
			window.onclick = null;
			}
		};
	},
}

//utils/constants.js
export const KEYCODE = {
    esc: 27,
    enter: 13,
};

  1. 컴포넌트가 마운트(mount)된 후, ref 속성을 통해 커서(?)가 이동 하도록 하는 로직. Mounted 훅에서 실행한 이유 : mounted 훅은 컴포넌트가 DOM에 렌더링 된 이후에 실행되므로, ref 속성을 통해 해당 엘리먼트를 참조할 수 있다!!
  1. 0번과 다르게, created 훅에서도 사용할 수 있을 것 같다.
  2. window에 "keyup"이벤트를 바인딩하고, 입력 키 코드를 체크해서 "Escape"키가 입력 되었을 경우, 모달을 닫고 `window.onkeyup = null'을 통해 이벤트를 해제한다. => 더 좋은 방법 없을까?

* 에러 처리

  • 주소창에 입력을 통해 생성되어있지 않은 board를 호출하려할 경우 404 not found에러 발생했다.
//api/index.js
const NOTFOUND = 404;

//noNotFound()
const noNotFound = () => {
    alert("존재하지 않는 보드입니다.");
    router.push("/");
};

//Axios Wrapping 함수
const request = (method, url, data) => {
    return axios({
        method,
        url: DOMAIN + url,
        data,
    })
        .then((result) => result.data)
        .catch((result) => {
            const { status } = result.response;

            if (status === UNAUTHROZIED) {
                onUnauthorized();
            } else if (status === NOTFOUND) {
                noNotFound();
            }
            throw result.response;
        });
};
  • axios가 response 객체의 status코드가 404일 경우 alert 메시지를 출력하고, 루트 경로로 이동하는 로직을 작성했다.
  • 실행되는 순서 : 라우터의 beforeEnter => 토큰 값이 있으므로 next()함수 실행 => 라우팅 경로에 해당하는 컴포넌트 렌더링 => 라이프 사이클 훅에 있는 api 함수 호출
    => 404 에러 발생

CSS

  • CSS :root
  • CSS 값을 변수로 치환해서 사용, 일괄 변경시에 용이하다.
  • 선언 예
:root {
	--black-color : #000;
}
  • 사용 예
var(--black-color);
  • flex-shrink : 컨테이너보다 아이템이 너비가 클때, 줄어드는지 여부를 결정한다.
flex-shrink : 1 //컨테이너의 크기에 반응하여 작아진다.
flex-shrink : 0 //컨테이너 크기에 관계없이 크기를 유지한다.

* Javascript

1. 엘리먼트 너비 구하기

: https://stackoverflow.com/questions/294250/how-do-i-retrieve-an-html-elements-actual-width-and-height

=> element.offsetWidth;

2. 엘리먼트(wrapper) position, left 변경시키기

정상 동작 : $("#wrapper").style.left = "-1200px"

정상 동작2 : $("#wrapper").style.left = -2400 + "px"

동작 X : $("#wrapper").style.left = -1200

3. 엘리먼트(wrapper) transform translate 변경시키기

: $wrapper.style.transform = "translate(x, y)";

4. event.target Vs event.currentTarget

: event.target => 이벤트가 실행된 엘리먼트

: event.currentTarget => 이벤트가 바인딩된 객체


Reference

  1. Vue Modal 컴포넌트 : https://kr.vuejs.org/v2/examples/modal.html
  2. Vue Slot : https://kr.vuejs.org/v2/guide/components-slots.html
  3. Vue Store : https://vuex.vuejs.org/kr/guide/state.html
  4. Modal 바깥쪽 클릭시 : : https://ej2.syncfusion.com/vue/documentation/dialog/how-to/close-dialog-while-click-on-outside-of-dialog/
profile
사람들에게 좋은 경험을 선사하고 싶은 주니어 프론트엔드 개발자

0개의 댓글