- VSCode VScode 설치
- node.js 노드
- vue.js 확장 프로그램 vue.js 확장 프로그램
- 깃허브에서 다운로드 zip 후 폴더 복사
vuetr, material icon, night owl, live server, ESLint, Prettier, Auto Close Tag, Atom Keymap 설치
live Server setting에서 chorme를 설정 후 host 내 ip주소를 넣어준다
- View -> 브라우저에서 사용자가 보는 요소(HTML)
- DOM Listeners -> 이벤트를 뷰에서 창취, 그리고 이벤트를 잡아서 자바스크립트에서 실행
- Data Bindings -> 데이터가 바뀔때 반영하게 도와줌
! + tab -> html/head/body 자동생성
html은 화면 그대로 보이는 것
Javascript는 값을 변화시키는 것
-> 처음 선언해준 값을 갱신시킬 때 그대로 반영되지 않고 바뀐 값을 다시 화면에 넣어줘야 갱신된 값을 출력할 수 있음
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>Document</title>
</head>
<body>
<div id="app"></div>
<script>
//console.log(div);
var div = document.querySelector('#app');
var str = 'hello world';
div.innerHTML = str;
str = 'hello world!!!';
div.innerHTML = str; // 갱신된 값을 다시 넣어줘야 화면에 출력
</script>
</body>
</html>
공식문서 설명
객체를 동작을 재정의하는 API
<!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>Document</title>
</head>
<body>
<div id="app"></div>
<script>
var div = document.querySelector('#app');
var viewModel = {};
// Object.defineProperty(대상 객체, 객체의 속성, {
// // 정의할 내용
// })
Object.defineProperty(viewModel, 'str', {
// 속성에 접근했을 때의 동작을 정의
get: function() {
console.log('접근');
},
// 속성에 값을 할당했을 때의 동작을 정의
set: function(newValue) {
console.log('할당', newValue);
div.innerHTML = newValue;
}
});
</script>
</body>
</html>
공식문서
즉시 실행 함수란?
-> 정의하자마자 실행되는 함수(function () { statements })();
<!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>Document</title>
</head>
<body>
<div id="app"></div>
<script>
var div = document.querySelector('#app');
var viewModel = {};
// Object.defineProperty(대상 객체, 객체의 속성, {
// // 정의할 내용
// })
(function() {
function init() {
Object.defineProperty(viewModel, 'str', {
// 속성에 접근했을 때의 동작을 정의
get: function () {
console.log('접근');
},
// 속성에 값을 할당했을 때의 동작을 정의
set: function (newValue) {
console.log('할당', newValue);
div.innerHTML = newValue;
render(newValue);
}
});
}
function render(value) {
div.innerHTML = value;
}
init();
})();
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Getting Started</title>
</head>
<body>
<div id="app">
{{ message }}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js'
}
})
</script>
</body>
</html>
컴포넌트안에서 편집도 가능하고 바로 페이지에서 반영도 가능!
vue를 선언해줘야함
그리고 가장 중요한건 특정 태그를 el:로 지정해줘야함❗
<!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>Document</title>
</head>
<body>
<div id="app">
<!-- ... -->
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#app', // 무조건 el 지정(특정 태그에 지정해야함)
data: {
message: 'hi'
}
});
</script>
</body>
</html>
fucntion 다음 대문자로 선언하면 생성자를 선언하겠다는 뜻
기본적인 생성자 함수 예시
인스턴스에서 사용할 수 있는 속성 / API
key / value 형태로 들어옴
new Vue({ el: , template: , data: , methods: , created: , watch: , });
원래는 var options = {} 객체안에 담아서 var vm = new Vue(options) 담지만 가독성을 위해 위에서 생성자를 생성하는 동시에 속성 및 api를 선언
<!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>Document</title> </head> <body> <div id="app"> <!-- ... --> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> // var options = var vm = new Vue({ el: '#app', // 무조건 el 지정(특정 태그에 지정해야함) data: { message: 'hi' }, methods: { }, created: function() { } }); </script> </body> </html>
코드의 재사용성 높임
인스턴스를 생성하면 root 컴포넌트가 됨
Vue.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>Document</title>
</head>
<body>
<div id="app">
<app-header></app-header>
<app-content></app-content>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
// Vue.component('컴포넌트 이름', 컴포넌트 내용);
// 전역 컴포넌트
Vue.component('app-header', {
template: '<h1>Header</h1>'
});
Vue.component('app-content', {
template: '<div>content</div>'
});
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>Document</title>
</head>
<body>
<div id="app">
<app-header></app-header>
<app-content></app-content>
<app-footer></app-footer>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
// Vue.component('컴포넌트 이름', 컴포넌트 내용);
// 전역 컴포넌트
Vue.component('app-header', {
template: '<h1>Header</h1>'
});
Vue.component('app-content', {
template: '<div>content</div>'
});
new Vue({
el: '#app', // 인스턴스를 생성해서 태그에 붙이겠다.
// 지역 컴포넌트
components: {
// '키' : '값'
// '컴포넌트 이름' : '컴포넌트 내용'
'app-footer' : {
template: '<footer>footer</footer>'
}
}
});
</script>
</body>
</html>
보통 여러개를 정의할 때는 -s까지 붙여야한다.
ex) components
- 지역 컴포넌트
-- 특정 컴포넌트 하단의 어떤 것이 등록되었는지 컴포넌트 속성에서 알 수 있다.
일반적으로 서비스를 구현할 때는 컴포넌트를 사용하여 계속 아래로 그린다.- 전역 컴포넌트
-- 대부분 플러그인이나 라이브러리처럼 전역으로 사용하는 경우메만 사용
인스턴스를 생성할 때마다 컴포넌트를 생성해줘야하는 것이 지역 컴포넌트
전역 컴포넌트를 선언하면 그럴 필요 없지만 보통은 지역 컴포넌트를 쓴다.
<!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>Document</title>
</head>
<body>
<div id="app">
<app-header></app-header>
<!-- <app-content></app-content> -->
<app-footer></app-footer>
</div>
<div id="app2">
<app-header></app-header>
<!-- <app-content></app-content> -->
<app-footer></app-footer>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
// Vue.component('컴포넌트 이름', 컴포넌트 내용);
// 전역 컴포넌트
Vue.component('app-header', {
template: '<h1>Header</h1>'
});
// Vue.component('app-content', {
// template: '<div>content</div>'
// });
new Vue({
el: '#app', // 인스턴스를 생성해서 태그에 붙이겠다.
// 지역 컴포넌트
components: {
// '키' : '값'
// '컴포넌트 이름' : '컴포넌트 내용'
'app-footer' : {
template: '<footer>footer</footer>'
}
}
});
new Vue({
el: '#app2',
components: {
'app-footer': {
template: '<footer>footer</footer>'
}
}
});
</script>
</body>
</html>
위에서 아래로는 데이터 전달 / 아래서 위로는 이벤트 발생
🤔만약? 컴포넌트가 제대로 선언이 안되어 있는 경우를 생각해보자
그렇다고 한다며 어디서 이벤트가 발생하고 데이터가 전달되는지 파악하기 어렵다.
❗❗ 하지만 초기에 설정은 복잡할 수 있지만 선언을 제대로 해준다면?
이런식으로 어디서 데이터(Props)가 움직이고 event가 어디서 발생하는 지
데이터의 흐름을 추적할 수 있다.
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>Document</title>
</head>
<body>
<div id="app">
<!-- <app-header v-bind:프롭스 속성 이름="상위 컴포넌트의 데이터 이름"></app-header> -->
<app-header v-bind:propsdata="message"></app-header>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var appHeader = {
template: '<h1>header</h1>',
props: ['propsdata']
}
new Vue({
el: '#app',
components: {
'app-header' : appHeader
},
data: {
message: 'hi'
}
})
</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>Document</title>
</head>
<body>
<div id="app">
<!-- <app-header v-bind:프롭스 속성 이름="상위 컴포넌트의 데이터 이름"></app-header> -->
<app-header v-bind:propsdata="message"></app-header>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var appHeader = {
template: '<h1>{{propsdata}}</h1>',
props: ['propsdata']
}
new Vue({
el: '#app',
components: {
'app-header' : appHeader
},
data: {
message: 'hi'
}
})
</script>
</body>
</html>
reactivity -> 상위 값이 바뀌면 하위 값도 같이 바뀐다.
<!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>Document</title>
</head>
<body>
<div id="app">
<!-- <app-header v-bind:프롭스 속성 이름="상위 컴포넌트의 데이터 이름"></app-header> -->
<app-header v-bind:propsdata="message"></app-header>
<app-content v-bind:propsdata="num"></app-content>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var appHeader = {
template: '<h1>{{propsdata}}</h1>',
props: ['propsdata']
}
var appContent = {
template: '<div>{{propsdata}}</div>',
props: ['propsdata']
}
new Vue({
el: '#app',
components: {
'app-header' : appHeader,
'app-content' : appContent
},
data: {
message: 'hi',
num : 10
}
})
</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>Document</title>
</head>
<body>
<div id="app">
<app-header></app-header>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var appHeader = {
template: '<button v-on:click="passEvent">click me</button>',
methods: {
passEvent: function() {
this.$emit('pass')
}
}
}
new Vue({
el: '#app',
components: {
'app-header': appHeader
}
});
</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>Document</title>
</head>
<body>
<div id="app">
<!-- <app-header v-on:하위 컴포넌트에서 발생한 이벤트 이름="상위 컴포넌트 메서드 이름"></app-header> -->
<app-header v-on:pass="logText"></app-header>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var appHeader = {
template: '<button v-on:click="passEvent">click me</button>',
methods: {
passEvent: function() {
this.$emit('pass')
}
}
}
new Vue({
el: '#app',
components: {
'app-header': appHeader
},
methods: {
logText: function() {
console.log('hi');
}
}
});
</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>Document</title>
</head>
<body>
<div id="app">
<p>{{ num }}</p>
<!-- <app-header v-on:하위 컴포넌트에서 발생한 이벤트 이름="상위 컴포넌트 메서드 이름"></app-header> -->
<app-header v-on:pass="logText"></app-header>
<app-content v-on:increase="increaseNumber"></app-content>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var appHeader = {
template: '<button v-on:click="passEvent">click me</button>',
methods: {
passEvent: function() {
this.$emit('pass')
}
}
}
var appContent = {
template: '<button v-on:click="addNumber">add</button>',
methods: {
addNumber: function() {
this.$emit('increase')
}
},
}
new Vue({
el: '#app',
components: {
'app-header': appHeader,
'app-content': appContent
},
methods: {
logText: function() {
console.log('hi');
},
// 메서드 정의
increaseNumber: function() {
this.num = this.num + 1;
}
},
data: {
num: 10
}
});
</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>Document</title>
</head>
<body>
<div id="app">
<p>{{ num }}</p>
<!-- <app-header v-on:하위 컴포넌트에서 발생한 이벤트 이름="상위 컴포넌트 메서드 이름"></app-header> -->
<app-header v-on:pass="logText"></app-header>
<app-content v-on:increase="increaseNumber"></app-content>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var appHeader = {
template: '<button v-on:click="passEvent">click me</button>',
methods: {
passEvent: function () {
this.$emit('pass')
}
}
}
var appContent = {
template: '<button v-on:click="addNumber">add</button>',
methods: {
addNumber: function() {
this.$emit('increase')
}
}
}
var vm = new Vue({
el: '#app',
components: {
'app-header': appHeader,
'app-content': appContent
},
methods: {
logText: function () {
console.log('hi');
},
increaseNumber: function() {
this.num = this.num + 1;
}
},
data: {
num: 10
}
});
</script>
</body>
</html>
여기서 new Vue를 var vm이라는 변수로 선언하고 console.log에 찍었을 때 결과 값을 살펴 보자
👉 console.log(vm) 했을 때 객체 Vue가 불러와지고 안에 num 값이 들어있다. 따라서 this.num은 Vue 객체의 num이라는 것이다.
root -> 인스턴스
같은 레벨의 컴포넌트인 appcontent, appHeader
🤔AppContent 에서 AppHeader를 어떻게 전달할까?
AppContent에서 AppHeader로 갈 수 있는 길은 막혀 있다.
따라서 AppContent에서 event로 올려주고 root에서 AppHeader로 데이터를 전달하는 방식을 사용해야한다.
<!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>Document</title>
</head>
<body>
<div id="app">
<app-header></app-header>
<app-content></app-content>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var appHeader = {
template: '<div>header</div>'
}
var appContent = {
template: '<div>content<button v-on:click="passNum">pass</button></div>',
methods: {
passNum: function() {
this.$emit('pass', 10);
}
}
}
new Vue({
el: '#app',
components: {
'app-header': appHeader,
'app-content': appContent
}
});
</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>Document</title>
</head>
<body>
<div id="app">
<app-header></app-header>
<app-content></app-content>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var appHeader = {
template: '<div>header</div>'
}
var appContent = {
template: '<div>content<button v-on:click="passNum">pass</button></div>',
methods: {
passNum: function() {
this.$emit('pass', 10);
}
}
}
new Vue({
el: '#app',
components: {
'app-header': appHeader,
'app-content': appContent
},
data: {
num: 0
}
});
</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>Document</title>
</head>
<body>
<div id="app">
<p>{{ num }}</p>
<!-- <app-header v-bind:프롭스 속성 이름="상위 컴포넌트의 이름"></app-header> -->
<app-header v-bind:propsdata="num"></app-header>
<!-- app-content v-on:pass="deliverNum(value)"></app-content> -->
<app-content v-on:pass="deliverNum"></app-content>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var appHeader = {
template: '<div>header</div>',
props: ['propsdata']
}
var appContent = {
template: '<div>content<button v-on:click="passNum">pass</button></div>',
methods: {
passNum: function() {
this.$emit('pass', 10);
}
}
}
new Vue({
el: '#app',
components: {
'app-header': appHeader,
'app-content': appContent
},
data: {
num: 0
},
methods: {
deliverNum: function(value) {
this.num = value;
}
}
});
</script>
</body>
</html>
- AppContent에서 인자 10을 담은 이벤트 발생
- deliverNum(value)를 따로 써주지 않아도 value값을 가져감
- value값을 this.num(data의 num)에 담음
- 변화된 data값을 가지고 props로 데이터를 AppHeader에 전달
뷰 라우터란?
뷰 라이브러리를 이용하여 페이지 이동은 하지 않고 싱글 페이지 애플리케이션을 구현할 때 사용하는 라이브러리
👇 아래 코드를 넣어줌 - 꼭 vue.js 다음 라우터 script를 넣어줘야함
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router@3.5.3/dist/vue-router.js"></script>
router : router 에서 오른쪽이 내가 선언해준 var router
공식문서에서 변수를 저런 식으로 선언함
<!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>Document</title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router@3.5.3/dist/vue-router.js"></script>
<script>
var router = new VueRouter({
});
new Vue({
el: '#app',
router: router
})
</script>
</body>
</html>