2020/03/18
MVVM 패턴의 ViewModel 레이어에 해당하는 화면 단 라이브러리
model과 view 사이의 관계를 어떻게 처리할지에 대한 해결책. UI(view)와 데이터(model)을 분리하여 작업하고, 상호연계를 하게 되는데, 이 연계 방식이 어떠냐에 따라 나뉘게 된다.
오늘은 vue를 만나는 첫 날이기 때문에, 설치를 진행하고 간단한 작업을 진행해보려고 합니다.
먼저 저는 Vue CLI를 사용하였습니다.
npm install -g @vue/cli
프로젝트를 생성합니다.
vue create firstVue
오늘 완성할 친구의 모습입니다. prop으로 이름,나이 등을 전달해주고, 오른쪽 자식 component에서 수정을 해서 노란 버튼을 클릭하게 되면 부모 component에게 전달이 되어 수정된 정보와 수정일자가 왼쪽에 다시 렌더링 하게 됩니다.
일단 vue는 template / script / style 세 가지로 구분 되는 것 같았다.
template에서는 html을 이용하여 view단을 작성하게 된다. react처럼 하나의 태그만 있어야한다.
<template>
<!-- 하나의 태그로 감싸야한다. main 태그 사용 -->
<main class="main_container">
<header class="title_header">User Information</header>
<div class="user_namebox">
User Name
<p class="user_name">{{ userName }}</p>
</div>
<div class="detail_box">
<!-- UserInfo와 UserChange는 자식 component -->
<UserInfo
:name="userName"
:age="userAge"
:number="userNumber"
:cat="isCat"
></UserInfo>
<UserChange
@changeUser="allChange"
:name="userName"
:age="userAge"
:number="userNumber"
:cat="isCat"
></UserChange>
</div>
</main>
</template>
@changeUser
는 $emit
인데 밑에서 다시 설명하도록 하겠다.:name = "userName
prop으로 자식에게 전달해 주는 것. :
이것은 축약한 것이라고 하는데, 추후에 다시 공부를 해야한다.<script>
import UserInfo from "./components/UserInfo";
import UserChange from "./components/UserChange";
export default {
components: {
UserInfo,
UserChange
}
};
</script>
<script>
import UserInfo from "./components/UserInfo";
import UserChange from "./components/UserChange";
export default {
components: {
UserInfo,
UserChange
},
data() {
return {
userName: "jotang",
userAge: 32,
userNumber: "000-111-222",
isCat: false
};
},
}
</script>
<script>
import UserInfo from "./components/UserInfo";
import UserChange from "./components/UserChange";
export default {
...
methods: {
allChange(user) {
(this.userName = user.name),
(this.userAge = user.age),
(this.userNumber = user.number),
(this.isCat = user.cat);
console.log("받앗따");
}
}
};
</script>
@changeUser
라는 것을 자식으로 부터 $emit
을 통해 전달받게 되었을 때 실행할 작업을 methods에 정의해준다.script부분만 어떻게 진행했는지 작성하도록 하겠습니다.
<script>
import { eventBus } from "../main";
// 병렬로 되어있는 자식 component 들끼리 데이터를 주고 받을 수 있도록
// eventBus를 만들어 사용하였다. 밑에서 다시 알아보겠다.
export default {
// props로 전달 받아온 것은 []에 정의한다.
props: ["name", "age", "number", "cat"],
// 수정이 되었을 때, 수정일자를 처음에는 null로 설정
data() {
return {
editDate: null
};
},
// clearTime이라는 함수는 date를 인자로 받아오게된다.
// 인자로는 editDate가 들어간다. "clearTime(editDate)"
methods: {
clearTime(date) {
if (date !== null) {
let hour = date.getHours();
let min = date.getMinutes();
let year = `${date.getFullYear()}-${date.getMonth() +
1}-${date.getDate()}`;
return `${year} ${hour}:${min}`;
} else {
this.editDate = null;
}
}
},
// 반려묘의 유무에 따라 있음과 없음을 표시하게 해주는 부분
computed: {
hasCat() {
return this.cat === true ? "있음" : "없음";
}
},
// 라이플사이클메서드 훅
created() {
eventBus.$on("makeTime", date => {
this.editDate = date;
});
}
};
</script>
react의 componentDidMount와 비슷한 느낌?
각 Vue 인스턴스는 생성될 때 일련의 초기화 단계를 거칩니다. 데이터 관찰 설정이 필요한 경우, 템플릿을 컴파일하는 경우, 인스턴스를 DOM에 마운트하는 경우, 그리고 데이터가 변경되어 DOM를 업데이트하는 경우가 있습니다. 그 과정에서 사용자 정의 로직을 실행할 수있는 라이프사이클 훅 도 호출됩니다. created 훅은 인스턴스가 생성된 후에 호출됩니다.
다음 vue시간에 lifeCycle에 대하여 더 상세히 공부하도록 하겠습니다.
<script>
// coming soon
import { eventBus } from "../main";
export default {
props: ["name", "age", "number", "cat"],
// 부모로 부터 받은 props를 수정하기 위해서 user라는 객체에 저장
data() {
return {
user: {}
};
},
methods: {
isCat() {
this.user.cat = true;
},
noCat() {
this.user.cat = false;
},
// 버튼을 눌렀을 때 실행될 함수.
// $emit
// eventBus
submit() {
console.log(this.user);
this.$emit("changeUser", this.user);
eventBus.$emit("makeTime", new Date());
}
},
// user라는 객체에 저장하여 component에서 사용한다
created() {
this.user.name = this.name;
this.user.age = this.age;
this.user.number = this.number;
this.user.cat = this.cat;
},
computed: {
hasCat() {
return this.cat === true ? "있음" : "없음";
}
}
};
사실 아직 자세히는 알지 못한다. 자식 컴포넌트에서 부모에게 받은 props를 바꾸게 될 때, 부모컴포넌트에서 그 값이 바뀌어버리게 되면, 자식에게서 바꿨던 값은 소용이 없어지게 된다.(부모의 값으로 덮어씌어짐)
그래서 user라는 새로운 객체에 전달받은 값을 저장하여 사용하고, 버튼을 클릭했을 때, $emit
을 통해서 부모에게 나이거 값을 바꿀거야 하고 알려준다
this.$emit("changeUser", this.user);
// 첫번째 인자는 부모에게 알려줄 이름.
// 두번째 인자는 넘겨줄 객체
// 함수로 작성해서 본다면 이렇게 이해할 수 있다.
changeUser(this.user){
...
}
<UserChange
@changeUser="allChange"
:name="userName"
:age="userAge"
:number="userNumber"
:cat="isCat"
>
<!-- 부모가 딱 쳐다보고있음. changeUser오면 allChange실행! -->
</UserChange>
컴포넌트간 통신을 위해 사용되는 것이 eventBus
vue는 단방향 통신이다.(부모 —> 자식) 하지만 경우에 따라 서로 관련없는 독립적인 컴포넌트끼리 이벤트를 통신해야 하는 경우가 생긴다. 이 경우를 편하게 도와주는 vuex라는 상태관리 라이브러리가 있지만, 규모가 작을 경우 단순히 eventBus를 활용하여 간단하게 처리할 수 있다.
// main.js에 작성
export const eventBus = new Vue();
// 사용할 컴포넌트에서 import
import { eventBus } from '../main';
eventBus.$emit('makeTime', new Date());
$emit
메소드를 사용한다.
makeTime이라는 이름으로 new Date() 데이터를 전달해준다.
created() {
eventBus.$on("makeTime", date => {
this.editDate = date;
});
}
이벤트를 받을 때에는 $on
메소드를 사용한다. 첫번째 파라미터에는 이벤트의 이름, 두번째 파라미터로는 콜백함수를 지정한다.