: 하위 컴포넌트의 템플릿을 부모 컴포넌트에서 작성한 템플릿으로 대체하기위한 방법
이름을 가지는 Slot
: 부모 컴포넌트의 템플릿을 자식 컴포넌트의 Slot가 더 명확히 매칭하기 위해서 사용한다.
//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>
<Modal>
<div slot="header">
<h2>
Create new board
<a href="" class="modal-default-button"
@click.prevent="SET_IS_ADD_BOARD(false)">×</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>을 대체해서 렌더링된다.
//Homde.vue
data() {
return {
boards : [],
}
}
AddBoard컴포넌트에서 바로 보드를 생성한 후, Store의 actions에 등록한 메서드를 통해서 바로 Board 데이터를 fetch할 수 있다.
AddBoard가 보여지는지 여부를 설정하는 데이터도 store에서 관리하면 토글하기 편하다.
- actions로 비동기 로직, mutations => state 갱신 => state를 통해서 데이터를 가져온다.
mapState, mapGetters, mapActions, mapMutations
: store의 프로퍼티들을 편리하게 가져올 수 있게 도와주는 역할.
- "mapState, mapGetters" : Vue인스턴스의 computed 속성
- "mapMutations, mapActions" : methods속성에 객체 전개 연산자 (Object Spread Operator)를 통해 Store에 접근한다.
객체 전개 연산자를 이용해 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.를 통해 접근이 가능하다.
- 각각, 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));
//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,
};
- 컴포넌트가 마운트(mount)된 후, ref 속성을 통해 커서(?)가 이동 하도록 하는 로직. Mounted 훅에서 실행한 이유 : mounted 훅은 컴포넌트가 DOM에 렌더링 된 이후에 실행되므로, ref 속성을 통해 해당 엘리먼트를 참조할 수 있다!!
- 0번과 다르게, created 훅에서도 사용할 수 있을 것 같다.
- window에 "keyup"이벤트를 바인딩하고, 입력 키 코드를 체크해서 "Escape"키가 입력 되었을 경우, 모달을 닫고 `window.onkeyup = null'을 통해 이벤트를 해제한다. => 더 좋은 방법 없을까?
//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 값을 변수로 치환해서 사용, 일괄 변경시에 용이하다.
:root {
--black-color : #000;
}
var(--black-color);
flex-shrink : 1 //컨테이너의 크기에 반응하여 작아진다.
flex-shrink : 0 //컨테이너 크기에 관계없이 크기를 유지한다.
=> element.offsetWidth;
정상 동작 : $("#wrapper").style.left = "-1200px"
정상 동작2 : $("#wrapper").style.left = -2400 + "px"
동작 X : $("#wrapper").style.left = -1200
: $wrapper.style.transform = "translate(x, y)";
: event.target => 이벤트가 실행된 엘리먼트
: event.currentTarget => 이벤트가 바인딩된 객체