프로그래밍 언어/Vue
Vue 기초 - v-for, 컴포넌트, props, emit, slot
claire
2023. 4. 11. 18:08
v-for
<body>
<div id="app">
<div>{{people[0].name}} {{people[0].age}}</div>
<div>{{people[1].name}} {{people[1].age}}</div>
<div>{{people[2].name}} {{people[2].age}}</div>
<div>{{people[3].name}} {{people[3].age}}</div>
<hr />
<!-- 위와 같은 코드를 아래와 같이 반복문으로 작성할 수 있다. -->
<div v-for="person in people">{{person.name}} {{person.age}}</div>
<!-- of를 써도 된다. -->
<div v-for="person of people">{{person.name}} {{person.age}}</div>
<!-- 아래와 같이 index를 쓸 수 있다. -->
<!-- for 문은 고유한 key를 넣어준다. key는 값의 조합으로 넣어줘도 됨. 주로 unique한 id값을 설정.
index값은 키로 사용하면 안된다.
-->
<div v-for="(person,index) in people" :key="person.name+'-'+person.age">
{{person.name}} {{person.age}} {{index}}
</div>
</div>
<script>
new Vue({
el: "#app",
data: {
people: [
{ name: "a", age: 10 },
{ name: "b", age: 21 },
{ name: "c", age: 22 },
{ name: "d", age: 27 },
],
},
methods: {},
});
</script>
</body>
v-for를 사용해서 객체의 속성을 반복할 수도 있다.
<ul id="v-for-object" class="demo">
<li v-for="value in object">
{{ value }}
</li>
<div v-for="(value, name, index) in object">
{{ index }}. {{ name }}: {{ value }}
</div>
</ul>
new Vue({
el: '#v-for-object',
data: {
object: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
})
결과
여러개의 vue 인스턴스 사용하기
<body>
<div id="app">
{{name}}
<button @click="changeText">Click</button>
</div>
<div id="app-1">{{name}}<button @click="changeText">Click</button></div>
<script>
const app = new Vue({
el: "#app",
data: {
name: "승연",
},
methods: {
changeText() {
// this.name = "승연 업데이트";
app1.name = "헬로헬로";
},
},
});
// vue인스턴스를 변수에 담고 해당 변수를 통해 다른 인스턴스의 값에 접근한다.
const app1 = new Vue({
el: "#app-1",
data: {
name: "승얌",
},
methods: {
changeText() {
this.name = "승얌 업데이트";
},
},
});
</script>
</body>
컴포넌트 사용하기
전역 등록
Vue.component('my-component', {
// 옵션
})
컴포넌트에서 data는 함수여야 한다.
<body>
<div id="app">
<seung-button></seung-button>
</div>
<script>
// 한 컴포넌트 내에서 다른 컴포넌트를 쓸 수도 있음
Vue.component("hello-world", {
template: "<div>hello world</div>",
});
Vue.component("seung-button", {
template: `
<div>
<div>{{name}}</div>
<hello-world></hello-world>
<button @click="changeText">Click</button>
</div>
`,
//data는 함수로 사용해야 한다. 만약 객체 형태면 한 곳에서 변경되면 다른 곳에도 영향을 줌
// data: {
// name: "승연",
// },
data() {
return {
name: "seungYeon",
};
},
methods: {
changeText() {
this.name = "승연 업데이트";
},
},
});
new Vue({
el: "#app",
});
</script>
</body>
지역 등록
<body>
<div id="app">
<seung-button></seung-button>
</div>
<div id="app1">
<seung-button></seung-button>
</div>
<script>
const HelloWold = {
template: "<div>Hello World</div>",
};
const seungButton = {
components: {
"hello-world": HelloWold,
},
template: `<div>{{name}}
<hello-world></hello-world>
<button @click='changeText'>Click</button></div>`,
data() {
return {
name: "seungYeon",
};
},
methods: {
changeText() {
this.name = "seung updated";
},
},
};
const app = new Vue({
el: "#app",
components: {
"seung-button": seungButton,
},
});
// 지역 등록은 인스턴스마다 component 속성에 넣어줘야 한다. app1에선 seung-button 사용 불가.
const app1 = new Vue({
el: "#app1",
});
</script>
</body>
vue 프로젝트 시작하기
npm install -g @vue/cli
vue create 프로젝트명
vue/cli를 설치하지 않아도
npx @vue/cli create 프로젝트명
으로 프로젝트 시작이 가능하다.
npm run serve 로 실행.
vue router
<template>
<div id="app">
<nav>
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</nav>
<!-- router-view 부분이 link에 따라 바뀌는 것이다. -->
<router-view />
</div>
</template>
싱글 파일 컴포넌트
- componets/SeungYeon.vue
<template>
<div>
<p>{{ name }}</p>
<button @click="updateName">Change Name</button>
</div>
</template>
<script>
export default {
data() {
return {
name: "seung yeon",
};
},
methods: {
updateName() {
this.name = "승연이올시다. ";
},
},
};
</script>
<style scoped></style>
- views/Home.vue
<template>
<div>
<h1>This is home page</h1>
<SeungYeon />
</div>
</template>
<script>
import SeungYeon from "@/components/SeungYeon.vue";
export default {
components: {
SeungYeon,
},
data() {
return {
name: "승연",
};
},
};
</script>
<!-- scoped를 넣어줘야 이 파일에만 적용됨-->
<style scoped>
h1 {
color: red;
}
</style>
props
자식 컴포넌트에 데이터 보내기
- componets/SeungYeon.vue
<template>
<div>
<h1>{{ title }}</h1>
<h2>{{ names }}</h2>
<p>{{ name }}</p>
<button @click="updateName">Change Name</button>
</div>
</template>
<script>
export default {
// props 작성 시 type과 required를 설정해준다.
// props는 methods에서 바꾸면 안된다.자식에서는 직접적으로 props를 바꾸지 않고 부모에서만 변경한다.
props: {
title: {
type: String,
required: false,
default: "기본 타이틀",
},
names: {
type: String,
default: "기본 타이틀",
},
},
data() {
return {
name: "seung yeon",
};
},
methods: {
updateName() {
this.name = "승연이올시다. ";
},
},
};
</script>
<style scoped></style>
- views/Home.vue
<template>
<div>
<h1>This is home page</h1>
<SeungYeon title="헬로우!" names="이건 이름이야~" />
</div>
</template>
<script>
import SeungYeon from "@/components/SeungYeon.vue";
export default {
components: {
SeungYeon,
},
data() {
return {
name: "승연",
};
},
};
</script>
<!-- scoped를 넣어줘야 이 파일에만 적용됨-->
<style scoped>
h1 {
color: red;
}
</style>
emit
- components/inputField.vue
<template>
<div>
<label for="">Name</label>
<input
type="text"
:value="name"
style="padding: 30px; border: 2px solid green"
@input="updateName"
/>
</div>
</template>
<script>
export default {
props: {
name: {
type: String,
required: true,
},
},
methods: {
updateName(e) {
console.log(e.target.value);
this.$emit("update-name", e.target.value);
},
},
};
</script>
- views/HomeView.vue
<template>
<div>
<h1>This is home page</h1>
<form action="">
<InputField :name="name" @update-name="updateName" />
<br />
<button>Submitt</button>
</form>
{{ name }}
</div>
</template>
<script>
import InputField from "@/components/InputField.vue";
export default {
components: {
InputField,
},
data() {
return {
name: "",
};
},
methods: {
updateName(name) {
this.name = name;
},
},
};
</script>
<!-- scoped를 넣어줘야 이 파일에만 적용됨-->
<style scoped>
h1 {
color: red;
}
</style>
v-model로 다시
- inputField.vue
<template>
<div>
<label for="">Name</label>
<input
type="text"
:value="value"
style="padding: 30px; border: 2px solid green"
@input="$emit('input', $event.target.value)"
/>
</div>
</template>
<script>
export default {
props: {
value: {
type: String,
required: true,
},
},
methods: {
updateName(e) {
console.log(e.target.value);
this.$emit("update-name", e.target.value);
},
},
};
</script>
- Home.vue
<template>
<div>
<h1>This is home page</h1>
<form action="">
<InputField v-model="name" />
<br />
<button>Submitt</button>
</form>
{{ name }}
</div>
</template>
<script>
import InputField from "@/components/InputField.vue";
export default {
components: {
InputField,
},
data() {
return {
name: "",
};
},
methods: {
updateName(name) {
this.name = name;
},
},
};
</script>
<!-- scoped를 넣어줘야 이 파일에만 적용됨-->
<style scoped>
h1 {
color: red;
}
</style>
Slot
- about.vue
<template>
<div class="about">
<h1>This is an about page</h1>
<!-- slot이 있는 있는 컴포넌트의 태그 안에 작성 -->
<SeungYeonVue :title="title">
<!-- name이 header인 slot에 들어간다. -->
<!-- v-slot은 #으로 줄여쓸 수 있다. -->
<template v-slot:header="props">
<p>header11{{ props.seung }}</p>
</template>
<!-- v-slot:default는 name에 아무것도 쓰지 않은 slot에 들어간다. -->
<template #default="{ seung }"> hello22{{ seung }} </template>
</SeungYeonVue>
</div>
</template>
<script>
import SeungYeonVue from "../components/SeungYeon.vue";
export default {
components: {
SeungYeonVue,
},
data() {
return {
title: "하이염",
};
},
};
</script>
- SeungYeon.vue
<template>
<div>
<p>header</p>
<!-- 원하는 데이터를 변수에 넣어주면 된다. -->
<slot name="header" :seung="seung"></slot>
<p>body</p>
<slot :seung="seung"></slot>
<p>footer</p>
</div>
</template>
<script>
export default {
data() {
return {
seung: "coder",
};
},
};
</script>