Vue JS
2022. 4. 8. 11:35ㆍStudy/JavaScript
Vue JS
Vue(/vjuː/ 로 발음, view 와 발음이 같습니다.)는 사용자 인터페이스를 만들기 위한 진보적인 프레임워크 입니다.
다른 단일형 프레임워크와 달리 Vue는 점진적으로 채택할 수 있도록 설계하였습니다.
핵심 라이브러리는 뷰 레이어만 초점을 맞추어 다른 라이브러리나 기존 프로젝트와의 통합이 매우 쉽습니다.
그리고 Vue는 현대적 도구 및 지원하는 라이브러리와 함께 사용한다면 정교한 단일 페이지 응용프로그램(SPA)을 완벽하게 지원할 수 있습니다.
Vue JS 공식사이트
공식 사이트에서 가이드문서를 볼 수 있다.
https://kr.vuejs.org/v2/guide/
설치방법
1. Vue.js 라이브러리를 연결해서 사용하는 방법 (CDN)
https://kr.vuejs.org/v2/guide/installation.html#CDN
최신버전을 사용하면 문제가 발생할 수 있기 때문에 안정화된 버전을 사용하자
<!-- 개발버전, 도움되는 콘솔 경고를 포함. -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- 상용버전, 속도와 용량이 최적화됨. -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<!-- 버전:권장 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.0"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<!-- 기본 ES 모듈을 사용하는 경우 이를 지원 하는 ES 모듈 호환 빌드 파일도 있습니다. -->
<script type="module">
import Vue from 'https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.esm.browser.js'
</script>
2. NPM (node.js 설치)
Vue로 대규모 응용 프로그램을 빌드할 때 NPM을 권장합니다.
Webpack 또는 Browserify와 같은 모듈 번들러와 잘 작동합니다.
Vue는 싱글 파일 컴포넌트를 만들기 위한 도구도 제공합니다.
# 최신 안정화 버전
$ npm install vue
3. CLI
Vue.js는 단일 페이지 애플리케이션를 빠르게 구축할 수 있는 공식 CLI를 제공합니다. 최신 프론트엔드 워크 플로우를 위해 사전 구성된 빌드 설정을 제공합니다. 핫 리로드, 저장시 린트 체크 및 프로덕션 준비가 된 빌드로 시작하고 실행하는데 몇 분 밖에 걸리지 않습니다. 상세한 내용은 Vue CLI 문서에서 찾아보실 수 있습니다.
우선 CDN방식으로 맛보기
1. 사용방법
1-1. Vue 인스턴스
Vue 인스턴스 만들기(모든 Vue 앱은 Vue 함수로 새 Vue 인스턴스를 만드는 것부터 시작합니다.)
Vue 문법을 사용할 영역(?) 지정
<script>
var vm = new Vue({
// 옵션
})
</script>
ex1-1) 초기화 코드
div의 id 또는 class 명과 function 내 el 객체 값을 맞춰주면 된다.
- data객체 : 변수, 배열, 객체, 객체배열 등을 모아놓는 영역
<div id="app">
<h1>Hello {{ str + ' ' + str1 }} World!</h1>
</div>
<script>
var app = new Vue({
el: '#app', // 해당 태그의 id, class
data: { // 변수, 배열, 객체, 객체배열 등을 모아놓는 영역
str: 'Vue.js',
str1: '프론트엔드'
}
});
</script>
ex1-2) 객체를 사용하여 코드분리
el | Vue 인스턴스와 연결하여 DOM요소를 지정하는 옵션 속성(사용범위) |
data | Vue 인스턴스 내부에서 마치 변수, 객체, 배열, 객체배열 처럼 사용할 수 있는 data 값들을 설정하는 옵션 속성 => 자료들을 담아놓는 공간 |
DOM 요소와 Vue Instancs가 연결되면
- 템플릿 문법을 사용가능
- 손쉽게 이벤트 등록 및 제어 가능
- 디렉티브(directive)를 사용 가능
- 컴포넌트를 사용 가능
<div id="app1-2">
<h1>Hello {{ str + ' ' + str1 }} World!</h1>
</div>
<script>
var datas = { // datas 객체
str: 'Vue.js',
str1: '프론트엔드 과정'
};
var vueConfigOptions = { // vueConfigOptions 객체
el: '#app1-2',
data: datas
};
var app = new Vue(vueConfigOptions);
</script>
ex1-3) Vue Instancs 영역
el : 옵션 속성을 통해 지정한 DOM요소 안쪽만 해당된다.
el을 #header로 바꿔도 에러가 나진 않지만, visual~~footer는 배경색이 적용되지 않는다.
<div id="app1-3">
<div id="header">{{ header }}</div>
<div id="visual">{{ visual }}</div>
<div id="content">{{ content }}</div>
<div id="footer">{{ footer }}</div>
</div>
<script>
var vueConfigOptions ={
el: '#app1-3',
data: {
header: '여기는 header 영역',
visual: '여기는 visual 영역',
content: '여기는 content 영역',
footer: '여기는 footer 영역'
}
};
var app=new Vue(vueConfigOptions);
app.$el.style.backgroundColor = 'yellow';
</script>
2. 템플릿 문법
Vue.js는 렌더링 된 DOM을 기본 Vue 인스턴스의 데이터에 선언적으로 바인딩 할 수있는 HTML 기반 템플릿 구문을 사용합니다.
모든 Vue.js 템플릿은 스펙을 호환하는 브라우저 및 HTML 파서로 구문 분석 할 수있는 유효한 HTML입니다.
*보간법(Interpolation) - 두겹의 중괄호 {{ }} (Mustache 머스태시) 사이에 js문법 사용
ex2-1) Interpolation의 유효 범위
Interpolation은 태그에 영향을 미치지 않는 부분에 사용할 수 있다.
태그 안에서는 사용할 수 없다.
data 값을 태그 속성으로 사용할 때에는 (class, id, src ···)
:속성 = "data변수"
<h1 :class="cla">Class Name</h1>
<div id="app2-1">
<h1>Hello {{ str }} World!</h1>
<!-- 태그 안에서 class 사용하기 -->
<h1 :class="cla">Class name</h1>
<img :src="imgsrc" alt="">
<!-- <h1 {{ str }}>Hello {{ str }} World!</h1> 에러! -->
<h1 class="{{ str }}">Hello World!</h1>
</div>
<script>
var app = new Vue({
el: '#app2-1',
data: {
str: 'Vue_js',
cla: 'head1',
imgsrc: 'abc.jpg'
}
});
</script>
ex2-2) Interpolation에서 가능한 문법
{{ }} 안에서 javascript 사용 가능
if문은 사용 금지 => 3항 연산자 사용 or 메소드를 구현
<div id="app2-2">
<h1>{{ (number+100)*2 }}</h1>
<h1>{{ new Date() }}</h1>
<h1>{{ (Math.floor(Math.random()*10)%2 == 1) ? '홀수':'짝수' }}</h1>
</div>
<script>
var app = new Vue({
el: '#app2-2',
data: {
number: 100
}
});
</script>
ex2-3) 문자열에 태그를 사용하고 싶을때 v-html
문자열의 태그도 그대로 문자열로 출력된다.
<div id="app2-3">
<h1>{{ str }}</h1>
</div>
<script>
var app = new Vue({
el: '#app2-3',
data: {
str: '문자를 <strong>굵게</strong> 또는 <em>기울이고</em> 싶다 간절히!!!'
}
});
</script>
ex2-4) v-html 디렉티브(v- 접두사가 있는 특수 속성)
v-html을 사용하면 해당 태그 안쪽에 data 값이 그대로 삽입되게 된다. (태그 포함)
<div id="app2-4">
<h1 v-html="str"></h1>
</div>
<script>
var app = new Vue({
el: '#app2-4',
data: {
str: '<p>문자를 <strong style="color:red">굵게</strong> 또는 <em>기울이고</em> 싶다 간절히!!!</p>'
}
});
</script>
3. 데이터와 메소드
ex3-1) 메소드
methods: 옵션 속성 - 메소드(function)를 등록할 수 있는 옵션 속성
<div id="app3-1">
<h1>{{ eat(name,food) }}</h1>
</div>
<script>
var app = new Vue({
el: '#app3-1',
data: {
name:'홍길동',
food:'짬뽕'
},
methods: {
eat: function(n,f){
return n + '이 ' + f + '을 먹고 있습니다';
// return this.name + '이 ' + this.food + '을 먹고 있습니다';
}
}
});
</script>
ex3-2) 데이터와 메소드의 바인딩
<div id="app3-2">
<h1>
반지름이 {{ radius }}cm인 원의 둘레의 길이는 {{ circumference(radius) }}cm이고, 원의 넓이는 {{ circleArea(radius) }}cm <sup>2</sup>입니다
</h1>
</div>
<script>
var dataOptionsObject = { radius:10 };
var methodsOptionsObject = {
circumference: function(r){
return Math.round(2*Math.PI*r*100)/100;
},
circleArea: function(r){
return Math.round(Math.PI*r*r*100)/100;
}
};
var vueConfigOptions = {
el: '#app3-2',
data: dataOptionsObject,
methods: methodsOptionsObject
};
var app = new Vue( vueConfigOptions );
</script>
ex3-3)
※ 비동기 처리를 원할때에는 Vue methods 를 활용하자
<div id="app3-3">
<h1>날짜/시간="{{ dataProperty }}"</h1>
<button onclick="changeData();">change</button>
</div>
<script>
var app = new Vue({
el: '#app3-3',
data: { dataProperty: "dummy"}
});
function changeData(){ // 일반함수
var now = new Date();
app.dataProperty = now.toLocaleString();
};
</script>
ex3-4)
위의 예제에서 초기화 된 속성값을 변경하면 오류가 발생한다 (초기화)
계산된 속성 (Computed)
- Vue 인스턴스를 초기화 할 때 사용한다.
- 메소드 수행 결과가 캐싱된다. 메소드 속성처럼 정의하고 데이터 속성처럼 사용한다.
<div id="app3-4">
<h1>{{ computedProperty }}</h1>
<button onclick="changeData();">change</button>
</div>
<script>
var app = new Vue({
el: '#app3-4',
computed: { // 초기값, 속성 변경 불가
computedProperty(){
console.log("computed?");
return new Date();
}
}
});
function changeData(){
app.computedProperty = new Date();
};
</script>
4.조건부 렌더링 (if문)
v-show, v-if & v-else & v-else-if
<div v-show = "속성값"> 내용 </div>
속성값은 true나 false를 판별할 수 있는 값
ex4-1) v-show 디렉티브 (css의 display 속성을 이용한 화면 표시 여부)
<div id="app4-1">
<div v-show='isLogin'>
<p>로그아웃 상태 화면</p>
<button onclick="login();">로그인</button>
</div>
<div v-show='!isLogin'>
<p>로그인 상태 화면</p>
<button onclick="logout();">로그아웃</button>
</div>
</div>
<script>
var app = new Vue({
el: '#app4-1',
data:{
isLogin: true
}
});
function login(){
app.isLogin = false;
};
function logout(){
app.isLogin = true;
};
</script>
ex4-2) v-if 디렉티브 (속성값이 true인 경우만 DOM요소를 랜더링)
<div id="app4-2">
<div v-if='isLogin'>
<p>로그아웃 상태 화면</p>
<button onclick="toggle();">로그인</button>
</div>
<div v-else>
<p>로그인 상태 화면</p>
<button onclick="toggle();">로그아웃</button>
</div>
</div>
<script>
var app = new Vue({
el: '#app4-2',
data:{
isLogin: true
}
});
function toggle(){
app.isLogin = !app.isLogin;
};
</script>
ex4-3) v-if & v-else & v-else-if
<div id="app4-3">
<p>오늘은
<span v-if='dayOfWeek==1'>월요일! 원래</span>
<span v-else-if='dayOfWeek==2'>화요일! 화가나서 </span>
<span v-else-if='dayOfWeek==3'>수요일! 수없이 </span>
<span v-else-if='dayOfWeek==4'>목요일! 목아프게 </span>
<span v-else-if='dayOfWeek==5'>금요일! 불금이라 </span>
<span v-else-if='dayOfWeek==6'>토요일! 토하도록</span>
<span v-else>일요일! 일없으니</span>
겁니 마시는 날~~~~
</p>
<button onclick="rand();">다른날은?</button>
</div>
<script>
var app = new Vue({
el: '#app4-3',
data:{
dayOfWeek: (new Date()).getDay()
}
});
function rand(){
app.dayOfWeek = Math.floor(Math.random()*7);
};
</script>
5. 이벤트 제어
v-on 디렉티브 (이벤트 등록)
약어(shorthand)로 @ 사용 가능
v-on 뒤에 : 을 사용하여 html의 이벤트 관련 속성 지정
v-on 디렉티브를 사용한 이벤트의 해제는 vue.js가 관리 합니다. (이벤트를 따로 제거할 필요가 없다.)
ex5-1) v-on:click, @click
<div id="app5-1">
<h1>{{ value }}</h1>
<!-- <button onclick='app.setValue("왼쪽");'>Click!!</button> -->
<button v-on:click='setValue("왼쪽");'>Click!!</button>
<button @click='setValue("오른쪽");'>Click!!</button>
</div>
<script>
var app = new Vue({
el: '#app5-1',
data:{
value: "클릭해 보세요~ 지발~~요~~"
},
methods:{
setValue: function(str){
this.value = str + " 버튼을 클릭했군요!!";
}
}
});
</script>
ex5-2) .enter 수식어
* 수식어(Modifier)
- 이벤트 처리를 더욱 손쉽게 도와주는 역할
- v-on 디렉티브 바로 뒤에 .(수식어명)을 이용하여 사용한다
- 키보드 수식어
- .enter .tab .esc .space
- .delete (delete와 backspace)
- .up .down .left .right
- .ctrl .alt .shift
- 마우스 수식어
- .left (왼쪽클릭) .right (오른쪽클릭) .middle (휠버튼클릭)
<div id="app5-2">
<h1>{{ value }}</h1>
<input id="inputValue" type="text" @keyUp.enter='setValue();'>
</div>
<script>
var app = new Vue({
el: '#app5-2',
data:{
value: "value"
},
methods:{
setValue: function(){
this.value = document.getElementById('inputValue').value;
}
}
});
</script>
ex5-3) 수식어의 체이닝
<div id="app5-3">
<h1>{{ value }}</h1>
<input id="inputValue" type="text" @keyUp.shift.enter='setValue();'>
</div>
<script>
var app = new Vue({
el: '#app5-3',
data:{
value: "value"
},
methods:{
setValue: function(){
this.value = document.getElementById('inputValue').value;
}
}
});
</script>
* shift.enter 키와 다른키가 클릭되어도 처리되는 문제점 발생
-해결방법 => .exact를 추가로 체이닝
<input id="inputValue" type="text" @keyUp.shift.enter.exact='setValue();'>
6.데이터 바인딩
v-bind 디렉티브, 클래스/스타일 바인딩
v-bind 디렉티브 => 태그 속성(Attribute)에 동적인 속성값 사용 (약어 : 로 사용가능)
ex6-1) v-bind 디렉티브
: 을 사용하여 태그 내 속성에 접근할 수 있다.
<div id="app6-1">
<li><a v-bind:href=' url '>{{ url }}</a></li>
<li><a :href=' getUrl("google") '>google</a></li>
<li><a :href=' getUrl("naver") '>naver</a></li>
</div>
<script>
var app = new Vue({
el: '#app6-1',
data:{
url: "http://google.com"
},
methods:{
getUrl: function(name){
return "https://" + name + ".com";
}
}
});
</script>
ex6-2) 일반 속성과의 중복
동등한 레벨 => 우선순위와 상관 없이 나중에 지정된 속성값이 처리됨
<div id="app6-2">
<li><a :href='url' href="http://naver.com">네이버</a></li>
<li><a href="http://naver.com" :href='url'>구글</a></li>
</div>
<script>
var app = new Vue({
el: '#app6-2',
data:{
url: "http://google.com"
}
});
</script>
ex6-3) 여러 값이 가능한 속성
class와 style 속성 => 기본속성 + v-bind 지정 속성 결합
<div id="app6-3">
<p :style='vueStyle' style='font-size:3em;'>스타일 바인딩</p>
<p :class='vueClass' class="box2">클래스 바인딩</p>
</div>
<script>
var app = new Vue({
el: '#app6-3',
data:{
vueStyle: "color:red; background:yellow;",
vueClass: "box1"
}
});
</script>
ex6-4) 클래스 바인딩 => 객체와 배열로 지정하는 방법 지원
object 속성 값이 false일 때는 class 적용되지 않음
<div id="app6-4">
<p :class='vueArray'>배열 지정</p> <!-- vueArray[1] 사용가능 -->
<p :class='vueObject'>객체 지정</p>
</div>
<script>
var app = new Vue({
el: '#app6-4',
data:{
vueArray: ["array1","array2", "array3"],
vueObject: {
object1:true,
object2:false, // class 적용 안됨
'object-3':true
}
}
});
</script>
7.폼 입력 바인딩
v-model 디렉티브
- form관련 태그의 입력과 데이터 동기화를 도와주는 양방향 바인딩 디렉티브
ex7-1) v-model과 input[type=text] => 데이터와 value속성(attribute)이 서로 바인딩 된다
input은 자동으로 v-model안에 변수에 그 값이 들어간다.
<div id="app7-1">
<h1>{{ value }}</h1>
<input type="text" v-model='value'>
<button @click='setDefault()'>기본값</button>
</div>
<script>
var app = new Vue({
el: '#app7-1',
data:{
value: "default"
},
methods:{
setDefault: function(){
this.value = "default";
}
}
});
</script>
ex7-2) v-model과 checkbox
* v-model과 checkbox 속성이 boolean(true/false)으로 바인딩
- 같은 데이터에 여러 체크박스가 설정되면 데이터가 체크박스의 value값 배열로 바인딩
<div id="app7-2">
<h1>{{ single }}</h1>
<input type="checkbox" v-model='single' value="단일체크박스">single
<h1>{{ multi }}</h1>
<input type="checkbox" v-model='multi' value="one">1
<input type="checkbox" v-model='multi' value="two">2
<input type="checkbox" v-model='multi' value="three">3
</div>
<script>
var app = new Vue({
el: '#app7-2',
data:{
single: true,
multi: []
}
});
</script>
ex7-3) radio, select, textarea
* v-model과 radio => 데이터와 선택된 값의 value 속성값이 바인딩
* v-model과 select => 데이터와 선택된 값의 value 속성값이 바인딩
* v-model과 textarea => 데이터와 textarea 내부값이 바인딩
<div id="app7-3">
<h1>{{ vueradio }}</h1>
<input type="radio" v-model='vueradio' name="radioset" checked value="one">1
<input type="radio" v-model='vueradio' name="radioset" value="two">2
<input type="radio" v-model='vueradio' name="radioset" value="three">3
<h1>{{ vueselect }}</h1>
<select v-model='vueselect'>
<option value="A">A</option>
<option value="B">B</option>
<option value="C">C</option>
</select>
<h1>{{ vuetextarea }}</h1>
<textarea v-model='vuetextarea' cols="30" rows="5"></textarea>
</div>
<script>
var app = new Vue({
el: '#app7-3',
data:{
vueradio: "one",
vueselect: "학점",
vuetextarea: "자기소개를 입력하세요"
}
});
</script>
ex7-4) 수식어 .lazy / .trim / .number
* v-model 수식어
.lazy | .trim | .number |
입력이 끝나면 바인딩 | 공백문자 정리 | 숫자를 자동 숫자로 변환 (문자>숫자) |
<div id="app7-4">
<h1>{{ str + " : " + typeof str }}</h1>
<input type="text" v-model.trim.lazy='str'>
<h1>{{ num + " : " + typeof num }}</h1>
<input type="number" v-model.number='num'>
</div>
<script>
var app = new Vue({
el: '#app7-4',
data:{
str: "default",
num: 100
}
});
</script>
8. 리스트 렌더링 v-for ( 반복문 )
* v-for 디렉티브 => 비슷한 템플릿을 반복해주는 역할
* 단순 횟수 반복 : v-for="n in 10" => n은 0~9가 아니라 1~10
ex8-1) 단순 횟수 반복
<div id="app8-1">
<ul>
<li v-for='i in 10'> <!-- i : 1~10 -->
2 * {{ i }} = {{ 2*i }}
</li>
</ul>
</div>
<script>
var app = new Vue({
el: '#app8-1'
});
</script>
ex8-2) 중첩 사용 반복
<div id="app8-2">
<ul v-for='i in 9'>
<li v-for='j in 9'>
{{ i }} * {{ j }} = {{ i*j }}
</li>
</ul>
</div>
<script>
var app = new Vue({
el: '#app8-2'
});
</script>
ex8-3) 배열과 객체 반복 item in array
* 배열(Array) 반복
v-for = "item in arry"
v-for = "(item,index) in arry"
* 객체(object) 반복
v-for = "item in object"
v-for = "(item,key) in object"
v-for = "(item,key,index) in object"
* 가능하면 배열을 사용 권장
- 객체의 경우 프로포트 명(key)의 순서 제어가 어렵고 객체의 프로퍼티 추가의 감지가 어려움
<div id="app8-3">
<ul>
<li v-for='item in arr'> {{ item }} </li>
</ul>
<ul>
<li v-for='item in obj'> {{ item }} </li>
</ul>
</div>
<script>
var app = new Vue({
el: '#app8-3',
data: {
arr: ["사과","배","감","바나나","망고"],
obj:{
one:"웹디자인",
two:"퍼블리셔",
three:"웹개발"
}
}
});
</script>
ex8-4) 배열과 객체 반복 2
<div id="app8-4">
<p v-for='(item,index) in arr'> {{ index }} => {{ item }} </p>
<p v-for='(item,key) in obj'> {{ key }} : {{ item }} </p>
<p v-for='(item,key,index) in obj'> {{ index }} => {{ key }} : {{ item }} </p>
</div>
<script>
var app = new Vue({
el: '#app8-4',
data: {
arr: ["사과","배","감","바나나","망고"],
obj:{
one:"웹디자인",
two:"퍼블리셔",
three:"웹개발"
}
}
});
</script>
ex8-5) 동적 배열 증가
<div id="app8-5">
<ul>
<li v-for='(no,i) in arr'> {{ '번호' + (i+1) + ' : ' + no + '명 입니다' }} </li>
</ul>
<button @click='append()'>추가</button>
</div>
<script>
var app = new Vue({
el: '#app8-5',
data: {
arr: [1,2,3],
cur:3
},
methods: {
append: function(){
// this.cur++;
this.arr.push(++this.cur); // ++cur 먼저 실행 후 push
}
}
});
</script>
ex8-6) 배열 메소드 응용(추가/삭제)
* 감지하는 배열의 메소드
.push() => 배열의 마지막 요소를 추가
.pop() => 배열의 마지막 요소를 제거
.shift() => 배열의 첫번째 요소를 제거
.unshift() => 배열의 첫번째 요소를 추가
.splice() => 배열의 일정 부분의 요소를 치환 및 제거 splice(인덱스번호, 갯수)
.sort() => 배열의 요소를 오름차순 정렬
.reverse() => 배열의 요소 순서를 역순으로 바꾼다
<div id="app8-6">
<ul>
<li v-for='(no,i) in arr'>
{{ no + '명 입니다' }}
<button @click='remove(i)'>삭제</button>
</li>
</ul>
<button @click='append(1)'>1명추가</button>
<button @click='append(5)'>5명추가</button>
<button @click='append(10)'>10명추가</button>
<button @click='sort()'>순서정리</button>
</div>
<script>
var app = new Vue({
el: '#app8-6',
data: {
arr: [],
cur:0
},
methods: {
append: function(x){
for(var i=0; i<x ; i++){
this.arr.push(++this.cur);
}
},
remove: function(index){
this.arr.splice(index,1);
},
sort : function(){
this.arr.sort(function(a,b){return b-a});
}
}
});
</script>
* Key 속성 바인딩
-데이터의 정확도와 성능향상을 위해 사용 (컴포넌트에서는 필수!!!)
ex8-7) 객체배열 읽어오기
<div id="app8-7">
<ul>
<li v-for="job in jobs">
<span>{{ '이름:' + job.name +', ' }}</span>
<span>{{ '나이:' + job.age +', ' }}</span>
<span>{{ '전화번호:' + job.tel +', ' }}</span>
<span>{{ '주소:' + job.add }}</span>
</li>
</ul>
</div>
<script>
var app = new Vue({
el: '#app8-7',
data: {
jobs:[
{name:'홍길동', age: 30, tel:'010-0000-0000', add:'서울'},
{name:'이순신', age: 20, tel:'010-1111-1111', add:'부산'},
{name:'최순실', age: 50, tel:'010-2222-3333', add:'교도소'}
]
}
})
</script>
ex8-8) json 파일 읽어오기
Vue CDN으로 제작 시 json 파일을 읽어오려면 아래 링크를 추가해야 한다.
exios cdn (vue에 사용하는 라이브러리)
https://joshua1988.github.io/vue-camp/vue/axios.html
뷰에서 권고하는 HTTP 통신 라이브러리는 액시오스(Axios)입니다. Promise 기반의 HTTP 통신 라이브러리이며 상대적으로 다른 HTTP 통신 라이브러리들에 비해 문서화가 잘되어 있고 API가 다양합니다.
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<style>
table{border-collapse: collapse;}
td{border: 1px solid #ccc; padding: 10px;}
</style>
<div id="app8-8">
<!-- <ul>
<li v-for="post in posts">
<span>{{ post.Name }}</span>
<span>{{ post.City }}</span>
<span>{{ post.Country }}</span>
</li>
</ul> -->
<table>
<tr v-for="(post,i) in posts">
<td>{{ i+1 }}</td>
<td>{{ post.Name }}</td>
<td>{{ post.City }}</td>
<td>{{ post.Country }}</td>
</tr>
</table>
</div>
<script>
var app = new Vue({
el: '#app8-8',
data: {
posts:[], // json 객체 배열을 담을 posts
posts2:[]
},
created: function(){ // 뷰 인스턴스가 생성될 때(실행될때) 자동으로 호출되는 함수
axios.get("./customers.json")
.then(function(response) { // then 통신되고 나면
this.posts = response.data.records // posts 배열에 담는다.
}.bind(this)) // 바인딩
}
})
// exios 문법
// var app = new Vue({
// el: '#app',
// methods: {
// fetchData: function() {
// axios.get('https://jsonplaceholder.typicode.com/users/')
// .then(function(response) {
// console.log(response);
// })
// .catch(function(error) {
// console.log(error);
// });
// }
// }
// })
</script>
ex8-9) 버튼 클릭 시 json 파일 읽어오기
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<style>
table{border-collapse: collapse;}
td{border: 1px solid #ccc; padding: 10px;}
</style>
<div id="app8-8">
<!-- <ul>
<li v-for="post in posts">
<span>{{ post.Name }}</span>
<span>{{ post.City }}</span>
<span>{{ post.Country }}</span>
</li>
</ul> -->
<button @click="jsonLoad">get Data</button>
<table>
<tr v-for="(post,i) in posts">
<td>{{ i+1 }}</td>
<td>{{ post.Name }}</td>
<td>{{ post.City }}</td>
<td>{{ post.Country }}</td>
</tr>
</table>
</div>
<script>
var app = new Vue({
el: '#app8-8',
data: {
posts:[] // json 객체 배열을 담을 posts
},
method: {
jsonLoad: function(){ // 뷰 인스턴스가 생성될 때(실행될때) 자동으로 호출되는 함수
axios.get("./customers.json")
.then(function(response) { // then 통신되고 나면
this.posts = response.data.records // posts 배열에 담는다.
}.bind(this)) // 바인딩
}
}
})
</script>
9. 인스턴스 생명주기
* 생명주기(Lifecycle)
-태어나서부터 죽기전까지 순환되는 일련의 과정
-(Vue Lifecycle)인스턴스가 생성되어 메모리에서 삭제되기 전까지의 주기
* 라이프사이클 다이어그램
https://kr.vuejs.org/v2/guide/instance.html
* Veu Instance의 생명주기
-생성(Create)
이벤트와 생명주기 메소드가 초기화
메소드 및 데이터 옵션을 주입(바인딩)하고 반응형으로 설정
-초기화(Mount)
템플릿을 읽어와 문법을 적용하고 화면에 랜더링
-갱신(Update)
데이처 속성의 변화를 감지하면 화면을 다시 랜더링
-소멸(Destroy)
데이터의 반응 해제 및 이벤트를 삭제하고 인스턴스를 소멸
* Lifecycle Hooks
-각 단계가 변할 때마다 수행할 콜백함수 지정 가능
-변화 전(before), 후(~ed)에 조작 가능
-Lifecycle Method Option
beforeCreate, created
beforeMount, mounted
beforeUpdate, updated
beforeDestroy, destroyed
ex9-1) step09code01.html 참고
10.여러개의 Vue 인스턴스 사용하기
ex10-1) 두개의 인스턴스 생성하기
<div id="app10-1">
{{ name }}<br>
<button @click="changeText">Click</button>
</div>
<div id="app10-2">
{{ name }}<br>
<button @click="changeText">Click</button>
</div>
<script>
const app101 = new Vue({
el: '#app10-1',
data: {
name: 'javascript'
},
methods: {
changeText() {
this.name = 'javascript updated';
}
},
})
const app102 = new Vue({
el: '#app10-2',
data: {
name: 'Vue'
},
methods: {
changeText() {
this.name = 'Vue updated';
}
},
})
</script>
ex10-2) 다른 인스턴스의 변수값에 접근하는 방법
<div id="app">
{{ name }}<br>
<button @click="changeText">Click</button>
</div>
<div id="app-1">
{{ name }}<br>
<button @click="changeText">Click</button>
</div>
<script>
const app = new Vue({
el: '#app',
data: {
name: 'javascript'
},
methods: {
changeText() {
app1.name = 'javascript updated';
}
},
})
const app1 = new Vue({
el: '#app-1',
data: {
name: 'Vue'
},
methods: {
changeText() {
app.name = 'Vue updated';
}
},
})
</script>
11. 컴포넌트(component) ★★★★★
template를 만들어 놓고 가져다가 사용하는 개념
- 뷰의 중요한 특징 중 하나인데 HTML의 기본 엘리먼트 외에 자신만의 엘리먼트를 만들어 쓰는 모듈을 의미
- 미리 만든 컴포넌트 이름을 가지고 여는 태그(<>)와 닫는 태그(</>)에 적용해 사용>
- 전역 컴포넌트를 등록하려면, Vue.component(tagName, options)를 사용합니다.
- data 는 반드시 함수여야합니다.
Vue.component('my-component', {
data: function () {
return {
}
},
template: `
`
})
<div id="example">
<my-component></my-component>
<!-- 아래 도 가능 -->
<my-component/>
</div>
-템플릿(template)이란?
새로운 엘리먼트처럼 사용할 수 있도록 컴포넌트를 등록할 때 html과 뷰 코드로 작성된 소스를 의미
-템플릿 속성
-컴포넌트 안에서 화면에 표시될 부분을 처리하는 속성
-html,css,javascript를 적용하여 표시될 내용의 구조와 표현, 사용자와의 상호작용 기능을 구현
-백틱(`) 키를 사용하여 문자열을 선언하면 줄바꿈이 있어도 html 문서로 자동으로 인식
ex11-1) 컴포넌트 등록 및 사용하기
<style>
.fruit_style {
border: 1px solid #ccc;
background-color: white;
padding-left: 1em;
}
</style>
<div id="main">
<h1>{{ sTitle }}</h1>
<!-- 신규 컴포넌트 엘리먼트를 2개 사용함 -->
<favorite-fruits></favorite-fruits>
<favorite-fruits></favorite-fruits>
</div>
<script>
// 좋아하는 과일 3개를 표시하는 컴포넌트를 정의
Vue.component('favorite-fruits', { // 데이터는 aFruits 배열에 3개의 과일명을 반환하는 함수로 정의
data: function () {
return {
aFruits: [{
sFruit_name: '사과'
},
{
sFruit_name: '오렌지'
},
{
sFruit_name: '수박'
}
]
}
},
// 템플릿은 화면에 표시할 엘리먼트 구조를 정의
template: `
<div>
<div v-for="item in aFruits" class="fruit_style">
<p>좋아하는 과일: {{ item.sFruit_name }}</p>
</div>
<br>
</div>`
});
new Vue({
el: '#main',
data: {
sTitle: '안녕하세요!',
}
});
</script>
ex11-2) 컴포넌트 속성(props)
-컴포넌트에서 전달되는 어트리뷰트의 값으로써, 문자열이나 객체의 배열 형식을 사용
<div id="app">
<h1>좋아하는 과일!</h1>
<my-fruits fruit="사과"></my-fruits>
<my-fruits fruit="오렌지"></my-fruits>
<my-fruits fruit="수박"></my-fruits>
<ol>
<!--
favorite-fruits 신규 엘리먼트 사용
aFruits 배열의 값을 반복문으로 가져와 fruit 속성에 바인딩하여 컴포넌트에 전달
key 속성은 반드시 고유한 값으로 전달되어야 하므로 item의 id값 대입
-->
<favorite-fruits
v-for = "item in aFruits"
v-bind:fruit = "item"
v-bind:key = "item.id"> <!-- 식별자 -->
</favorite-fruits>
</ol>
</div>
<script>
// Vue 인스턴스에 신규 엘리먼트 컴포넌트 등록
// props에 엘리먼트에 사용될 속성 이름 선언
Vue.component('my-fruits', {
props: ['fruit'], // props : 속성을 만듦 => <my-fruits fruit=''>
template: '<h2>좋아하는 과일 : {{ fruit }}</h2>'
})
//정규 속성을 표현식에 바인딩하는 것과 비슷하게, v-bind를 사용하여 부모의 데이터에 props를 동적으로 바인딩 할 수 있습니다.
//데이터가 상위에서 업데이트 될 때마다 하위 데이터로도 전달됩니다.
// template에 전달받은 속성 객체의 text 제목을 렌더링에 활용
Vue.component('favorite-fruits', {
props: ['fruit'],
template: '<li>{{ fruit.text }}</li>'
})
var app = new Vue({
el: '#app',
data: {
// 컴포넌트에 표시할 과일 데이터 정의
aFruits: [
{ id: 0, text: '사과' },
{ id: 1, text: '오렌지' },
{ id: 2, text: '수박' }
]
}
})
</script>
ex11-3) 컴포넌트 js 파일로 분리 (SPA)
index.html
<!DOCTYPE html>
<html lang="ko">
<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 Project</title>
<style>
*{margin: 0; padding: 0;}
img{border: 0; vertical-align: top;}
a{color: #333; text-decoration: none;}
ul{list-style: none;}
#app{width: 100%;}
header{background: pink; overflow: hidden;}
header h1{float: left; margin: 15px}
header ul{overflow: hidden; float: right;}
header ul li{float: left; margin:25px 15px 0 0;}
.visual img{width:100%;}
#content{padding: 15px; background: greenyellow; text-align: center;}
#content h2{margin-bottom: 20px;}
#content p{margin-bottom: 30px;}
footer{background: #333; overflow: hidden;}
footer p{text-align: center; color: #fff; margin: 15px 0;}
</style>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
</head>
<body>
<div id="app">
<Headerarea></Headerarea>
<Visualarea></Visualarea>
<Contentarea></Contentarea>
<Footerarea></Footerarea>
</div>
<script src="./component/Headerarea.js"></script>
<script src="./component/Visualarea.js"></script>
<script src="./component/Contentarea.js"></script>
<script src="./component/Footerarea.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
}
})
</script>
</body>
</html>
Headerarea.js
Vue.component('Headerarea', {
props: [],
template: `
<header>
<h1><a href="#">로고</a></h1>
<nav>
<ul>
<li><a href="#">메뉴1</a></li>
<li><a href="#">메뉴2</a></li>
<li><a href="#">메뉴3</a></li>
</ul>
</nav>
</header>
`
})
Visualarea.js
Vue.component('Visualarea', {
props: [],
template: `
<div class="visual">
<img src="./back.jpg">
</div>
`
})
Contentarea.js
Vue.component('Contentarea', {
props: [],
template: `
<article id="content">
<h2>본문입니다</h2>
<section>
<h3>콘텐츠1 제목</h3>
<p>콘텐츠1 내용</p>
</section>
<section>
<h3>콘텐츠2 제목</h3>
<p>콘텐츠3 내용</p>
</section>
</article>
`
})
Footerarea.js
Vue.component('Footerarea', {
props: [],
template: `
<footer>
<p>© Copyright</p>
</footer>
`
})
12. Vuex
Vuex를 사용하기 위해 CDN 연결
<script src="https://unpkg.com/vuex"></script>
13. 내비게이션과 라우터(router)
- 라우터(router)란 페이지끼리 이동할 수 있는 기능을 의미한다.
- 라우터를 사용하여 경로와 컴포넌트를 등록하면 싱글 페이지 어플리케이션(SPA) 사용자가 클릭한 경로로 화면이 쉽게 이동한다
-라우터를 사용하기 위해 해당 CDN 연결
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
라우터를 사용하기 위해 해당 CDN 연결
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<!-- or -->
<script src="https://unpkg.com/vue-router@2.0.0/dist/vue-router.js"></script>
ex 13-1) 라우터 등록 및 사용
router-link로 링크를 걸면 router-view에 표시된다.
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script src="https://unpkg.com/vue-router@2.0.0/dist/vue-router.js"></script>
<style>
.pmain{width: 600px; height: 300px; background: pink;}
.psub{width: 600px; height: 400px; background: green;}
</style>
<div id="app">
<h1>안녕하세요!</h1>
<!-- 현재 라우트 위치의 컴포넌트를 렌더링 시킴 -->
<router-view></router-view>
<hr>
<p>라우트 사용:
<!-- to 속성에 이동할 링크를 지정 -->
<router-link to="/main">메인 페이지 이동</router-link>
<router-link to="/sub">서브 페이지 이동</router-link>
</p>
</div>
<script>
// 라우트에 컴포넌트를 정의
const tmMain = {
template: '<h2>메인 페이지입니다.</h2>'
}
const tmSub = {
template: '<h2>서브 페이지입니다.</h2>'
}
// 이동할 주소명과 사용할 컴포넌트를 등록하여 라우트를 정의
const rtRoutes = [
{
path: '/',
component: tmMain
},
{
path: '/main',
component: tmMain
},
{
path: '/sub',
component: tmSub
}
]
// 라우트 인스턴스를 생성하고 `routes` 옵션을 전달
// 'router' 객체변수는 라우트 인스턴스이면서 Vue 생성 시 옵션으로 사용되므로 변수이름은 반드시 'router'사용
const router = new VueRouter({
routes : rtRoutes
})
// 뷰 루트 인스턴스를 만들고 router 옵션 추가
var app = new Vue({
el: '#app',
router
})
</script>
ex 13-2) 라우터 파일 분리
index.html
<!DOCTYPE html>
<html lang="ko">
<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 Project</title>
<style>
*{margin: 0; padding: 0;}
img{border: 0; vertical-align: top;}
a{color: #333; text-decoration: none;}
ul{list-style: none;}
#app{width: 100%;}
header{background: pink; overflow: hidden;}
header h1{float: left; margin: 15px}
header ul{overflow: hidden; float: right;}
header ul li{float: left; margin:25px 15px 0 0;}
.visual img{width:100%;}
#content{padding: 15px; background: greenyellow; text-align: center;}
#content h2{margin-bottom: 20px;}
#content p{margin-bottom: 30px;}
footer{background: #333; overflow: hidden;}
footer p{text-align: center; color: #fff; margin: 15px 0;}
</style>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script src="https://unpkg.com/vue-router@2.0.0/dist/vue-router.js"></script>
</head>
<body>
<div id="app">
<Headerarea></Headerarea>
<Visualarea></Visualarea>
<router-view></router-view>
<Footerarea></Footerarea>
</div>
<script src="./component/Headerarea.js"></script>
<script src="./component/Visualarea.js"></script>
<!-- <script src="./component/Contentarea.js"></script> -->
<script src="./component/Footerarea.js"></script>
<script src="./component/Main.js"></script>
<script src="./component/Sub1.js"></script>
<script src="./component/Sub2.js"></script>
<script>
// 이동할 주소명과 사용할 컴포넌트를 등록하여 라우트를 정의
const rtRoutes = [
{
path: '/',
component: Main
},
{
path: '/main',
component: Main
},
{
path: '/sub1',
component: Sub1
},
{
path: '/sub2',
component: Sub2
}
]
// 라우트 인스턴스를 생성하고 `routes` 옵션을 전달
// 'router' 객체변수는 라우트 인스턴스이면서 Vue 생성 시 옵션으로 사용되므로 변수이름은 반드시 'router'사용
const router = new VueRouter({
routes : rtRoutes
})
var app = new Vue({
el: '#app',
router,
data: {
}
})
</script>
</body>
</html>
./component/Headerarea.js
Vue.component('Headerarea', {
props: [],
template: `
<header>
<h1><a href="#">로고</a></h1>
<nav>
<ul>
<li><router-link to="/">Home</router-link></li>
<li><router-link to="/sub1">sub1</router-link></li>
<li><router-link to="/sub2">sub2</router-link></li>
</ul>
</nav>
</header>
`
})
./component/Visualarea.js
Vue.component('Visualarea', {
props: [],
template: `
<div class="visual">
<img src="./back.jpg">
</div>
`
})
./component/Footerarea.js
Vue.component('Footerarea', {
props: [],
template: `
<footer>
<p>© Copyright</p>
</footer>
`
})
./component/Sub1.js
const Sub1 = {
template: `
<article id="content">
<h2>서브페이지1 입니다</h2>
<section>
<h3>콘텐츠1 제목</h3>
<p>콘텐츠1 내용</p>
</section>
<section>
<h3>콘텐츠2 제목</h3>
<p>콘텐츠3 내용</p>
</section>
</article>
`
}
./component/Sub2.js
const Sub2 = {
template: `
<article id="content">
<h2>서브페이지2 입니다</h2>
<section>
<h3>콘텐츠1 제목</h3>
<p>콘텐츠1 내용</p>
</section>
<section>
<h3>콘텐츠2 제목</h3>
<p>콘텐츠3 내용</p>
</section>
</article>
`
}
Vue CLI 설치 및 세팅 - SPA
https://kr.vuejs.org/v2/guide/installation.html#CLI
NPM
Vue를 사용하여 대규모 애플리케이션을 구축할 때 NPM를 이용한 설치를 권장하고 있습니다. NPM은 Webpack 또는 Browserify와 같은 모듈 번들러와 잘 작동합니다. Vue는 싱글 파일 컴포넌트를 만들기 위한 도구도 제공합니다.
# 최신 안정화 버전
$ npm install vue
CLI
Vue.js는 단일 페이지 애플리케이션를 빠르게 구축할 수 있는 공식 CLI를 제공합니다. 최신 프론트엔드 워크 플로우를 위해 사전 구성된 빌드 설정을 제공합니다. 핫 리로드, 저장시 린트 체크 및 프로덕션 준비가 된 빌드로 시작하고 실행하는데 몇 분 밖에 걸리지 않습니다. 상세한 내용은 Vue CLI 문서에서 찾아보실 수 있습니다.
CLI 설치방법
01. nodejs 설치 (최신버전으로 세팅한다)
- https://nodejs.org/en/
- 안정화 버전 다운로드 14.15.1 LTS -> 최신버전으로 설치! => NPM 명령어를 사용할 수 있다!
- NPM 명령어를 콘솔창에서 사용하려면 node.js 설치가 필요하다.
02. visual studio code 설치
- https://code.visualstudio.com/
- 부가기능(확장) 설치
- vetur
- html css support
- vue 3 snippets
03. 개발환경 세팅
- visual studio code에 터미널을 열고 아래 명령어를 입력한다.
// 추천
$ npm install -g @vue/cli
// 또는 특정버전을 깔 수 있다.
$ npm install -g @vue/cli@4.5.11
// 또는
$ npm install vue
*에러 처리방법
https://online.codingapple.com/unit/vue-3-installation-with-vue-cli/?id=139
- 윈도우 Powershell에서 빨간글씨로 '보안오류'가 뜹니다.
"허가되지 않은 스크립트 입니다 어쩌구~" 그런 에러가 뜨면
윈도우 검색메뉴 (돋보기) - Powershell 검색 - 우클릭 - 관리자 권한으로 실행한 뒤
Set-ExecutionPolicy Unrestricted
라고 대소문자 하나라도 틀리지않고 입력하십시오.
그럼 이제 npm으로 뭐 하는거 잘됩니다.
04. vue 프로젝트 생성
- 작업 폴더를 만든다 c:/vue 폴더를 만든다
- vs code에서 open folder를 선택해서 c:/vue 폴더를 선택한다
- 터미널에서 아래와 값이 입력한다 (vue 버전 3을 선택한다)
c:/vue>vue create project1
여기까지 하고 아래로 이동!!!!!!!
- 프로젝트 생성이 완료되면 c:/vue/project1 폴더가 생성되고 필요한 파일들이 모두 세팅 되어있다
- vs code에서 open folder를 선택해서 c:/vue/project1 폴더를 선택한다
05. 코드작성
- project1 폴더에 src폴더에 App.vue(메인 페이지라고 생각하면 된다) 파일을 열과 코드를 작성한다
06. 결과를 브라우저에서 확인한다
c:/vue/project1>npm run serve
Local: http://localhost:8080/ (이주소를 크롬창에 입력한다)
참고(설치/세팅 방법 강좌)
https://www.youtube.com/watch?v=NONWar0jGLM&list=PLfLgtT94nNq3Br68sEe26jkOqCPK_8UQ-&index=2
1. Vue-CLI를 project1에 설치 한다
1-1. 폴더 생성하기 (경로 잡고 폴더 생성)
c:/vue> vue create project1
1-2. 폴더를 생성하고 옵션을 선택해야 설치가 진행된다.
//폴더 생성 후 옵션 선택
-please pick a preset : [Manuall select featres]
-check the featress needed .... : [Router]를 꼭 추가로 선택한다 (spacebar) => 엔터
-버전 선택 => 엔터
-use history mode ... : Y
-Pick a linter... : ESLink with error prevention only => 엔터
-Link on save 엔터
-In package.json 엔터
(?) -where do you prefer ... : [config]
-save this as preset ... : N
2. 작업 브라우저에서 확인하기 npm run serve
vue 프로젝트는 go live로 확인할 수 없다.
- src 폴더안에 App.vue 파일이 있다 (이 파일에 작업한다) - components / views 폴더를 삭제한다 (그냥 사용해도 됨)
- 터미널을 열고 입력한다 (project1 경로를 잡아준다)
c:/vue/project1>npm run serve
파일설명~.~
project1/package-lock.json => 설치 시 세팅된 내용
project1/node_modules => 자동으로 설치 된 라이브러리(?)들
project1/public/index.html => body에 <div id="app"></div>을 볼 수 있다.
project1/src/
project1/src/main.js
설치 시 옵션으로 선택 한 Vue, ./App.vue, ./router가 import 되어있고
new Vue 인스턴스가 만들어져있고
#app이 마운트 되어있다.
import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App)
}).$mount('#app')
project1/assets => 로고 이미지가 저장되어 있다.
proejct1/components => 컴포넌트 저장공간 (컴포넌트 확장자 .vue) (.js 사용 가능)
project1/router/index.js => 라우터 코드가 들어가 있다.
project1/views/ => 서브페이지들
project1/src/App.vue
- 작업할 파일. 메인 컴포넌트
- project1/src/main.js를 통해 project1/public/index.html로 보여진다.
작업하기
[생성] project1/src/main_page.vue
스크립트 문법이 cdn과 약간 다르다. (파일이 분리되어 있기 때문에)
export default { }를 이용해 data, methods만 정의해준다.
내부에서 만든 함수를 1. 내보내고(export) 2. main.js에서 받아 (import) 사용한다.
- 매개변수가 없는 함수는 호출 시 ( )를 생략할 수 있다.
<template lang="html">
<div class="box1">
<h2>메인 페이지 입니다.</h2>
<button @click="fnSubPage">서브 페이지로 이동(라우터 함수 사용)</button>
</div>
</template>
<script>
export default {
methods: {
// 라우터 함수로 이동할 때는 $router 글로벌 객체에 이동할 주소 넣어줌
fnSubPage() {
this.$router.push('/sub')
}
}
}
</script>
<style>
.box1{width: 90%; margin: 10px 5%; padding: 20px; box-sizing: border-box;
background: crimson; color: #fff;}
</style>
[생성] project1/src/sub_page.vue
<template lang="html">
<div class="box2">
<h2>서브 페이지 입니다.</h2>
<button @click="fnMainPage">메인 페이지로 이동(라우터 함수 사용)</button>
</div>
</template>
<style>
.box2{width: 90%; margin: 10px 5%; padding: 20px; box-sizing: border-box;
background:darkseagreen; color: #333;}
</style>
<script>
export default {
methods: {
// 라우터 함수로 이동할 때는 $router 글로벌 객체에 이동할 주소 넣어줌
fnMainPage() {
this.$router.push('/main')
}
}
}
</script>
project/src/router/index.js
컴포넌트 임폴트 및 경로를 설정해준다.
import Vue from 'vue'
import Router from 'vue-router'
// 라우터로 연결할 main_page, sub_page 컴포넌트 모듈 가져옴
import main_page from '../main_page.vue';
import sub_page from '../sub_page.vue';
Vue.use(Router)
export default new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{ path: '/', component: main_page},
{ path: '/main', component: main_page},
{ path: '/sub', component: sub_page}
]
})
project1/src/App.vue
<template>
<div id="app">
<HeaderArea></HeaderArea>
<!-- 라우터 컴포넌트에 연결된 컴포넌트가 렌더링 됨-->
<router-view></router-view>
<hr>
<p>라우터링크 사용:
<router-link to="/main">메인 페이지</router-link>
<router-link to="/sub">서브 페이지</router-link>
</p>
<div v-for="(x,ind) in onerooms" :key="ind">
<img :src="x.image" :alt="x.title" class="rimg">
<h4>{{ (x.id+1) + '.' + x.title }}</h4>
<p>{{ 'price : ' + x.price }}</p>
<p>{{ x.content }}</p>
</div>
<FooterArea></FooterArea>
</div>
</template>
<style>
*{margin:0; padding:0;}
#app {
font-family: Arial, sans-serif;
text-align: center;
color: #2c3e50;
}
.head{color:red;}
.rimg{width: 90%; margin: 15px auto;}
h4{font-size: 24px;margin: 15px 0;}
p{font-size: 18px; margin: 15px 0;}
</style>
<script>
import HeaderArea from './components/HeaderArea.vue'
import FooterArea from './components/FooterArea.vue'
import jdata from './oneroom.json'
export default {
name: 'app',
data(){
return{
onerooms : jdata // state 변수
}
},
components: {
HeaderArea,
FooterArea
}
};
</script>
project1/src/components/HeaderArea.vue
<template>
<header>
<h1><router-link to="/main">LOGO</router-link></h1>
<nav>
<ul>
<li><router-link to="/main">메인</router-link></li>
<li><router-link to="/sub">서브</router-link></li>
</ul>
</nav>
</header>
</template>
<style>
header{overflow: hidden;}
header h1 a{float:left; font-size:30px;}
header nav{float:right;}
header ul, header li{list-style:none; padding:0;}
header ul{text-align:center;}
header ul li{display:inline-block; margin:0 1rem;}
</style>
project1/src/components/FeaderArea.vue
<template>
<footer>
<p>© Copyright</p>
</footer>
</template>
빌드하기(배포하기)
npm run build
- Vue파일을 FTP에 그대로 올려서는 웹사이트에서 확인할 수 없다.
- 웹팩, 번들 이란 용어
- 빌드할때는 에러가 없어야 한다.
* 아래 나오는 vue.config.js 설정을 한 후 빌드하도록 하자
터미널에
npm run build
경로설정 vue.config
dist/index.html 을 살펴보면 경로가 모두 ' / '로 되어있다.
파일을 이용해 경로를 바꿔준 후 build 해야 한다.
project/vue.config.js 파일을 아래 내용으로 변경한다. (없다면 생성한다)
outputDir: path.resolve(__dirname, "./tastDist"); // 빌드 할 폴더명
publicPath: './' // 경로
const path = require("path");
module.exports = {
outputDir: path.resolve(__dirname, "./tastDist"),
publicPath: './'
// assetsDir: "./"
// asset 파일 위치 설정
}
이제 VS code go live로 페이지를 확인할 수 있다.
Vuetify
- https://vuetifyjs.com/ (Vue 2버전 사용)
- 뷰 자바스크립트 프레임워크에 머티리얼 디자인을 사용할 수 있는 컴포넌트 프레임워크이다.
- 뷰 용 부트스트랩이라고 생각하면 된다.
1. Vuetify 설치하기
1-1. Vue-CLI 를 설치한다. (라우터 포함 설치)
c:/vue> vue create project2
[참조] 1. Vue-CLI를 project1에 설치 한다 섹션을 참고하여 설치한다.
1-2. 콘솔창에 입력한다 (vuetify 플러그인 추가)
c:/vue/project2/vue add vuetify
옵션 선택은 Default 로 한다.
오류가 나면 아래 명령어를 터미널에 입력해준다.
npm audit fix
package.json에 14번째 줄 정도 "vuetify": "^2.6.0" 설치가 되었는지 확인한다.
1-3. 설치 확인
- project2/src/plugins/vuetify.js 가 생성되어 있다.
- project2/src/main.js 파일에 import vuetify from './plugins/vuetify' 가 추가된 것을 확인한다.
1-4. npm run serve로 확인
c:/vue/project2/npm run serve
에러가 생겼는데, project/src/views/HomeView.vue 의 name:을 변경해줬더니 됐다.
2. Vuetify 사용하기
project2/src/main.js
import Vue from 'vue'
import App from './App.vue'
// import router from './router'
import vuetify from './plugins/vuetify'
Vue.config.productionTip = false
new Vue({
// router,
vuetify,
render: h => h(App)
}).$mount('#app')
project2/src/App.vue
뷰티파이 문법을 사용할 수 있다.
<template>
<div id="app">
<v-app id="inspire">
<div>
코드를 가져와서 사용한다
</div>
</v-app>
</div>
</template>
<script>
export default {
name: 'App',
data: () => ({
//
}),
};
</script>
뷰티파이 사이트에서
https://vuetifyjs.com/en/components/api-explorer/ 에서 UI component 사용
- 해당 콤퍼넌트 들의 예시 파일의 좌측 상단메뉴의 두번째 edit in codepan 을 클릭하고 html의 코드를 복사해서 원하는 UI를 만든다
project2/src/App.vue
<template>
<div id="app">
<v-app id="inspire">
<div class="box1">
<v-alert
border="left"
colored-border
color="deep-purple accent-4"
elevation="2"
>
Aliquam eu nunc. Fusce commodo aliquam arcu. In consectetuer turpis ut velit. Nulla facilisi..
Morbi mollis tellus ac sapien. Fusce vel dui. Praesent ut ligula non mi varius sagittis. Vivamus consectetuer hendrerit lacus. Suspendisse enim turpis, dictum sed, iaculis a, condimentum nec, nisi.
</v-alert>
<v-alert
border="top"
colored-border
type="info"
elevation="2"
>
Vestibulum ullamcorper mauris at ligula. Nam pretium turpis et arcu. Ut varius tincidunt libero. Curabitur ligula sapien, tincidunt non, euismod vitae, posuere imperdiet, leo. Morbi nec metus.
</v-alert>
<v-alert
border="bottom"
colored-border
type="warning"
elevation="2"
>
Sed in libero ut nibh placerat accumsan. Phasellus leo dolor, tempus non, auctor et, hendrerit quis, nisi. Phasellus leo dolor, tempus non, auctor et, hendrerit quis, nisi. Sed consequat, leo eget bibendum sodales, augue velit cursus nunc, quis gravida magna mi a libero. Donec elit libero, sodales nec, volutpat a, suscipit non, turpis.
</v-alert>
<v-alert
border="right"
colored-border
type="error"
elevation="2"
>
Fusce commodo aliquam arcu. Pellentesque posuere. Phasellus tempus. Donec posuere vulputate arcu.
</v-alert>
</div>
<div class="box2">
<v-carousel hide-delimiters>
<v-carousel-item
v-for="(item,i) in items"
:key="i"
:src="item.src"
></v-carousel-item>
</v-carousel>
</div>
<div class="box3">
<v-expansion-panels focusable>
<v-expansion-panel
v-for="(item,i) in tabs"
:key="i"
>
<v-expansion-panel-header>{{ item.title }}</v-expansion-panel-header>
<v-expansion-panel-content>
{{ item.content }}
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
</div>
<div class="box4">
<v-card color="basil">
<v-card-title class="text-center justify-center py-6">
<h1 class="font-weight-bold text-h2 basil--text">
BASiL
</h1>
</v-card-title>
<v-tabs
v-model="tab"
background-color="transparent"
color="basil"
grow
>
<v-tab
v-for="item in basil"
:key="item"
>
{{ item }}
</v-tab>
</v-tabs>
<v-tabs-items v-model="tab">
<v-tab-item
v-for="item in basil"
:key="item"
>
<v-card
color="basil"
flat
>
<v-card-text>{{ text }}</v-card-text>
</v-card>
</v-tab-item>
</v-tabs-items>
</v-card>
</div>
</v-app>
</div>
</template>
<style>
*{margin:0; padding: 0;}
#app{padding:1rem;}
/* Helper classes */
.basil {
background-color: #FFFBE6 !important;
}
.basil--text {
color: #356859 !important;
}
</style>
<script>
export default {
name: 'App',
data () {
return {
items: [
{
src: 'https://cdn.vuetifyjs.com/images/carousel/squirrel.jpg',
},
{
src: 'https://cdn.vuetifyjs.com/images/carousel/sky.jpg',
},
{
src: 'https://cdn.vuetifyjs.com/images/carousel/bird.jpg',
},
{
src: 'https://cdn.vuetifyjs.com/images/carousel/planet.jpg',
},
],
tabs: [
{
title: '안녕1', content: 'ㅇㅇ1',
},
{
title: '안녕2', content: 'ㅇㅇ2',
},
{
title: '안녕3', content: 'ㅇㅇ3',
},
{
title: '안녕4', content: 'ㅇㅇ4',
},
{
title: '안녕5', content: 'ㅇㅇ5',
}
],
tab: null,
basil: [
'Appetizers', 'Entrees', 'Deserts', 'Cocktails',
],
text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.',
}
},
};
</script>
'Study > JavaScript' 카테고리의 다른 글
Momentum (0) | 2022.04.25 |
---|---|
React JS (0) | 2022.04.15 |
Angular JS (0) | 2022.04.06 |
마우스 휠 중복 과다 제어 막기 (0) | 2022.03.24 |
해상도별 이미지 교체 window resize (0) | 2022.01.11 |