본문 바로가기

데일리 공부 기록

hands on vue3 - 재사용성이 높은 button component 만들어보기

728x90

[목표]

1. 버튼을 만들 때마다 계속 만들지 않고 필요한 내용들만 수정해서 사용하도록 하는 component를 생성한다. 

 

제공된 소스만을 가지고서

다음과 같이 구현해보기

 

 

[Button을 위한 CSS]

button {
  padding: 0.75rem 1.5rem;
  font-family: inherit;
  background-color: #3a0061;
  border: 1px solid #3a0061;
  color: white;
  cursor: pointer;
}

button:hover,
button:active {
  background-color: #270041;
  border-color: #270041;
}

.flat {
  background-color: transparent;
  color: #3a0061;
  border: none;
}

.flat:hover,
.flat:active {
  background-color: #edd2ff;
}

[App.vue]

<template>
  <the-header/>
  <div>
    <ul>
      <stored-resource 
        :resources="resources"
        @rmvRsc="rmvRsc"
        >
      </stored-resource>
    </ul>
  </div>
</template>

<script>
import LearningResource from './components/learning-resource/LearningResource.vue'
import StoredResource from './components/learning-resource/StoredResource.vue'
import TheHeader from './components/layout/TheHeader.vue'

export default {
  components: {
    LearningResource,
    StoredResource,
    TheHeader,
  },
  methods:{
    rmvRsc(id){
      console.log("From App.vue rmvRec is Running...");
      console.log(`emitVal: ${id}`);
      this.resources = this.resources.filter((element, index, array) => {
        return element.id != id;
      });
      console.log(JSON.stringify(this.resources));
    }
  },
  data(){
    return{
      resources:[
        {
          id: '1',
          title: 'Google',
          description: 'Learning something by Google!',
          link: 'https://google.com'
        },
        {
          id: '2',
          title: 'Naver',
          description: 'Have you ever had experience with Naver?',
          link: 'https://www.naver.com'
        },
        {
          id: '3',
          title: 'Daum',
          description: 'I am from Hell.',
          link: 'https://www.daum.net'
        },
      ]
    }
  }
}
</script>

<style>
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');

* {
  box-sizing: border-box;
}

html {
  font-family: 'Roboto', sans-serif;
}

body {
  margin: 0;
}
</style>

[TheHeader.vue]

<template>
	<header>
		<h1>Resources</h1> 
	</header>
</template>

<script>
export default {

}
</script>

<style scoped>
header{
	width: 100%;
	height: 5rem;

	justify-content: center;
	display:flex;

	background-color:#640032;
	
}
header h1{
	color: white;
}
</style>

[LearningResource.vue]

<template>
	<base-card>
		<li>
			<div>
				<header>
					<h2>{{res.title}}</h2>
					<p>{{res.description}}</p>
					<button @click="rmvRsc">Delete</button>
				</header>
			</div>
			<a :href="link">View Resource</a>
		</li>
	</base-card>
</template>

<script>
import BaseCard from '../UI/BaseCard.vue';

export default {
  components: { BaseCard },
	props: ['res'],
	methods:{
		rmvRsc(){
			console.log("rmvRec is Running...");
			this.$emit('rmvRsc', this.res.id);
		}
	}
}
</script>

<style scoped>
li {
  margin: auto;
  max-width: 40rem;
}

header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

h3 {
  font-size: 1.25rem;
  margin: 0.5rem 0;
}

p {
  margin: 0.5rem 0;
}

a {
  text-decoration: none;
  color: #ce5c00;
}

a:hover,
a:active {
  color: #c89300;
}
button{
	background-color:#640032;
	color:white;
	border-radius: 12px;
	box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.26);
}
</style>

[StoredResource.vue]

<template>
		<learning-resource v-for="res in resources" 
				:key="res.id"
				:res="res"
				@rmvRsc="rmvRsc"
		>
		</learning-resource>
</template>

<script>
import LearningResource from './LearningResource.vue'

export default {
	props: ['resources'],
	emits: ['rmvRsc'],
	components:{
		LearningResource,
	},
	methods:{
		rmvRsc(val){
			this.$emit('rmvRsc', val);
		}
	}
}
</script>

<style scoped>
ul {
  list-style: none;
  margin: 0;
  padding: 0;
  margin: auto;
  max-width: 40rem;
}

</style>

[BaseCard.vue]

<template>
	<div>
		<slot></slot>
	</div>
</template>

<script>
export default {

}
</script>

<style scoped>
div{
	max-width:40rem;
	margin:2rem auto;
	padding:26px;
	border-radius: 12px;
	box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.26);
}
</style>

[main.js]

import {createApp} from 'vue';
import App from './App.vue';

const app = createApp(App);
app.mount("#app");