#Vue 인스턴스 생성
[Vue2]
//Vue2 application instance 생성방법
new Vue({
//component options
el: '#app', // mount할 element
template: '<p>{{firstName}} {{lastName}} aka {{alias}}</p>',, //화면에 표시할 요소
data: function() {
return {
firstName: 'choi',
lastName: 'coding',
alias: 'choicoding'
}
},
method: {
changeFirstName(first) {
this.firstName=first
},
}, //화면의 동작, 이벤트 handling할 메소드
created: function(){}, //life cycle hook (beforeCreate, beforeMount, mounted, ..)
watch: {
firstName: function (val, oldVal) {
console.log(oldVal,'->',val);
}
}, //data의 변화를 감시하여 대응할 동작
});
new Vue({
data: {
},
}).$mount('#app');
[Vue3]
//Vue3 application instance 생성 방법
Vue.createApp({
data() {
return {
a: 'adata'
}
}
}).mount('#app');
#Vue Directive[ v-on ]
이벤트함수 등록
v-on:이벤트="function"
>> v-on:은 @으로 대체될 수 있다.
ex) @click="function"
<div id="app">
<button v-on:click="minus">-</button>
<p>{{count}}</p>
<button v-on:click="plus">+</button>
</div>
<script>
Vue.createApp({
data(){
return{
count: 0
}
},
methods: {
plus(){
this.count++;
},
minus(){
this.count--;
}
}
}).mount('#app');
</script>
#Vue Directive[ v-for ]
리스트 렌더링
v-for=" alias in list"
<div id="app">
<ul>
<li v-for="item in items">{{item}}</li>
</ul>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
Vue.createApp({
data(){
return{
items: ['1번','2번','3번','4번']
}
}
}).mount('#app');
</script>
실행결과
**shortcut
ul>li +tap : ul와 하위 li 태그 동시 생성
#Vue Directive[ v-if / v-else-if / v-else ]
조건부 렌더링
v-if=" 조건"
<body>
<div id="app">
<p v-if="a">a가 존재하면 렌더링될 태그</p>
<p v-else-if="a==10">a=10이면 렌더링될 태그</p>
<p v-else>다 아니면 렌더링될 태그</p>
</div>
</body>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
Vue.createApp({
data(){
return{
a:1
}
}
}).mount('#app');
</script>
v-show="조건"
<p v-show="a">a가 존재하면 렌더링될 태그</p>
v-if 와 v-show의 차이점
v-if는 조건에 따라서 선택적으로 렌더링되고
v-show는 일단 렌더링되고 조건이 false이면 css로 display:none 이 된다.
v-if는 전환비용이 높기 때문에 만약 사용자가 v-if의 조건을 자주 바꾼다면
v-if가 전환될 때마다 재렌더링을 해야한다.
반면, v-show는 최초 렌더링 할때 같이 렌더링해두고 css만 전환하면 되기 전환비용이 낮다.
대신 최초 렌더링할때 비용이 더 높기 때문에
전환이 자주 발생한다면 v-show를, 전환비용보다 최초 렌더링시 비용이 더 크다면 v-show를 선택하는 것이 좋다.
#v-if 와 v-for 함께 사용하기
v-if와 v-for를 함께 사용하는 것은 권장되지 않는다.
//잘못된 코드
<ul>
<li
v-for="user in users"
v-if="user.isActive"
>
{{ user }}
</li>
</ul>
위 코드의 목표는 v-for로 users를 순회하면서 user의 isActive로 조건을 걸어 리스팅하는것이다.
하지만 위 코드를 실행하면 user프로퍼티를 찾을 수 없어 오류가 발생한다.
v-if가 v-for보다 우선순위가 높기 때문에
users의 user를 설정하기 전에 if의 user 프로퍼티를 먼저 찾기 때문에 찾을 수 없다는 것이다.
v-if와 v-for를 함께 사용하기 위해선
users를 먼저 필터링하거나 template 태그를 이용해 for지시어를 먼저 선언해주는 방법이 있다.
* computed property 사용하기
<ul>
<li
v-for="user in activeUsers" //계산된 프로퍼티 내를 순회한다.
>
{{ user }}
</li>
</ul>
computed: {
activeUsers() { //users를 필터링하여 activeUsers를 정의한다.
return this.users.filter(user => user.isActive)
}
}
* template tag 사용하기
<ul>
<template v-for="user in users"> //li를 래핑하고 li의 상위 레벨에서 for지시어를 사용함으로써 if보다 우선하게 한다
<li v-if="user.isActive">
{{ user }}
</li>
</template>
</ul>
#Vue Directive[ v-bind ]
데이터, id, class, style 바인딩
Vue.createApp({
data(){
return {
textClass: 'primary',
sectionid: 'tab1',
sectionStyle: {color:'red'},
isActive:true,
hasError:false,
classObject:{
active:true,
'text-danger':false
}
}
}
}).mount('#app');
* v-bind: 은 매우 자주 사용되기 때문에 v-bind를 생략하고 :만 붙여 사용할 수 있다.
v-bind를 이용하면 컴포넌트의 data를 바인딩 할 수 있다.
v-bind는 컴포넌트의 {{property}}뿐만 아니라 id, class, style 등 태그의 속성도 바인딩할 수 있다.
바인딩하는 data는 객체 또는 배열도 가능하다.
<div :class="[textClass, {active: isActive}]">클래스 바인딩</div>
active의 클래스 여부가 isActive에 의해 결정된다.
isActive가 true이므로 :class="[textClass, active] 배열이 되고
class="primary active"가 된다.
<div :id="sectionid" :style="sectionStyle">아이디 스타일 바인딩</div>
아이디와 스타일 바인딩의 예시이다.
아이디는 문자열로, 스타일은 객체로 바인딩 되었다.
<div class="static" :class="classObject">클래스 객체로 바인딩</div>
class="static"이 이미 존재하고 classObjecct가 바인딩된다.
이때, classObject는 true인 active만 바인딩되고 false인 'text-danger'는 바인딩 되지 않는다.
바인딩 결과는 static active가 된다.
<div :class="isActive ? textClass : ''">삼항연산 클래스 토글</div>
삼항 표현식을 사용할 수도 있다.
isAcitve이면 textClass가 바인딩된다.
삼항 조건의 결과값에는 문자열 또는 바인딩될 data가 들어간다.
#Vue Component 등록
app이라는 root 컴포넌트에 자식 컴포넌트들을 등록한다.
components: {
컴포넌트명: {body}
}
<div id="app">
<app-header></app-header>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
Vue.createApp({
components: {
//'component이름' :{body}
'app-header': {
template: '<h1>app 하위 컴포넌트 "app-header"</h1>'
}
}
}).mount('#app');
</script>
#app 태그 내에
<component명으로 태그를 작성한다.>
실행결과
dev tool의 Vue에
<Root> 하위 <AppHeader>컴포넌트가 등록된 것을 확인할 수 있다.
#Component간 통신
Component는 event와 props로 데이터와 신호를 주고받는다.
동일 레벨의 컴포넌트 간에 직접 통신은 불가능하다.
상위 컴포넌트에 event를 발생시켜 데이터를 전달할 다른 하위 컴포넌트로 prop을 전달하는 방식으로 통신한다.
Props
상위 컴포넌트에서 하위 컴포넌트에 전달하는 프로퍼티
* 하위 프로퍼티에 props 배열을 작성한다.
* html의 컴포넌트 태그에서 props를 바인딩한다.
v-bind:prop명="prop에 바인딩할 상위 컴포넌트의 프로퍼티명"
<div id="app">
<app-header v-bind:prop-title="title"></app-header>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
const appHeader = {
props:['propTitle'],
template: `<p>{{propTitle}}</p>`,
}
Vue.createApp({
data(){
return {
title: 'Title'
}
},
components: {
'app-header': appHeader,
}
}).mount('#app');
</script>
EventEmit
하위 컴포넌트에서 상위 컴포넌트로 이벤트를 발생시킴
* 하위 컴포넌트에서 this.$emit('발생시킬이벤트명') 을 작성한다.
* html의 컴포넌트 태그에서 이벤트 핸들러로 상위 컴포넌트에 메소드를 동작하게 한다.
v-on:하위컴포넌트에서 발생시킨 이벤트명="상위컴포넌트에서 동작할 메소드명"
<div id="app">
<app-header :prop-title="title"></app-header>
<app-contents @set-title="changeProp"></app-contents>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
const appHeader={
props:['propTitle'],
template:`<p>{{propTitle}}</p>`
}
const appContents={
template: `<button v-on:click="sendEvent">제목</button>`,
methods:{
sendEvent(){
this.$emit('setTitle');
}
}
}
Vue.createApp({
data(){
return{
title:''
}
},
methods:{
changeProp(){
this.title='newTitle'
}
},
components:{
'app-header':appHeader,
'app-contents':appContents
}
}).mount('#app');
</script>
동일 레벨의 컴포넌트간 통신이 이루어지는 과정
-> appContents내의 버튼에서 클릭이벤트가 발생하면
-> appContents 컴포넌트에 setTitle 이벤트를 발생시킨다.
-> setTitle 이벤트 핸들러에 의해 Root 컴포넌트의 changeProp함수가 실행된다.
-> changeProp 함수가 data를 갱신하고
-> data가 변경됨에 따라 props의 propTitle도 변경된다.
**html 태그 작성시 주의할점
html 파일에서 vue를 사용할 때 카멜케이스를 사용하면 인식하지 못하기 때문에 -(하이픈)을 사용한다.
이러한 문제는 .vue 파일 형식과는 관계없이 .html 파일에만 해당한다.
.vue 파일에는 카멜케이스로 작성하여도 된다.
<div id="app">
<app-contents @set-title="changeProp"></app-contents> //setTitle을 set-title로 changeProp은 속성명이 아닌 ""내의 문자열 값이기 때문에 관계 없다.
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
const appContents={
template: `<button v-on:click="sendEvent">제목</button>`,
methods:{
sendEvent(){
this.$emit('setTitle'); //카멜케이스
}
}
}
Vue.createApp({
methods:{
changeProp(){ //카멜케이스
this.title='newTitle'
}
},
components:{
'app-contents':appContents //컴포넌트명은 html에 작성될 태그명이므로 - 사용
}
}).mount('#app');
</script>