test17
<div id="app">
<div>data : {{message}}</div>
<div>method kor : {{helloKor()}}</div>
<div>method eng : {{helloEng()}}</div>
</div>
<script>
new Vue({
el: '#app',
data: {
message: 'Hello 싸피',
name: '안효인',
},
methods: {
helloEng() {
return 'Hello ' + this.name;
},
helloKor() {
return '안녕 ' + this.name;
},
},
});
</script>
test18
<script>
let vm = new Vue({
data: {
count: 1
},
methods: {
incCount() {
console.log("incCount 호출됨");
this.count++
}
}
})
vm.incCount();
console.log(vm.count); // 2
</script>
{{}}
또는 v-bind
속성에서 사용 가능test19
<script>
Vue.filter('count1', (val) => {
if (val.length == 0) {
return;
}
return `${val} : ${val.length}자`;
});
new Vue({
el: '#app',
data: {
msg: '',
},
filters: {
count2(val, alternative) {
if (val.length == 0) {
return alternative;
}
return `${val} : ${val.length}자`;
},
},
});
</script>
test20
천 단위마다 ,
찍기, 전화번호에 -
넣기.
<script>
Vue.filter('price', (value) => {
if (!value) return value;
return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
});
Vue.filter('mobile', (value) => {
if (!value || !(value.length === 10 || value.length === 11)) return value;
return value.replace(/^(\d{3})(\d{3,4})(\d{4})/g, '$1-$2-$3');
});
new Vue({
el: '#app',
data: {
msg1: '',
msg2: '',
},
});
</script>
test22
test21
<div id="app">
<input type="text" v-model="message" />
<p>원본 메시지: "{{ message }}"</p>
<p>역순으로 표시한 메시지1: "{{ reversedMsg() }}"</p>
<p>역순으로 표시한 메시지2: "{{ reversedMsg() }}"</p>
<p>역순으로 표시한 메시지3: "{{ reversedMsg() }}"</p>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
message: '안녕하세요 싸피여러분',
},
methods: {
reversedMsg: function () {
console.log('거꾸로 찍기');
return this.message.split('').reverse().join('');
},
},
});
</script>
test23
<div id="app">
<div>
<input type="text" v-model="a" />
</div>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
a: 1,
},
watch: {
a: function (val, oldVal) {
console.log('new: %s, old: %s', val, oldVal);
},
},
});
console.log(vm.a);
vm.a = 2; // => new: 2, old: 1
console.log(vm.a);
</script>
test24
<div id="app">
<p>원본 메시지: "{{ message }}"</p>
<p>역순으로 표시한 메시지: "{{ reversedMsg }}"</p>
<input type="text" v-model="message" />
</div>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'Hello',
reversedMsg: '',
},
watch: {
message: function (newVal, oldVal) {
console.log(newVal, oldVal);
this.reversedMsg = newVal.split('').reverse().join('');
},
},
});
</script>
v-on
directive 사용v-on
test25
<div id="app">
<button v-on:click="counter += 1">클릭</button>
<p>위 버튼을 클릭한 횟수는 {{counter}} 번 입니다.</p>
</div>
<script>
new Vue({
el: '#app',
data: {
counter: 0,
},
});
</script>
test26
<div id="app">
<button v-on:click="greet">Greet</button>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
name: 'SSAFY',
},
methods: {
greet: function (event) {
alert('Hello ' + this.name + '!');
console.dir(event.target);
},
},
});
// 또한 JavaScript를 이용해서 메소드를 호출할 수 있습니다.
//vm.greet(); // => 'Hello Vue.js!'
</script>
test27
<div id="app">
<form action="http://www.naver.com">
<button v-on:click="greet1('SSAFY')">Greet</button>
<button v-on:click="greet2($event, 'Ssafy')">Greet</button>
</form>
</div>
<script>
new Vue({
el: '#app',
methods: {
greet1: function (msg) {
alert('Hello ' + msg + '!');
console.dir(event.target);
},
greet2: function (e, msg) {
if (e) e.preventDefault();
alert('Hello ' + msg + '!');
console.dir(e.target);
},
},
});
</script>
test27
에서의 event.preventDefault()와 같이 method 내에서 작업을 할 수도 있지만, method는 DOM의 이벤트를 처리하는 것보다 data 처리를 위한 로직만 작업하는 것이 좋다..
으로 표시된 접미사이다.test28
<div id="app">
<h2>페이지 이동</h2>
<a href="test29.html" @click="sendMsg1">페이지 이동 막기1</a><br />
<a href="test29.html" @click="sendMsg2">페이지 이동 막기2</a><br />
<a href="test29.html" @click.prevent="sendMsg1">페이지 이동 막기3</a><br />
</div>
<script>
new Vue({
el: '#app',
methods: {
sendMsg1() {
alert('이동할까요?');
},
sendMsg2(e) {
e.preventDefault();
alert('이동막기');
},
},
});
</script>
test29
<div id="app">
아이디 :<br>
<input placeholder="검색할 아이디를 입력하세요" v-model="id" @keyup="sendId" /><br>
<input placeholder="검색할 아이디를 입력하세요" v-model="id" @keyup.enter="sendId" /><br>
<input placeholder="검색할 아이디를 입력하세요" v-model="id" @keyup.13="sendId" /><br>
<button @click.once="sendId">검색</button>
</div>
<script>
new Vue({
el: '#app',
data: {
id: '',
},
methods: {
sendId() {
alert(this.id);
},
},
});
</script>
test30
<div id="app">
<h2>엘리먼트 참조하기</h2>
<!-- 아이디 : <input type="text" v-model="id"> -->
아이디 : <input type="text" v-model="id" ref="id" @keyup="idCheck" />
<button @click="idCheck">아이디 중복 체크</button>
<div v-bind:class="{success : isSuccess, fail : isFail}" v-bind:style="myStyle" v-html="msg"></div>
</div>
<script>
new Vue({
el: '#app',
data: {
id: '',
msg: '',
isSuccess: false,
isFail: false,
myStyle: {
fontSize: '25px',
},
},
methods: {
idCheck() {
if (this.id.length < 5 || this.id.length > 12) {
this.msg = `아이디는 5자이상 12자리 이하입니다.`;
this.$refs.id.focus();
console.dir(this.$refs.id);
this.isSuccess = false;
this.isFail = false;
return;
} else {
if (this.id === 'ssafy') {
this.msg = `<b>${this.id}</b>는 사용할 수 없습니다.`;
this.isSuccess = false;
this.isFail = true;
} else {
this.msg = `<b>${this.id}</b>는 사용할 수 있습니다.`;
this.isSuccess = true;
this.isFail = false;
}
}
console.log(this.$refs.id.value);
},
},
});
</script>
test31
<div id="app">
<div v-bind:class="{ active: isActive }">VueCSS적용</div>
<button v-on:click="toggle">VueCSS</button>
</div>
<script type="text/javascript">
new Vue({
el: '#app',
data: {
isActive: false,
},
methods: {
toggle: function () {
this.isActive = !this.isActive;
},
},
});
</script>
test32
<div id="app">
<ul>
<li :class="{completed: todo.done}" :style="myStyle" v-for="todo in todos">
{{todo.msg}}
<button @click="complete(todo)" class="btn">완료</button>
</li>
</ul>
</div>
<script>
new Vue({
el: '#app',
data: {
todos: [
{
msg: '5시간 잠자기',
done: false,
},
{
msg: '알고리즘 1시간 공부하기',
done: false,
},
{
msg: 'Vue 1시간 공부하기',
done: false,
},
],
myStyle: {
fontSize: '20px',
},
},
methods: {
complete: function (todo) {
todo.msg = todo.msg + '완료';
todo.done = !todo.done;
},
},
});
</script>
v-model
directive를 사용하여 폼 input과 textarea element에 양방향 데이터 바인딩을 생성할 수 있다.
test33
<div id="app">
<div>
아이디 :
<input v-model.trim="id" placeholder="아이디를 입력하세요" />
<!-- v-model은 기본적으로 모든 key stroke가 발생할 때마다 값을 업데이트 시킨다.
.lazy 수식어를 추가하여 change 이벤트 이후에 동기화 할 수 있습니다. -->
<input v-model.lazy="id" placeholder="아이디를 입력하세요" />
</div>
<div>
메세지 :
<textarea v-model="message" placeholder="내용을 입력하세요"></textarea>
</div>
<p>{{ id }} 님에게 보내는 메세지 : {{ message }}</p>
</div>
<script>
new Vue({
el: '#app',
data: {
id: '',
message: '',
},
});
</script>
<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{checked}} </label>
test34
<div id="app">
<div>
<p>
이메일 수신
<input type="checkbox" id="emailYN" v-model="email" />
<label for="emailYN">{{ email }}</label>
</p>
</div>
<div>
<p>
SMS 수신
<input type="checkbox" id="smsYN" v-model="sms" true-value="Y" false-value="N" />
<label for="smsYN">{{ sms }}</label>
</p>
</div>
</div>
<script>
new Vue({
el: '#app',
data: {
email: false,
sms: 'Y',
},
});
</script>
test35
<div id="app">
<div>당신이 가고 싶은 지역을 선택하시오</div>
<input type="checkbox" id="buk" value="부울경" v-model="checkedAreas" />
<label for="buk">부울경</label>
<input type="checkbox" id="gwangju" value="광주" v-model="checkedAreas" />
<label for="gwangju">광주</label>
<input type="checkbox" id="gumi" value="구미" v-model="checkedAreas" />
<label for="gumi">구미</label>
<input type="checkbox" id="daejeon" value="대전" v-model="checkedAreas" />
<label for="daejeon">대전</label>
<input type="checkbox" id="seoul" value="서울" v-model="checkedAreas" />
<label for="seoul">서울</label>
<br />
<span>체크한 이름: {{ checkedAreas }}</span>
</div>
<script>
new Vue({
el: '#app',
data: {
checkedAreas: [],
},
});
</script>
<input type="radio" id="one" value="One" v-model="picked">
<label for="one">One</label>
<br>
<input type="radio" id="two" value="Two" v-model="picked">
<label for="two">Two</label>
<br>
<span>t선택 : {{ picked }} </span>
test36
<div id="app">
<div>수업을 듣는 지역을 선택하시오</div>
<div>
<input type="radio" id="buk" value="부울경" v-model="ckArea" />
<label for="buk">부울경</label>
<input type="radio" id="gwangju" value="광주" v-model="ckArea" />
<label for="gwangju">광주</label>
<input type="radio" id="gumi" value="구미" v-model="ckArea" />
<label for="gumi">구미</label>
<input type="radio" id="daejeon" value="대전" v-model="ckArea" />
<label for="daejeon">대전</label>
<input type="radio" id="seoul" value="서울" v-model="ckArea" />
<label for="seoul">서울</label>
</div>
<span>선택한 지역 : {{ ckArea }}</span>
</div>
<script>
new Vue({
el: '#app',
data: {
ckArea: '광주',
},
});
</script>
v-model
표현식의 초기 값이 어떤 옵션에도 없으면, <select>
element는 "선택 없음" 상태로 랜더링된다.test37
<div id="app">
<div>
<p>수업을 듣는 지역을 선택하시오</p>
<select v-model="selectedArea">
<option disabled value="">선택하세요</option>
<option value="buk">부울경</option>
<option value="gwangju">광주</option>
<option value="gumi">구미</option>
<option value="daejeon">대전</option>
<option value="seoul">서울</option>
</select>
</div>
<span>선택한 지역 : {{ selectedArea }}</span><br />
</div>
<script>
new Vue({
el: '#app',
data: {
selectedArea: '',
},
});
</script>
test38
<div id="app">
<div>
<p>수업을 듣고자하는 지역을 선택하시오(다중가능)</p>
<select v-model="selectedArea" multiple>
<option disabled value="">선택하세요</option>
<option value="buk">부울경</option>
<option value="gwangju">광주</option>
<option value="gumi">구미</option>
<option value="daejeon">대전</option>
<option value="seoul">서울</option>
</select>
</div>
<span>선택한 지역 : {{ selectedArea }}</span>
</div>
<script>
new Vue({
el: '#app',
data: {
selectedArea: [],
},
});
</script>
v-for를 이용한 동적 option 렌더링.
test39
<div id="app">
<div>
<select>
<option value="1">1</option>
<option value="2" selected>2</option>
<option value="3">3</option>
</select>
<p>수업을 듣는 지역을 선택하시오</p>
<select v-model="selectedArea">
<option v-for="option in options" v-bind:value="option.value">{{ option.text }}</option>
</select>
</div>
<span>선택한 지역 : {{ selectedArea }}</span>
</div>
<script>
new Vue({
el: '#app',
data: {
selectedArea: '',
options: [
{ text: '서울', value: 'seoul' },
{ text: '광주', value: 'gwangju' },
{ text: '대전', value: 'daejeon' },
{ text: '구미', value: 'gumi' },
{ text: '부울경', value: 'buk' },
],
},
created() {
param = 'gwangju';
this.selectedArea = param;
},
});
</script>
<input v-model.lazy="msg">
<input v-model.number="age" type="number">
<input v-model.trim="msg">
test01
<div id="app1">
</div>
<div id="app2">
</div>
<script>
// 전역 컴포넌트 설정
new Vue({
el: '#app1',
});
new Vue({
el: '#app2',
});
</script>
components
인스턴스 옵션으로 등록함으로써 다른 인스턴스/컴포넌트의 범위에서만 사용할 수 있는 컴포넌트를 만들 수 있다.test02
<div id="app1">
<my-local></my-local>
<my-local></my-local>
</div>
<div id="app2">
<my-local></my-local>
<my-local></my-local>
</div>
<script>
new Vue({
el: '#app1',
// 지역 컴포넌트 설정
});
new Vue({
el: '#app2',
});
</script>
test03
<div id="app">
<my-comp></my-comp>
</div>
<!-- template 설정 -->
<script>
Vue.component('MyComp', {
template: '#MyComp',
data() {
return {
msg: 'hello component',
};
},
});
new Vue({
el: '#app',
});
</script>
test04
문제점.
<div id="app">
<count-view></count-view>
<count-view></count-view>
<count-view></count-view>
</div>
<template id="CountView">
<div>
<span>{{ count }}</span>
<button @click="count++">클릭</button>
</div>
</template>
<script>
let num = {
count: 0,
};
Vue.component('countView', {
data() {
return num;
},
template: '#CountView',
});
new Vue({
el: '#app',
});
</script>
test05
해결법.
<h2>컴포넌트 데이터 공유 문제 해결</h2>
<div id="app">
<count-view></count-view>
<count-view></count-view>
<count-view></count-view>
</div>
<template id="CountView">
<div>
<span>{{ count }}</span>
<button @click="count++">클릭</button>
</div>
</template>
<script>
Vue.component('CountView', {
template: '#CountView',
data() {
return {
count: 0,
};
},
});
new Vue({
el: '#app',
});
</script>
test06
<div id="app">
<h2>props test</h2>
</div>
<script>
//하위 컴포넌트
new Vue({
el: '#app',
});
</script>
new Vue()
로 상위 컴포넌트인 인스턴스를 하나 생성.Vue.component()
를 이용하여 하위 컴포넌트인 child-component를 생성.<div id="app">
내부에 <chile-component>
가 있기 때문에 하위 컴포넌트가 된다. 처음 생성한 인스턴스 객체가 #app의 요소를 가지기 때문에 부모와 자식 관계가 성립된다.v-bind
속성을 사용하면 상위 컴포넌트의 data의 key에 접근이 가능하다. (message)'<span>{{propsdata}}</span>'
에게 전달된다.v-bind
를 사용하여 부모의 데이터에 props를 동적으로 바인딩 할 수 있다.test07-1
<div id="app">
<child-comp area="부울경" v-bind:msg="msg[parseInt(Math.random() * 5)]"></child-comp>
<child-comp area="광주" v-bind:msg="msg[parseInt(Math.random() * 5)]"></child-comp>
<child-comp area="구미" v-bind:msg="msg[parseInt(Math.random() * 5)]"></child-comp>
<child-comp area="대전" v-bind:msg="msg[parseInt(Math.random() * 5)]"></child-comp>
<child-comp area="서울" v-bind:msg="msg[parseInt(Math.random() * 5)]"></child-comp>
</div>
<template id="ChildComp">
<div>
<h2>SSAFY {{area}}지역 7기 {{msg}}</h2>
</div>
</template>
<script>
Vue.component('childComp', {
props: ['area', 'msg'],
template: '#ChildComp',
});
new Vue({
el: '#app',
data: {
msg: ['굿^^', '최고!!', '실화냐?', '좋아요*', '짱!!'],
},
});
</script>
test07-2
<div id="app">
<child-comp v-for="(area, i) in areas" :key="i" :area="area" v-bind:msg="msg[parseInt(Math.random() * 5)]">
</child-comp>
</div>
<template id="ChildComp">
<div>
<h2>SSAFY {{area}}지역 7기 {{msg}}</h2>
</div>
</template>
<script>
Vue.component('childComp', {
props: {
'area': String,
'msg': {
type: String, require: true
}
},
template: '#ChildComp',
});
new Vue({
el: '#app',
data: {
areas: ['부울경', '광주', '구미', '대전', '서울'],
msg: ['굿^^', '최고!!', '실화냐?', '좋아요*', '짱!!'],
},
});
</script>
v-bind:prop-name
대신 v-bind
만 작성함으로써 모든 속성을 prop으로 전달할 수 있다.test08
<h2>컴포넌트 객체 데이터 전달</h2>
<div id="app">
</div>
<script>
new Vue({
el: '#app',
data() {
return {
user: {
name: '홍길동',
age: 22,
email: 'hong@ssafy.com',
},
};
},
});
</script>
v-on
이벤트 리스너는 항상 자동으로 소문자 변환되기 때문에 이벤트 이름은 kebab-case를 사용하는 것이 권장됨.test09
<h2>사용자 정의 이벤트</h2>
<div id="app">
<button v-on:click="doAction">메세지전송</button>
<h2>{{message}}</h2>
</div>
<script>
new Vue({
el: '#app',
data: {
message: '',
},
methods: {
doAction() {
this.$emit('sendMsg', '안녕하세요 여러분');
},
},
created() {
this.$on('sendMsg', (msg) => {
alert(msg);
this.message = msg;
});
},
});
</script>
test10
<div id="app">
<h4>당신이 좋아하는 파트를 선택하세요</h4>
<h2>총 투표수 : {{ total }}</h2>
<subject v-on:add-total-count="addTotalCount" title="코딩"></subject>
<subject v-on:add-total-count="addTotalCount" title="알고리즘"></subject>
</div>
<script>
Vue.component('Subject', {
template: '<button v-on:click="addCount">{{title}} - {{ count }}</button>',
//props 설정
data: function () {
return {
count: 0,
};
},
methods: {
addCount: function () {
this.count += 1;
// 부모 v-on:이름 에 해당하는 이름의 이벤트를 호출
},
},
});
new Vue({
el: '#app',
data: {
total: 0,
},
methods: {
addTotalCount: function () {
this.total += 1;
},
},
});
</script>
test11
<div id="app">
<my-count></my-count>
<log></log>
</div>
<template id="myCount">
<div>
<input type="text" v-model.number="count" @keyup.enter="send" />
<button @click="send">보내기</button>
</div>
</template>
<template id="log">
<div>
<h2>{{count}}</h2>
<ul>
<li v-for="msg in list">{{msg}}</li>
</ul>
</div>
</template>
<script>
const bus = new Vue();
Vue.component('myCount', {
template: '#myCount',
data() {
return {
count: 0,
};
},
methods: {
send() {
bus.$emit('updateLog', this.count);
this.count = '';
},
},
});
Vue.component('Log', {
template: '#log',
data() {
return {
count: 0,
list: [],
};
},
methods: {
updateLog(data) {
this.count += data;
this.list.push(`${data}을 받았습니다.`);
},
},
created: function () {
bus.$on('updateLog', this.updateLog);
},
});
new Vue({
el: '#app',
});
</script>