return {
...todo,
id: index+1,
done: false
}
return Object.assign(
{}, todo, {
id: index+1,
done: false
})
Object.assign : 새로운 객체를 반환할 때 사용
두번쨰 인자와 세번째 인자를 병합하여 return한다
그리고 다음으로 done의 상태에 따라 check를 하는 input checkbox를 만든다
양방향 binding은 v-model을 사용한다
<!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 Test</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div
v-for="todo in computedTodos"
:key="todo.id"> <!--밑에서 computed로 추가한 id를 사용한다-->
<input type="checkbox"
v-model="todo.done">
{{todo.title}}
</div>
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
todos: [
{title: '아침먹기'},
{title: '점심먹기'},
{title: '저녁먹기'},
]
},
computed: {
computedTodos(){
return this.todos.map((todo, index) =>{
return {
...todo,
id: index+1,
done: false
}
})
}
}
})
</script>
</body>
</html>
vue에있는 data를 methods를 사용하여 거꾸로 출력해보자
<!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 Test</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div>{{reverseMsg()}}</div>
<div>{{reverseMsg()}}</div>
<div>{{reverseMsg()}}</div>
<div>ㅡㅡㅡㅡㅡㅡㅡㅡ</div>
<div>{{reversedMsg}}</div>
<div>{{reversedMsg}}</div>
<div>{{reversedMsg}}</div>
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
msg : "hello world"
},
computed: {
reversedMsg(){
return this.msg.split('').reverse().join('')
}
},
methods: {
reverseMsg(){
return this.msg.split('').reverse().join('')
}
}
})
</script>
</body>
</html>
computed: {
reversedMsg(){
return this.msg.split('').reverse().join('')
},
reversedMsg: {
get(){
return this.msg.split('').reverse().join('')
}
}
}
<!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 Test</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div>{{reversedMsg}}</div>
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
msg : "hello world"
},
computed: {
reversedMsg: {
get(){
return this.msg.split('').reverse().join('')
},
set(val){
this.msg = val
}
}
}
})
</script>
</body>
</html>
data가 언제 바뀌는건지 정확하지 않고 메세지가 바꼈을 때 특정한 로직을 실행해야한다면, 바뀌는 시점을 감시할 수 있어야한다
<!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 Test</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
</head>
<body>
<div id = "app">
<diV>{{msg}}</diV>
<div>{{reversedMsg}}</div>
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
msg : 'hello bue!~!~'
},
computed: {
reversedMsg(){
return this.msg.split('').reverse().join('')
}
},
watch: {
msg(newMsg){ //msg가 변경되면 이렇게 됨
console.log('변경되었습니다!! : ' + newMsg)
},
reversedMsg(newMsg){
console.log('reversedMsg 변경되었스니다!! : ' + newMsg)
}
}
})
</script>
</body>
</html>
특정한 html 속성에 data를 연결하려면 v-bind를 사용했었다
특정한 class를 동적으로 바인딩하기 위해서 v-bind를 사용한다
1. 인라인방식으로 객체데이터를 html template에 적기
<div
class="static"
v-bind:class="{ active: isActive, 'text-danger': hasError }"
></div>
data() {
return {
classObject: {
active: true,
'text-danger': false
}
}
}
<div v-bind:class="classObject"></div>
3. data와 computed를 활용한 바인딩
data() {
return {
isActive: true,
error: null
}
},
computed: {
classObject() {
return {
active: this.isActive && !this.error,
'text-danger': this.error && this.error.type === 'fatal'
}
}
}
배열을 v-bind:class에 전달할 수 있다
v-bind:class="[ ... ]"
<!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 Test</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
</head>
<body>
<style>
.active {
background-color: red;
}
.text-danger{
font-size: 100px;
}
</style>
<div id = "app" :class="[classes]">
안녕
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
isActive : true,
classes : [
'active', 'text-danger']
},
computed: {
classObject(){
return{
'text-danger': true,
active : this.isText
}
}
}
})
</script>
</body>
</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 Test</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
</head>
<body>
<style>
.active {
background-color: red;
}
.text-danger{
font-size: 100px;
}
</style>
<div id = "app" v-bind:class="[isActive ? class1 : '', errorClass]">
안녕
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
isActive : true,
errorClass : 'text-danger'
},
computed: {
class1(){
return{
'text-danger': true,
active : true
}
}
}
})
</script>
</body>
</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 Test</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
</head>
<body>
<style>
.active {
font-size: 100px;
}
.one{
margin-left: 200px;
}
.bar{
background-color: blue;
}
.two{
color: cadetblue;
}
</style>
<div id = "app">
<component1 class ="one two">
</component1>
</div>
<script>
Vue.component('component1', {
template: '<p class="active bar">HIHI</p>'
})
const vm = new Vue({
el: '#app',
data: {
isActive : true,
bar: 'bar',
}
})
</script>
</body>
</html>
여러개의 데이터는 띄어쓰기로 구분한다
template의 최상위 element와 compoent1을정의했을때의 최상위 element는 같다 즉, 위의 코드는 아래의 코드와 같다
<component1 :class ="one, two, active, bar"></component1>
v-bind : vue에 있는 data를 연결하는 디렉티브
<!DOCTYPE html>
<html lang="ko">
<body>
<div id = "app" v-bind:style="style1">
야옹야옹멍멍
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
style1:{
color: 'red',
fontSize: '150px'
}
}
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="ko">
<body>
<div id = "app" v-bind:style="{color: redColor, fontSize: '100px'}">
야옹야옹멍멍
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
redColor: 'red',
}
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="ko">
<body>
<div id = "app" v-bind:style="[style1, style2]">
야옹야옹멍멍
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
style1:{
color: 'red',
fontSize: '100px'
},
style2:{
color: 'blue'
}
}
})
</script>
</body>
</html>
<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>
colorState라는 변수를 둬서 빨간색이면 빨간 박스를, 파란색이면 파란박스를, 나머지색이면 회색박스를 출력해보자
<!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 Test</title> <script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script> </head> <body> <style> .box{ width: 100px; height: 100px; } .red-box{ background-color: red; } .gray-box{ background-color: gray; } .blue-box{ background-color: blue; } </style> <div id = "app" v-bind:style="[style1, style2]"> <div v-if="colorState==='red'" class ="box red-box"></div> <div v-else-if="colorState==='blue'" class="box blue-box"></div> <div v-else class="box gray-box"></div> </div> <script> const vm = new Vue({ el: '#app', data: { colorState:'white' } }) </script> </body> </html>
v-if를 사용하면 매번 요소를 생성·삭제해야한다
<!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 Test</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
</head>
<body>
<div id = "app">
<ul>
<li v-for="(todo, index) in todos"
:key="index"
:class="'item' + (index+1)"
@click="click1(todo.title, $event)">
{{todo.title}}</li>
</ul>
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
todos:[
{title: '아침먹기'},
{title: '점심먹기'},
{title: '저녁먹기'},
]
},
methods: {
click1(title, event){
console.log(title)
console.log(event.currentTarget.className)
}
}
})
</script>
</body>
</html>
@click="click1(todo.title, $event); click2()"
<script>
$(document).ready(function() {
$('#aTag').on('click', function(e) {
e.preventDefault(); // 이벤트 작동 X
console.log("https://plitche.github.io")
})
});
</script>
이벤트 캡쳐는 이벤트 버블링과 반대 방향으로 진행되는 이벤트 전파 방식입니다.
.stop : 이벤트 버블링을 막아준다(event.stopPrepagation)
.prevent : event.preventDefault
.capture : 캡처링
.self : 이벤트가 붙어있는 딱 그 공간이어야만 작동된다
이벤트 뒤에 수식어를 붙여 사용한다
<!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 Test</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
</head>
<body>
<style>
.parent{
width: 200px;
height: 200px;
background-color: blue;
}
.child{
width: 100px;
height: 100px;
background-color: red;
}
</style>
<div id = "app" class="parent" @click="click1">
<div class="child" @click="click1"></div>
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
},
methods: {
click1(event){
console.log(event.currentTarget.className)
}
}
})
</script>
</body>
</html>
<div id = "app" class="parent" @click.self="click1">
<div class="child" ></div>
</div>
사용자의 키 입력이 들어올 때 수식어를 설정할 수 있다
<!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 Test</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
</head>
<body>
<div id = "app">
<input type="text" @KeyDown="keyHandler">
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
},
methods: {
keyHandler(e){
if(e.keyCode===13) console.log("done!")
}
}
})
</script>
</body>
</html>
<input type="text" @KeyDown.enter="keyHandler">
키는 chain으로 참조하여 사용할 수 있다
<input type="text" @KeyDown.ctrl.enter="keyHandler">
form : input, text area, select ...
이러한 양식요소들을 사용하기위해서 vue에서는 v-model이라는 디렉티브를 사용한다
<!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 Test</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
</head>
<body>
<div id = "app">
<input type="text" v-bind:value="msg"> <!-- 기본 값-->
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
msg: 'hello~'
},
methods: {
}
})
</script>
</body>
</html>
<input type="text" v-model="msg">
단, 한글은 글자하나의 입력이 완료 되어야지 출력된다

<!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 Test</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
</head>
<body>
<div id = "app">
<input type="text" v-on:input="bindMessage" :value="msg">
{{msg}}
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
msg: 'hello~'
},
methods: {
bindMessage(event){
this.msg = event.target.value
}
}
})
</script>
</body>
</html>
아래와 같이도 가능
<input type="text" v-on:input="msg = $event.target.value">
실시간으로 탐지하는게 아니라 enter를 눌렀을때만 변경감지가 되도록, 또한 양방향이도록 헤보자
- change : focus가 풀리거나 했을 때 메서드를 지정해줄 수 있다
<!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 Test</title> <script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script> </head> <body> <div id = "app"> <input type="text" v-on:change="changeMessage" :value="msg"> {{msg}} </div> <script> const vm = new Vue({ el: '#app', data: { msg: 'hello~' }, methods: { changeMessage(event){ this.msg = event.target.value } } }) </script> </body> </html>위 작업에 해당하는 수식어가 있다
<input type="text" v-model.lazy="msg" :value="msg">
원래는 trim이라는 method를 제공해주는데 매번 method 사용 없이 수식어로 사용이 가능하다
<input type="text" v-model.trim="msg" :value="msg">
input에 있는 data를 string이 아닌 숫자로 변환해준다
<div id = "app">
<input type="text" v-model.number="msg" :value="msg">
{{msg}}
<div>{{typeof msg}}</div>
</div>
ui의 그룹(덩어리)
Vue.component('my-component1',
{
template: '<div class="me">{{msg}}</div>',
data(){
return{
msg: 'hello vue'
}
}
})
<body>
<div id = "app1">
<my-component/>
</div>
<div id = "app2">
<my-component/>
</div>
<script>
const myCompo = {
template: '<div class="me">{{msg}}</div>',
data(){
return{
msg: 'hello vue'
}
}
}
const vm1 = new Vue({
el: '#app1',
components: {
'my-component': myCompo
}
})
const vm2 = new Vue({
el: '#app2'
})
</script>
</body>
<body>
<div id = "app1">
<my-compo/>
</div>
<div id = "app2">
</div>
<script>
const myCompo = {
template: '<div class="me">{{msg}}</div>',
data(){
return{
msg: 'hello vue'
}
}
}
const vm1 = new Vue({
el: '#app1',
components: {
myCompo
}
})
const vm2 = new Vue({
el: '#app2'
})
</script>
</body>
Vue.component('my-component', {
template: '<div>{{msg}}</div>',
props : ['msg']
})
Vue.component('my-component', {
template: '<div>{{msg}}</div>',
props : {
msg : String //msg 가 string이 아니면 error!
}
})
<body>
<div id = "app">
<my-component ></my-component>
</div>
<script>
Vue.component('my-component', {
template: '<div>{{msg}}</div>',
props : {
msg : {
type: String,
default: "default value"
}
}
})
const vm = new Vue({
el: '#app',
data(){
return{
"msg" : "msg"
}
}
})
</script>
</body>
msg : {
type: [String, Number],
default: "default value",
required: true //msg라는 속성을 정의해주지 않을떄 error
}
<script>
Vue.component('my-component', {
template: '<div>{{msg}}</div>',
props : {
msg : {
type: [String, Number],
default: "default value",
required: true,
validator(val){ // true가 return되면 유효성검사를 통과한 것!
return val ==='hello'
}
}
}
})
const vm = new Vue({
el: '#app',
data(){
return{
"msg" : "hello"
}
}
})
</script>
<my-component :my-msg="msg"></my-component>
Vue.component('my-component', {
template: '<div>{{myMsg}}</div>',
props : {
myMsg : {
type: [String, Number],
default: "default value",
required: true,
validator(val){ // true가 return되면 유효성검사를 통과한 것!
return val ==='hello'
}
}
}
})
<body>
<div id = "app">
<my-component :my-msg="msg"></my-component>
</div>
<script>
Vue.component('my-component', {
template: '<div @click="updateMsg">{{myMsg}}</div>',
props:{
myMsg: String
},
methods:{
updateMsg(){
this.myMsg = "goood"
}
}
})
const vm = new Vue({
el: '#app',
data(){
return{
"msg" : "hello"
}
}
})
</script>
</body>
출처
https://cucat.tistory.com/entry/CSS-벤더프리픽스-예시-자동-접두사-라이브러리
https://ismydream.tistory.com/98
https://joshua1988.github.io/web-development/javascript/event-propagation-delegation/