Evan You가 2013년에 발표한 Front-end JavaScript framework
Angular와 React 장점만 가진 프레임워크
SPA(Single Page Application) 목적의 프레임워크
Vue-CLI : Vuejs 프로젝트(코드, 디렉토리 구조)를 생성 해주는 라이브러리
CRA(Create Project App) : ReactJS 프로젝트(코드, 디렉토리 구조)를 생성 해주는 라이브러리
Vite : 다양한 JS(TS) 프로젝트를 생성해주는 라이브러리
JS 컴파일러가 필요함
Bundling(번들링) 도구가 필요함
<script src="https://cdn/jsdelivr.net/npm/vue/dist/vue.js"></script>
npm install -g @vue/cli
View (Template)
Model
ViewModel
Controller 역할을 하며 Vue 객체가 담당함
가장 중요한 역할은 View와 Model의 연결
📋 코드 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vuejs 기본구조</title>
<!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<!-- view -->
<div id="app">
{{ message }}
</div>
<script>
// Model
let model = {
message : '안녕하세요 Vue!'
};
// ViewModel - Vue 객체
var app = new Vue({
el: '#app', // 연결할 View 선택
data: { // 사용할 Model 설정
message: model.message
}
});
</script>
</body>
</html>
📋 실행 📋
📋 코드 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vuejs data종류</title>
<!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!-- data 종류 -->
message:{{ message }}<br>
age:{{ age }}<br>
phones:{{ phones[0] }} {{ phones}}<br>
author:{{ author.name }} {{author.age}}<br>
isMarried:{{ isMarried }}<br>
<hr>
<!-- {{}}을 mustache(이중중괄호)라고 부른다.-->
1) message:{{ message }}<br>
2) age(산술연산):{{ age+1 }}<br>
3) 30보다 적냐?(비교연산):{{age<30}}<br>
4) 이름길이:{{ author.name.length}}<br>
5) 결혼여부(3항연산자):{{ isMarried?"기혼":"미혼" }}<br>
6) 문자열_대문자함수:{{message.toUpperCase()}}<br>
7) 문자열_소문자함수:{{message.toLowerCase()}}<br>
7-1) 문자열 대문자와 소문자 출력 함수:{{upper_lower_case()}}<br>
8) 문자열_부분열함수:{{message.slice(0,3)}}<br>
9) 문자열_치환함수:{{message.replace("Vue","vuex")}}<br>
10) 수치_정수변환함수:{{Number.parseInt(height)}}<br>
11) 배열_join함수:{{phones.join(":")}}
</div>
<script>
var app = new Vue({
el: '#app',
data: {
message: '안녕하세요 Vue!',
age: 20,
height: 178.535,
phones: [100, 200, 300],
author: { name: "홍길동", age: 20 },
isMarried: true
}, // data
methods: {
upper_lower_case() {
return this.message.toUpperCase() + ' || ' +this.message.toLowerCase()
}
}
});
</script>
</body>
</html>
📋 실행 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vuejs template</title>
<!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
This will be replaced !
</div>
<script>
var app = new Vue({
el: '#app',
data: {
message: '안녕하세요 Vue!'
},
template: `<div>{{message}}</div>` //template 속성값에는 반드시 root태그 필요
});
</script>
</body>
</html>
📋 실행 📋
Vue 객체의 유효범위는 Vue 객체가 관리하는 HTML의 범위 (el 속성에 지정된 영역)
해당 범위에서만 Vue가 동작하기 때문에 지정된 scope를 벗어나면 {{}} 표현식 등 단순한 문자열로 처리
Vue 객체 동작 과정
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vuejs app scope</title>
<!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
scope범위포함:{{ message }}
</div>
scope범위 미포함:{{ message }}
<script>
var app = new Vue({
el: '#app',
data: {
message: '안녕하세요 Vue!'
}
});
</script>
</body>
</html>
📋 실행 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>directive v-text, v-html, v-once</title>
<!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<ul>
<li>{{ message }}</li>
<li><span v-text="message"></span></li>
<li v-html="message"></li>
<li v-once>{{message}}</li>
</ul>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
message: '<h1>안녕하세요 Vue!</h1>'
}
});
</script>
</body>
</html>
📋 실행 📋
v-bind
html의 속성인 id, class, style 등에 model 값을 연결할 때 사용하는 단방향 바인딩
연동하려는 대상에 따라 v-bind:id, v-bind:class, v-bind:style 등 사용
축약형으로 v-bind 생략 가능
html의 class 속성의 경우 여러 값 설정 가능
📋 코드 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>directive v-bind</title>
<!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<style>
.red-accent {
color: red;
}
</style>
</head>
<body>
<div id="app">
<ul v-bind:id="mid">
<li v-bind:class="mclass">클래스바인딩</li>
<li :style="mstyle">스타일바인딩</li>
<li><a :href="link.mhref" :title="link.mtitle">go</a></li>
</ul>
<img v-bind:src="user_imgs[0]" /><br/>
<img :src="user_imgs[1]" />
</div>
<script>
var app = new Vue({
el: '#app',
data: {
mid: "list",
mclass: "red-accent",
mstyle: "color:blue",
link: {
mhref: "http://vuejs.org",
mtitle: "Vuejs"
},
user_imgs :
["https://reqres.in/img/faces/1-image.jpg",
"https://reqres.in/img/faces/2-image.jpg"] ,
}
});
</script>
</body>
</html>
📋 실행 📋
📋 코드 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>directive v-bind 멀티 class속성</title>
<!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<style>
.set1 {
color: red;
}
.set2 {
background-color: blue
}
.set3 {
font-style: italic;
}
</style>
</head>
<body>
<div id="app">
<div :class="{set1:s1, set2:s2, set3:s3}">
Hello
</div>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
s1: true,
s2: false,
s3: false,
}
});
</script>
</body>
</html>
📋 실행 📋
📋 코드 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>directive v-bind 동적 전달 인자</title>
<!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<style>
.set1 {
color: red;
}
</style>
</head>
<body>
<div id="app">
<div :[mid]="xxx" :[mclass]="s1">
Hello
</div>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
mid: "id",
mclass: "class",
xxx: "v1",
s1: "set1"
}
});
</script>
</body>
</html>
📋 실행 📋
v-model
view와 model 사이의 양방향 데이터 바인딩에 사용되는 디렉티브
사용자로부터 값을 입력 받는 <input>, <select>, <textarea> 등에서 사용
기능 추가하기 위한 수식어 제공 ('.'
이용해서 설정, 여러 속성 chaining 가능)
📋 코드 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>directive v-model</title>
<!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div>
이름1:<input v-model="username" /><br>
<!-- 이름2(lazy):<input v-model.lazy="username" /><br> -->
입력한 이름:{{username}}<br>
<hr/>
나이1:<input v-model="age" /><br>
나이2(number):<input v-model.number="age" /><br>
입력한 나이:{{age}}<br>
<hr/>
주소1:<input v-model="address" /><br>
주소2(trim):<input v-model.trim="address" /><br>
입력한 주소:{{address}}<br>
입력한 주소:{{address.length}}<br>
<hr/>
출생연도(lazy.number):<input v-model.lazy.number="year"><br>
입력연도:{{year}}<br>
<hr/>
배열1:<input type="checkbox" v-model="team" value="A">A<br>
배열2:<input type="checkbox" v-model="team" value="B">B<br>
배열3:<input type="checkbox" v-model="team" value="C">C<br>
선택한 배열:{{team}}
<hr/>
<input type="checkbox" v-model="isFlag">user Image변경 <br/>
<img :src="isFlag?user_imgs[0]:user_imgs[1]" />
</div>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
username: "",
age: '',
address: '',
year: '',
team: [],
user_imgs :
["https://reqres.in/img/faces/1-image.jpg",
"https://reqres.in/img/faces/2-image.jpg"],
isFlag: true
}
});
</script>
</body>
</html>
📋 실행 📋
📋 코드 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>directive v-model 2</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<style>
.red-accent {
color: red;
}
</style>
</head>
<body>
<div id="select">
<label>가장 좋아하는 캐릭터는?</label>
<input type="text" v-model.trim="favorite"><br>
<label>팀 멤버를 선택하세요</label>
<input type="checkbox" value="1" v-model="team"><label>아이언맨</label>
<input type="checkbox" value="2" v-model="team"><label>토르</label>
<input type="checkbox" value="3" v-model="team"><label>헐크</label><br>
<label>출생 연도는?</label>
<input type="text" v-model.lazy.number="year"><br>
</div>
<hr>
<div id="result">
<p>당신의 선택은
<ul>
<li>캐릭터:{{favorite}}</li>
<li>팀:{{team}}</li>
<li>출생년도:{{year}}</li>
</ul>
</p>
</div>
<script>
let model = { favorite: "", team: [], year: "" }
var select = new Vue({
el: '#select',
data: model
});
var result = new Vue({
el: '#result',
data: model
});
</script>
</body>
</html>
📋 실행 📋
v-show
v-if
조건 불일치시 렌더링 방식 : 렌더링하지 않음
이에 따른 비용 : 토글 비용이 큼
유용한 경우 : 자주 바뀌지 않을 때
📋 코드 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>directive v-if, v-show</title>
<!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<input type="checkbox" v-model="isShow" />Image 보여주기
isShow 값은 {{isShow}} <br/>
<img src="images/error.png" width="20" height="20" v-show="isShow" /><br/>
나이:<input v-model.number="age" /> <br/>
<img v-show="age < 0" src="images/error.png" width="20" height="20">
<hr>
당신은:
<span v-if="age < 0">입력오류</span>
<span v-else-if="age < 8">미취학</span>
<span v-else-if="age < 19">미성년</span>
<span v-else>성년</span>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
age: '',
isShow:false,
}
});
</script>
</body>
</html>
📋 실행 📋
v-for
template 태그
<template>는 여러 요소를 묶어서 반복 렌더링 할 때 요소를 묶어주는 태그
실제 렌더링 내용에는 포함되지 않고, 단지 요소들을 그룹핑하는 용도로 사용
📋 코드 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>directive v-for</title>
<!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div>
<h1>배열 반복1</h1>
<ul>
<li v-for="(value) in heros">{{value}}</li>
</ul>
<h1>배열 반복2</h1>
<ul>
<li v-for="(value,index) in heros" :key="index">{{index}}:{{value}}</li>
</ul>
<h1>객체 반복1</h1>
<ul>
<li v-for="(value,key) in hero">{{key}}:{{value}}</li>
</ul>
<h1>객체 반복2</h1>
<ul>
<li v-for="(value,key,index) in hero" :key="index">{{index}}:{{key}}:{{value}}</li>
</ul>
</div>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
heros: ["A", "B", "C"],
hero: {
name: "홍길동",
age: 20,
address: "서울"
}
}
});
</script>
</body>
</html>
📋 실행 📋
📋 코드 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>directive v-for template</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<template v-for="(value, index) in heroes">
<div>
<p>등장순서:{{index}}, 이름:{{value}}</p>
</div>
<hr v-if="index % 2==0">
</template>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
heroes: ["아이언맨", "헐크", "토르", "캡틴아메리카", "비전"],
ironMan: {
name: "토니스타크",
nickName: "깡통"
}
}
});
</script>
</body>
</html>
📋 실행 📋
$options
속성 이용$el
속성 이용$data
사용라이프 사이클 커스터마이징 로직
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue 객체</title>
<!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
{{ message }}
</div>
<script>
var app = new Vue({
el: '#app',
data: {
message: '안녕하세요 Vue!'
}
});
console.log("Vue객체:", app)
console.log("el접근:", app.$el)
console.log("message 접근1:", app.$data.message)
console.log("message 접근2:", app.message)
</script>
</body>
</html>
📋 실행 📋
함수를 속성으로 갖는 객체
methods 속성과 달리 생성 시점에 계산된 값을 반환하고, 이후에는 캐시값을 사용
호출시 반드시 함수명만 사용
📋 코드 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>vue 객체 methods, computed</title>
<!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<input type="number" v-model="num" /><br />
num : {{num}}<br />
message : <input type="text" v-model="message" />
<p>원본 메시지: "{{ message }}"</p>
<p>역순으로 표시한 메시지: "{{ reversedMessage }}"</p>
</div>
<script>
var app = new Vue({
el: "#app",
data: {
message: "Hello",
num: 0,
},
// methods 함수는 기본적으로 호출할때마다 매번 호출된다. (캐시기능없음)
// 반드시 () 이용
// message 아닌 num 변경해도 계속 수행됨 (불필요한 렌더링 계속 발생)
methods: {
// reversedMessage() {
// 위와 동일
// reversedMessage: function () {
// console.log("methods reverseMessage");
// return this.message.split("").reverse().join(""); // olleH
// },
}, // methods
// computed 함수는 기본적으로 한번만 호출된다. ( 캐싱 기능 )
// () 사용안함
computed: {
reversedMessage: function () {
console.log("computed reverseMessage")
return this.message.split("").reverse().join("");
},
},
}); // computed
</script>
</body>
</html>
📋 실행 📋
📋 코드 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue 객체 methods, computed 화면 재렌더링시</title>
<!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<input type="number" v-model="num">
값:{{num}}<br>
{{xxx()}}{{xxx()}}
{{yyy}}{{yyy}}
</div>
<script>
var app = new Vue({
el: '#app',
data: {
num: 0
},
// methods 함수는 기본적으로 호출할때마다 매번 호출된다. (캐시기능없음)
// 반드시 () 이용
// 화면이 다시 랜더링 될때마다 화면에서 사용되고 있는 methods들이 모두 다시 실행된다
methods: {
xxx() {
console.log("xxx");
}
},
// computed 함수는 기본적으로 한번만 호출된다. ( 캐싱 기능 )
// () 사용안함
// 화면이 다시 랜더링 여부와 상관없이 실행 안됨.
computed: {
yyy() {
console.log("yyy");
}
}
});
</script>
</body>
</html>
📋 실행 📋
📋 코드 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dvue 객체 methods, computed Data 변경시</title>
<!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<input type="number" v-model="num">
값:{{num}}<br>
{{xxx()}}{{xxx()}}
{{yyy}}{{yyy}}
</div>
<script>
var app = new Vue({
el: '#app',
data: {
num: 0
},
// methods 함수는 기본적으로 호출할때마다 매번 호출된다. (캐시기능없음)
// 반드시 () 이용
// 화면이 다시 랜더링 될때마다 화면에서 사용되고 있는 methods들이 모두 다시 실행된다
methods: {
xxx() {
console.log("xxx", this.num);
}
},
// computed 함수는 기본적으로 한번만 호출된다. ( 캐싱 기능 )
// () 사용안함
// 화면이 다시 랜덩링 여부와 상관없이 실행 안됨.
// 함수안에서 data 접근코드 지정하고 data가 변경되면 호출된다.
computed: {
yyy() {
console.log("yyy", this.num);
}
}
});
</script>
</body>
</html>
📋 실행 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue 객체 watch/title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<input type="number" v-model='v1'>+<input type="number" v-model='v2'>={{sum}}
</div>
<script>
var app = new Vue({
el: '#app',
data: {
v1: 0,
v2: 0,
sum: 0
},
// 1. watch 속성의 함수명은 반드시 data 속성명과 일치해야 된다.
// 2. methods 및 computed 함수도 data 속성이 변경되면 자동으로 호출되지만,
// 반드시 명시적으로 함수명을 지정한 경우에만 해당된다.
// 하지만 watch는 명시적으로 호출하지 않아도 자동으로 호출된다.
watch: {
v1(newValue, oldValue) {
console.log("v1값 변경됨", oldValue, newValue);
this.sum = Number.parseInt(newValue) + Number.parseInt(this.v2);
},
v2(newValue, oldValue) {
console.log("v2값 변경됨", oldValue, newValue);
this.sum = Number.parseInt(this.v1) + Number.parseInt(newValue);
}
}
});
bookList = [
{title: "java", price:100},
{title: "java2", price:200},
{title: "java3", price:300}
]
</script>
</body>
</html>
📋 실행 📋
{{}} 표현식 또는 v-bind에서 텍스트 형식화하는 기능 제공
📋 코드 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue 객체 filter 지역적 </title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<span>원본:{{name}}</span><br>
<span>대문자로:{{name|toCap}}</span><br>
<span>첫 4글자만 대문자:{{name|subStr(0,4)|toCap}}</span>
</div>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
name: 'HongKilDong',
price: 1000000000
},
filters: {
toCap(param) {
return param.toUpperCase();
},
subStr(param, start, end) {
console.log(start, end);
return param.substr(start, end);
}
}
});
</script>
</body>
</html>
📋 실행 📋
📋 코드 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue 객체 filter 전역적</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<span>원본1:{{name}}</span><br>
<span>대문자로1:{{name|toCap}}</span><br>
</div>
<div id="app2">
<span>원본2:{{name}}</span><br>
<span>대문자로2:{{name|toCap(1,2)}}</span><br>
</div>
<script>
//전역객체
Vue.filter('toCap', (param, s, e) => {
console.log(s, e);
return param.toUpperCase();
});
var app = new Vue({
el: '#app',
data: {
name: 'EvanYou'
}
});
var app2 = new Vue({
el: '#app2',
data: {
name: 'JohnResig'
}
});
</script>
</body>
</html>
📋 실행 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue 객체 lifecycle hook</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<h3 v-html="num"></h3>
<button @click="plus">+</button>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
num: 0,
title: "hook method"
},
methods: {
plus() {
return ++this.num;
}
},
beforeCreate() {
// 아직 el 이나 data가 연동되지 않았다.
console.log("beforeCreate", this.title, this.$el);
},
created() {
// data, computed, methods, watch 설정이 완료된다.
console.log("created", this.title, this.$el);
},
beforeMount() {
// data와 el이 준비 되었지만 아직 화면이 대체되지 않았다.
console.log("beforeMount", this.title, this.$el.innerHTML);
console.log("beforeMount", document.querySelector("#app").innerHTML);
},
mounted() {
// data와 el이 준비 되었으며 화면이 Virtual DOM으로 대체되었다.
console.log("mounted", this.title, this.$el.innerHTML);
console.log("mounted", document.querySelector("#app").innerHTML);
},
beforeUpdate() {
// + 를 누르면 값이 업데이트 되려고 한다. 값은 변경되었으나 화면 갱신전이다.
console.log("beforeUpdate", this.num, document.querySelector("#app").innerHTML);
},
updated() {
// 값이 업데이트 되었고 화면도 갱신 되었다.
console.log("updated", this.num, document.querySelector("#app").innerHTML);
},
beforeDestory() {
// 객체가 삭제 되기 직전이다.
console.log("beforeDestory", this.title, this.$el);
},
destroy() {
// 객체가 삭제된 이후이다.
console.log("destroy", this.title, this.$el);
}
});
console.log(app);
</script>
</body>
</html>
📋 실행 📋
DOM 요소에 이벤트 등록
Vue에서 처리할 수 있는 이벤트 종류는 DOM 객체의 이벤트 처리와 동일
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vuejs 이벤트 처리</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
현재 잔고: <span>{{balance}}</span><br/>
<label>거래 금액</label>
<input type="number" v-model="amount">
<button v-on:click="balance += parseInt(amount)">입금</button><br/><br/>
<button @click="withdraw">출금1-콜백</button>
<button @click="withdraw()">출금2-직접호출</button>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
amount: 0,
balance: 1000
},
methods: {
withdraw() {
if (this.balance >= this.amount) {
this.balance -= this.amount;
} else {
alert("잔액 부족");
}
}
}
});
</script>
</body>
</html>
📋 실행 📋
Vue에서 이벤트 핸들러를 등록할 때 콜백 방식/직접 호출 방식 모두 가능
이벤트 핸들러 등록만 하는 형태는 시스템이 콜백하는 형태
실행하는 형태는 직접 함수를 호출하는 것이고. 시스템이 콜백하지X
이벤트 객체를 직접 활용할 수 없고, $event 이용해서 명시적으로 전달해야 함
📋 코드 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vuejs 이벤트 객체</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div @click="clicked" @mouseover="over()" @mouseout="out($event)">
Hello
</div>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
amount: 0,
balance: 1000
},
methods: {
clicked(e) {
console.log("clicked 콜백됨,", e);
},
over(e) {
console.log("over 콜백 안됨,", e);
},
out(e) {
console.log("over 콜백 안됨. 따라서 명시적으로 $event 지정,", e);
}
}
});
</script>
</body>
</html>
📋 실행 📋
📋 코드 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vuejs 이벤트 바인딩</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<style>
#canvas {
width: 100px;
height: 100px;
background-color: yellow;
}
</style>
</head>
<body>
<div id="app">
<select v-model="your_event">
<option value="mousemove">mousemove</option>
<option value="click">click</option>
</select>
>>> {{your_event}}
<div id="canvas" @[your_event]="actionPerform($event)"></div>
status:<input type="text" name="status" v-model="status"><br>
x:<input type="text" name="x" v-model="x"><br>
y:<input type="text" name="y" v-model="y">
</div>
<script>
var app = new Vue({
el: '#app',
data: {
your_event: 'mousemove',
status: '',
x: 0,
y: 0,
},
methods: {
actionPerform(e) {
this.status = e.type;
this.x = e.clientX;
this.y = e.clientY;
},
}
});
</script>
</body>
</html>
📋 실행 📋
이벤트 속성을 이용할 때 직접 이벤트 객체를 사용하기 보다 간단한 이벤트 수식어(Event Modifier) 이용해서 처리 가능
공통 이벤트 수식어
prevaentDefault()
대체stopPropagation()
대체키보드 이벤트 수식어
마우스 이벤트 수식어
left, right, middle : 각각 마우스의 어떤 버튼이 클릭 됐는지로 제한
📋 코드 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vuejs 기본 이벤트 처리 방지_이벤트 수식어 사용 전</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<h2>preventDefault</h2>
<form action="https://www.google.com/" @submit="login">
ID:<input type="text" placeholder="ID는 4글자 이상입니다." v-model="id" ref="myId">
<input type="submit">
</form>
<h2>stopPropagation</h2>
<div style="background-color: yellow;" @click="parent">
parent
<div style="background-color: green;" @click="child">
child
</div>
</div>
<h2>keyup.enter</h2>
num1:<input type="text" @keyup="knum"><br>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
id: ""
},
methods: {
login(e) {
if (this.id.length >= 4) {
e.target.submit();
} else {
e.preventDefault();
alert("ID를 4글자 이상으로 넣어주세요");
this.$refs.myId.focus();
}
},
parent(e) {
console.log("parent");
},
child(e) {
console.log("child");
e.stopPropagation();
},
knum(e) {
// console.log(e.keyCode); //enter는 13
if (e.keyCode == 13) {
console.log("knum");
}
}
}
});
</script>
</body>
</html>
📋 실행 📋
📋 코드 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vuejs 기본 이벤트 처리 방지_이벤트 수식어 사용 후</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<h2>preventDefault</h2>
<form action="https://www.google.com/" @submit.prevent="login">
ID:<input type="text" placeholder="ID는 4글자 이상입니다." v-model="id" ref="myId">
<input type="submit">
</form>
<h2>stopPropagation</h2>
<div style="background-color: yellow;" @click="parent">
parent
<div style="background-color: green;" @click.stop="child">
child
</div>
</div>
<h2>keyup.enter</h2>
num1:<input type="text" @keyup="knum"><br>
num2:<input type="text" @keyup.enter="knum"><br>
<button @click.once="one">한번만트리거됨</button>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
id: ""
},
methods: {
login(e) {
if (this.id.length >= 4) {
e.target.submit();
} else {
e.preventDefault();
alert("ID를 4글자 이상으로 넣어주세요");
this.$refs.myId.focus();
}
},
parent(e) {
console.log("parent");
},
child(e) {
console.log("child");
},
knum() {
console.log("knum");
},
one() {
console.log("one");
}
}
});
</script>
</body>
</html>
📋 실행 📋
<div id="app">
<form @submit.prevent="login">
<label for="id">아이디</label>
<input type="text" name="id" id="id" @keyup.prevent.enter="next" v-model.lazy="id"/>
<!-- ref 속성으로 DOM에 표시 -->
<input type="password" ref="pass" @keyup.enter="search"/>
<input type="button" value="제출"/>
</form>
</div>
<script>
let vi = new Vue({
el: "#app",
data: {
id: "",
},
methods: {
next() {
// ref 속성으로 접근 가능
let pass = this.$refs.pass;
console.log(pass);
pass.focus();
},
login() {
console.log("로그인 처리");
},
search() {
console.log("id: " + this.id);
}
}
});
</script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vuejs ref 참조</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
num:<input type="text" ref="xyz"><br>
<button @click="ok">OK</button>
</div>
<script>
var app = new Vue({
el: '#app',
methods: {
ok() {
console.log(this.$refs.xyz.value);
}
}
});
</script>
</body>
</html>
📋 실행 📋
component 개념
등록 방식에 따른 component 종류
Vue.component(tagName, options)
tagName
options
컴포넌트 사용시 주의할 점
template : 반드시 root element가 존재하고, 그 안에 다른 element가 나와야 함
<!-- root 존재하는 경우는 가능 -->
<template id="body-template">
<div>
<div></div>
</div>
<template>
<!-- root 없는 경우는 불가능-->
<template id="body-template">
<div></div>
<div></div>
</template>
data : 컴포넌트의 options에 정의하는 data는 반드시 함수로 작성하고, 함수 내부에서 리턴되는 객체**를 사용
/* data: {
cuttent: 0,
} */
// return 되는 함수로 data 정의
data: function() {
return {
current: 0,
};
}
📋 코드 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>전역 컴포넌트 사용 전</title>
<!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div>
<h1>검색기능</h1>
검색어:<input />
<hr>
<ul>
<li>야구</li>
<li>농구</li>
<li>축구</li>
</ul>
</div>
</div>
<script>
var app = new Vue({
el: '#app'
});
</script>
</body>
</html>
📋 실행 📋
📋 코드 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>전역 컴포넌트 사용 후</title>
<!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div>
<search-component></search-component>
<hr>
<list-component></list-component>
</div>
</div>
<template id="list-template">
<ul>
<li>야구</li>
<li>농구</li>
<li>축구</li>
</ul>
</template>
<script>
// 컴포너트의 태그명은 일반적으로 케밥표기법을 선호한다.
var search = Vue.component("search-component", {
//template은 반드시 root태그 필수
template: `
<div>
<h1>검색기능</h1>
검색어:<input />
</div>
`
});
var list = Vue.component("list-component", {
template: "#list-template"
});
var app = new Vue({
el: '#app'
});
</script>
</body>
</html>
📋 실행 📋
📋 코드 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>전역 컴포넌트 사용 후 Data 사용</title>
<!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div>
<search-component></search-component>
<hr>
<list-component></list-component>
</div>
</div>
<template id="list-template">
<ul>
<li v-for="value in hobby">{{value}}</li>
</ul>
</template>
<script>
// 컴포너트의 태그명은 일반적으로 케밥표기법을 선호한다.
var search = Vue.component("search-component", {
//template은 반드시 root태그 필수
template: `
<div>
<h1>검색기능</h1>
검색어:<input />
</div>
`
});
var list = Vue.component("list-component", {
template: "#list-template",
//data 사용 ==> 반드시 함수로 작성하고 리턴되는객체 사용
data: function () {
return {
hobby: ["야구", "농구", "축구","수영"]
}
}
});
var app = new Vue({
el: '#app'
});
</script>
</body>
</html>
📋 실행 📋
📋 코드 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>전역 컴포넌트 Data 공유문제</title>
<!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div>
<date1-component></date1-component>
<hr>
<date2-component></date2-component>
</div>
</div>
<template id="date-template">
<div>
<button @click="increment">+</button>
{{num}}
</div>
</template>
<script>
// 공유 데이터
var current = { num: 0 };
// 컴포너트의 태그명은 일반적으로 케밥표기법을 선호한다.
var date1 = Vue.component("date1-component", {
//template은 반드시 root태그 필수
template: "#date-template",
data: function () {
return current;
},
methods: {
increment() {
this.num = this.num + 1;
}
}
});
var date2 = Vue.component("date2-component", {
//template은 반드시 root태그 필수
template: "#date-template",
data: function () {
return current;
},
methods: {
increment() {
this.num = this.num + 1;
}
}
});
var app = new Vue({
el: '#app'
});
</script>
</body>
</html>
📋 실행 📋
📋 코드 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>전역 컴포넌트 Data 공유 문제 해결</title>
<!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div>
<date1-component></date1-component>
<hr>
<date2-component></date2-component>
</div>
</div>
<template id="date-template">
<div>
<button @click="increment">+</button>
{{num}}
</div>
</template>
<script>
// var current = { num: 0 };
// 컴포너트의 태그명은 일반적으로 케밥표기법을 선호한다.
var date1 = Vue.component("date1-component", {
//template은 반드시 root태그 필수
template: "#date-template",
data: function () {
return { num: 0 };
},
methods: {
increment() {
this.num = this.num + 1;
}
}
});
var date2 = Vue.component("date2-component", {
//template은 반드시 root태그 필수
template: "#date-template",
data: function () {
return { num: 0 };
},
methods: {
increment() {
this.num = this.num + 1;
}
}
});
var app = new Vue({
el: '#app'
});
</script>
</body>
</html>
📋 실행 📋
new Vue(
components: {
'component-name':'component 내용'
}
};
나머지 작성 방법은 전역 컴포넌트와 동일
📋 코드 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>지역 컴포넌트</title>
<!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
{{message}}
<local-component></local-component>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
message: '안녕하세요 Vue!'
},
components: {
'local-component': {
template: `<h1>지역컴포넌트{{num}}</h1>`,
data: function () {
return {
num: 200
}
}
}
}
});
</script>
</body>
</html>
📋 실행 📋
📋 코드 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>지역 컴포넌트와 전역 컴폰너트 비교</title>
<!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
{{message}}
<global-component></global-component>
<local-component></local-component>
</div>
<hr>
<div id="app2">
<global-component></global-component>
<!-- <local-component></local-component> -->
</div>
<script>
var global = Vue.component("global-component", {
template: `<h3>global component</h3>`
});
var app2 = new Vue({
el: '#app2'
});
var app = new Vue({
el: '#app',
data: {
message: '안녕하세요 Vue!'
},
components: {
'local-component': {
template: `<h3>지역컴포넌트{{num}}</h3>`,
data: function () {
return {
num: 200
}
}
}
}
});
</script>
</body>
</html>
📋 실행 📋
각각의 컴포넌트는 개별적으로 고유한 유효 범위를 가지기 때문에 다른 컴포넌트의 데이터를 직접 참조X
컴포넌트간의 자료 전달 방식은 관계에 따라 다른 방식 사용
부모/자식 (상하위) 컴포넌트의 관계
props
속성 이용이벤트
통해서 데이터 전달상하위 관계가 아닌 경우
이벤트 버스
이용📋 코드 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vuejs 기본 구조</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<style>
#t1 {
background-color: yellow;
}
#t2 {
background-color: blue;
}
#t3 {
background-color: green;
}
</style>
</head>
<body>
<div id="app">
<top1-component></top1-component>
</div>
<template id="top1">
<div id="t1">
<h1>top1</h1>
<top2-component></top2-component>
</div>
</template>
<template id="top2">
<div id="t2">
<h2>top2</h2>
<top3-component></top3-component>
</div>
</template>
<template id="top3">
<div id="t3">
<h3>top3</h3>
</div>
</template>
<script>
const t1 = Vue.component('top1-component', {
template: "#top1"
});
const t2 = Vue.component('top2-component', {
template: "#top2"
});
const t3 = Vue.component('top3-component', {
template: "#top3"
});
var app = new Vue({
el: '#app',
});
</script>
</body>
</html>
📋 실행 📋
상위 컴포넌트의 데이터를 하위 컴포넌트에서 사용할 때 - 하위 컴포넌트의 props 속성에 선언한 변수(속성명)에 상위 컴포넌트가 태그의 '속성명=값' 형태로 전달
📋 코드 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vuejs props</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<child-component xyz="hello" xyz2="hi"></child-component>
<child-component :xyz="message" xyz2="hi"></child-component>
</div>
<template id="child">
<div>
<h1>child</h1>
{{xyz}}<br>
{{xyz2}}<br>
</div>
</template>
<script>
//자식
const t1 = Vue.component('child-component', {
template: "#child",
props: ['xyz', 'xyz2']
});
//부모
var app = new Vue({
el: '#app',
data: {
message: "안녕하세요"
}
});
</script>
</body>
</html>
📋 실행 📋
📋 코드 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vuejs props 속성명</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 전달할 데이터 키는 캐밥 표기법으로 지정-->
<child-component xyz="hello" user-name="hi" user-age="20"></child-component>
<child-component :xyz="message" user-name="hi"></child-component>
</div>
<template id="child">
<div>
<h1>child</h1>
{{xyz}}<br>
{{userName}}<br>
{{userAge}}<br>
{{xxx()}}
</div>
</template>
<script>
//자식
const t1 = Vue.component('child-component', {
template: "#child",
props: ['xyz', 'user-name', 'userAge'] //받는 쪽에서는 카멜표기법 가능
,
methods: {
xxx() {
console.log(this.userAge, this.xyz, this.userName); // this.user-name은 안됨
}
}
});
//부모
var app = new Vue({
el: '#app',
data: {
message: "안녕하세요"
}
});
</script>
</body>
</html>
📋 실행 📋
📋 코드 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vuejs props 배열</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<top1-component :lang-data="language"></top1-component>
</div>
<template id="progrmming">
<div>
<h1>프로그램 언어</h1>
<ul v-for="(lang,index) in langData">
<li>{{lang}}</li>
</ul>
</div>
</template>
<script>
//자식
const t1 = Vue.component('top1-component', {
template: "#progrmming",
props: ['langData']
});
//부모
var app = new Vue({
el: '#app',
data: function () {
return {
language: ['자바', 'SQL', 'Vue.js']
}
}
});
</script>
</body>
</html>
📋 실행 📋
📋 코드 📋
<!DOCTYPE html>
<html>
<head>
<title>Vuejs 배열 활용_예방접종 샘플</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<h1>예방 접종 대상자</h1>
<h3>1차 대상자</h3>
<contact-component :contacts="list1"></contact-component>
<h3>2차 대상자</h3>
<contact-component :contacts="list2"></contact-component>
</div>
<template id="contactTemplate">
<table border="1">
<tr>
<th>번호</th>
<th>이름</th>
<th>전화번호</th>
<th>주소</th>
</tr>
<tr v-for="contact in contacts">
<td>{{contact.no}}</td>
<td>{{contact.name}}</td>
<td>{{contact.phone}}</td>
<td>{{contact.address}}</td>
</tr>
</table>
</template>
<script>
const t1 = Vue.component("contact-component", {
template: `#contactTemplate`,
props: ["contacts"],
});
var app = new Vue({
el: "#app",
data: {
list1: [
{ no: 10, name: "홍길동", phone: "010-1111-1111", address: "서울" },
{ no: 9, name: "이순신", phone: "010-4444-4444", address: "전라" },
{ no: 8, name: "강감찬", phone: "010-3333-3333", address: "경기" },
{ no: 7, name: "임꺽정", phone: "010-9999-9999", address: "전라" },
{ no: 6, name: "윤동주", phone: "010-8888-8888", address: "서울" },
],
list2: [
{ no: 5, name: "윤봉길", phone: "010-7777-7777", address: "제주" },
{ no: 4, name: "한용운", phone: "010-6666-6666", address: "부산" },
{ no: 3, name: "백범", phone: "010-5555-5555", address: "강원" },
{ no: 2, name: "안창호", phone: "010-2222-2222", address: "울산" },
{ no: 1, name: "이육사", phone: "010-0909-0909", address: "서울" },
],
},
});
</script>
</body>
</html>
📋 실행 📋
📋 코드 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vuejs props slot 1</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<style>
p {
color: red;
}
</style>
</head>
<body>
<div id="app">
<child-component :xyz="message">
<!-- 자식에게 전달할 html태그는 일반적으로 template 사용함.-->
<template>
<div>
<p>자식에게 전달할 html</p>
</div>
</template>
</child-component>
</div>
<template id="child">
<div>
<h1>child</h1>
<h2>부모에서 자식에게 문자열 전달: props</h2>
{{xyz}}
<h2>부모에서 자식에게 html 전달: slot</h2>
<slot></slot>
<slot></slot>
</div>
</template>
<script>
//자식
const t1 = Vue.component('child-component', {
template: "#child",
props: ['xyz']
});
//부모
var app = new Vue({
el: '#app',
data: function () {
return {
message: "안녕하세요"
}
}
});
</script>
</body>
</html>
📋 실행 📋
📋 코드 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vuejs props slot2</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<style>
p {
color: red;
}
</style>
</head>
<body>
<div id="app">
<child-component :xyz="message">
<template v-slot:header>
<div>
<p>자식에게 전달할 html,header</p>
</div>
</template>
<template v-slot:body>
<div>
<p>자식에게 전달할 html,body</p>
</div>
</template>
<template v-slot:footer>
<div>
<p>자식에게 전달할 html,footer</p>
</div>
</template>
</child-component>
</div>
<template id="child">
<div>
<h1>child</h1>
<h2>부모에서 자식에게 문자열 전달: props</h2>
{{xyz}}
<h2>부모에서 자식에게 html 전달: slot</h2>
<slot name="body"></slot>
<slot name="header"></slot>
<slot name="footer"></slot>
</div>
</template>
<script>
//자식
const t1 = Vue.component('child-component', {
template: "#child",
props: ['xyz']
});
//부모
var app = new Vue({
el: '#app',
data: function () {
return {
message: "안녕하세요"
}
}
});
</script>
</body>
</html>
📋 실행 📋
하위 컴포넌트의 데이터를 상위 컴포넌트로 전달하기 위해서 사용자 정의 이벤트를 발생시켜서 데이터 전달
하위 컴포넌트가 이벤트 발생시키면 이벤트를 통해서 사위 컴포넌트의 함수를 동작시키는 형태
이벤트를 발생시킬 때에는 Vue 객체의 $emit 함수 사용
📋 코드 📋
<!DOCTYPE html>
<html>
<head>
<title>Vuejs emit 1</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!-- <button @click="receive">parent</button> -->
<hello-component v-on:xyz="receive"></hello-component>
</div>
<template id="helloTemplate">
<div>
<button @click="send">child</button>
</div>
</template>
<script>
Vue.component('hello-component', {
template: `#helloTemplate`,
methods: {
send: function (e) {
//부모에게 xyz 이벤트 발신
this.$emit('xyz');
}
}
});
var app = new Vue({
el: '#app',
methods: {
receive: function () {
console.log("parent.receive");
}
}
})
</script>
</body>
</html>
📋 실행 📋
📋 코드 📋
<!DOCTYPE html>
<html>
<head>
<title>Vuejs emit 2</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!-- <button @click="receive">parent</button> -->
<hello-component v-on:xyz="receive"></hello-component>
</div>
<template id="helloTemplate">
<div>
<button @click="send">child</button>
</div>
</template>
<script>
Vue.component('hello-component', {
template: `#helloTemplate`,
methods: {
send: function (e) {
//부모에게 xyz 이벤트 발신
this.$emit('xyz', '홍길동', 20);
}
}
});
var app = new Vue({
el: '#app',
methods: {
receive: function (name, age) {
console.log("parent.receive", name, age);
}
}
})
</script>
</body>
</html>
📋 실행 📋
상/하위 레벨이 아닌 컴포넌트 간은 직접적인 정보 전달이 불가능
let eventBus = new Vue();
이벤트 버스는 단순한 Vue 객체
이벤트 버스는 데이터를 보내려는 쪽과 데이터를 받는 쪽 모두에서 사용
보내는 쪽에서 이벤트를 발신(emit)하고, 받는 쪽에서는 v-on 이용하여 이벤트 수신
📋 코드 📋
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vuejs event bus</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<comp-1></comp-1>
<comp-2></comp-2>
</div>
<script>
//이벤트 버스 생성
let eventBus = new Vue();
// < !--입력 컴포넌트-- >
Vue.component('comp-1', {
template: `<input type="text" @change="trans">`,
methods: {
trans(e) {
eventBus.$emit("gogo", e.target.value);
}
}
});
// < !--출력 컴포넌트-- >
Vue.component('comp-2', {
template: `<span>{{msg}}</span>`,
data: function () {
return {
msg: ""
}
},
created() {
eventBus.$on("gogo", this.update);
},
methods: {
update(data) {
this.msg = data;
}
}
});
var app = new Vue({
el: '#app'
});
</script>
</body>
</html>
📋 실행 📋
📋 코드 📋
<!DOCTYPE html>
<html>
<head>
<title>Vuejs event bus_Todo 샘플</title>
<script src="https://unpkg.com/vue"></script>
<!-- 이벤트 버스 객체 생성-->
<script>
var eventBus = new Vue();
</script>
<!-- input 컴포넌트 생성-->
<template id="inputTemplate">
<div>
<input type="text" @keyup.enter="add" v-model="mesg">
</div>
</template>
<script>
Vue.component('input-component', {
template: `#inputTemplate`,
data: function () {
return { mesg: '' }
},
methods: {
add: function () {
eventBus.$emit('xyz', this.mesg);
}
}
});
</script>
<!-- child2 컴포넌트 생성-->
<template id="listTemplate">
<div>
<ul v-for="(a,idx) in toDoList">
<li>{{a}}<button @click="del(idx)">삭제</button> </li>
</ul>
</div>
</template>
<script>
Vue.component('list-component', {
template: `#listTemplate`,
data: function () {
return { toDoList: [] }
},
created: function () {
eventBus.$on('xyz', this.add)
},
methods: {
add: function (m) {
this.toDoList.push(m);
},
del: function (idx) {
console.log(idx);
this.toDoList.splice(idx, 1);
}
}
});
</script>
</head>
<body>
<div id="app">
<input-component></input-component>
<list-component></list-component>
</div>
<script>
var app = new Vue({
el: '#app'
})
</script>
</body>
</html>
// Vue Router 생성
const router = new VueRouter({
// 라우팅 경로 정의 : {name: "path_alias", path: "요청 URL", component: "표시할 컴포넌트"}
routes: [{ path: "/", component: null},
{path: "/sub1", component: sub1},
{path: "/sub2", component: sub2}]
});
// Vue 객체에 Router 설정
new Vue({
el: "#app",
router: router
})
<router-link to="/user/hong">hong</router-link>
<router-link to="/user/jang">jang</router-link>
const vr = new VueRouter({
routes: [{
path: "user/:id",
component: user
}]
})
const user = Vue.component("comp-user", {
template: "<div>여기는 서브user: {{$route.params.id}}</span></div>"
})
push()
함수 제공const router = new VueRouter({
routes: [{
// 상위 컴포넌트에 대한 route 정보 포함
path: "/user/:id",
component: userComp,
// 자식 컴포넌트에 대한 route 정보 포함
children: [
{path: "profile", component: profileComp}, // 자식의 Path에는 '/' 사용X
{path: "posts", component: postComp}]
}]
});
<div id="app">
<p>
<router-link to="/user/hong">사용자 홈<router-link/>
<!-- 상위 컴포넌트의 경로를 포함함 -->
<router-link to="/user/hong/prifile">사용자 프로필</router-link>
<router-link to="/user/hong/posts">사용자 포스트</router-link>
</p>
<!-- component들이 보일 자리 -->
<router-view></router-view>
</div>
// 하위 component 정의
let profileComp = Vue.component('profile-comp', {
template: `<div>사용자의 프로필입니다.<\div>`
});
let postComp = Vue.component('post-comp', {
template: `<div>사용자의 작성글입니다.<\div>`
});
let userComp = = Vue.component('user-comp', {
template: `<div>사용자의{{$route.params.id}} <router-view></router-view><\div>`
});
<div id="app">
<router-view name="header"></router-view>
<!-- 이름이 없는 router-view: default -->
<router-view></router-view>
<router-view name="footer"></router-view>
</div>
const vr = new VueRouter({
routes: [{
// 경로 하나에 여러 개의 컴포넌트
path: "/",
components: {
header: headerComp,
default: bodyComp,
footer: footerComp,
}
}]
});
const headerComp = {
template: "<p>이것은 header</p>"
};
const bodyComp = {
template: "<p>이것은 body</p>"
};
const footerComp = {
template: "<p>이것은 footer</p>"
};
<div id="app">
<h1>navigation guard test</h1>
<p>
<router-link to="/login">login</router-link>|
<router-link to="/important">중요한 페이지 보러 가기</router-link>|
<router-link to="/important?id=hong">중요한 홍 페이지 보러가기</router-link>|
<router-link to="/normal">그냥 일반</router-link>|
</p>
<hr>
<router-view></router-view>
</div>
const router = new VueRouter({
routes: [
{path: "/login", component: LoginComp},
{path: "/important", component: ImportantComp},
{path: "/normal", component: NormalComp}
]
});
const needLogin = ["/important"];
router.beforeEach((to, from, next) => {
console.log(`경로 로깅: from : ${from.path} ==> to: ${to.path}`)
if (needLogin.includes(to.path) && to.query.id !== "hong") {
next("/login"); // 현재의 이동이 중단되고 지정된 페이지로 리다이렉션
} else {
next(); // 그냥 다음 route 호출
}
});
router.afterEach((to, from) => {
console.log(`router 작업 완료 : from : ${from.path} ==> to: ${to.path}`)
});
const router = new VueRouter({
routes: [
{path: "/login", component: LoginComp},
{path: "/important", component: ImportantComp},
{path: "/normal", component: NormalComp,
beforeEnter(to, from, next) {
console.log(`route별 guard: from : ${from.path} ==> to: ${to.path}`)
next();
}
}
]
});
.vue
확장자 파일을 이용npm install -g @vue/cli
vue create 프로젝트명
npm run serve
// http://localhost:8080/ 요청
import Vue from "Vue"; // 핵심 객체 Vue import
import App from "./App.vue"; // 개발하려는 SFC 첫 화면인 App.vue를 import
Vue.config.productionTip = true; // Vue 앱이 처음 실행될 때 나오는 경고문을 출력한 것인지 물어봄 (상용인 경우 false로 지정)
new Vue({ // id가 app인 html 태그에 App.vue 내용을 표시하는 문장
render: (h) => h(App),
}).$mount("#app");
let axios = axios({
url: "./food.json", // 호출할 서버의 경로
method: "get", // 사용하는 http method (post/get/put/delete), default는 get
params: {
name: "hong"
}, // url (쿼리스트링을 구성하는 파라미터 요소)
data: {
age: 10,
addr: "seoul"
}, // request body를 통해서 서버로 전송되는 값 (post, put, patch에서 사용)
});
axios.then(
success_callback
).catch(
error_callback
).finally(
finally_callback
);
{
// 서버가 출력한 값은 언제나 data 속성 안에 존재함
data: {},
// HTTP status code
status: 200,
// HTTP status message from the server response
statusText: 'OK',
// 'headers' the headers that the server responsed with All header names are lower cased
headers: {},
// 'config' is the config that was provided to 'axios' for the request
config: {}
}
npm install vuex --save
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
vue create vuex_counter
npm install vuex --save
mutatios: {
methods(state, payload) {
// payload에 전달된 값을 이용해서 state 수정함
}
}
import Vue from "vue";
import App from "./App.vue";
Vue.config.productionsTip = false;
import store from "./js/myVueXStore";
new Vue({
// store 속성에 Vuex.store 등록함
// Component에서 store가 필요하면 this.$store
store,
render: (h) => h(App),
}).$mount("#App");
...mapMutations({
increment: "increment", // 사용할 함수 이름 : mutation 함수 이름
decrement: "decrement",
setval: "serVal",
})
...mapState({ storecounter: "counter", asyncounter: "asnccounter" ]),
const state = new Vuex.Store({
state: {. . .},
mutations: {
mutation_method(state, payload) {
//
},
},
actions : {
action_method(state, payload) {
// store를 통해 state mutation은 물론 다른 action 사용 가능
}
}
})
import {mapState} from "vuex";
import Constant from "../js/Constant";
export default {
data() {
return { date: "" };
},
computed: {
...mapState(["movielist"]) // 저장소의 이름과 동일하게 자동 연결
},
methods: {
[Constant.BoxOFFICE](payload) {
this.$store.dispatch(Constant.BOXOFFICE, payload); // 호출
}
}
};
export default {
computed: {
// ...mapState(["movielist"]) // 저장소의 이름과 동일하게 자동 연결
movielist() {
return this.$store.getters.under;
}
}
}