Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 |
Tags
- 한글 특수문자 자바스크립트
- 분산파일
- 자바스크립트 깨질 때
- LLM기반 콘텐츠 추천
- integrationtest
- tomcat튜닝
- 외부 톰캣 특수문자 깨질 때
- staem algorithm
- LLM기반CBF
- jsp 예외 permission
- dial timeout
- dialtimeout
- 스팀 게임 스코어 알고리즘
- 존폴결혼반지
- jsp permission denied
- cookie refreshToke
- 비개인화추천모델
- 존폴결혼예물
- 분산파일시스템
- jqx워터마크제거
- Akamai 연구결과
- 존폴쥬얼리
- set-cookie 안만들어짐
- 존폴반지
- steam game score
- jqxWidget워터마크
- 스프링단위테스트방법
- spring unit test
- 동시 요청 처리
- 추천시스템steam
Archives
- Today
- Total
hola 개발
[ Vue ] 영화 검색 사이트 본문
- assets
-- movie.js
let data = [
{
title: "노랑",
year: 2023,
category: "액션, 드라마마",
textRed: "color: red",
like: 0,
imgUrl: './assets/logo.png'
},
{
title: "아쿠아맨과 로스트 킹덤",
year: 2023,
category: "액션, 드라마마",
like: 0,
imgUrl: './assets/루미너스메모리0009.jpg'
},
]
export default data;
App.vue
<template>
<Navbar />
<Event :text="text" />
<Searchbar :data="data_temp" @searchMovie="searchMovie($event)"/>
<Movies :data="data_temp" @openModal="isModal=true;selectedMovie=$event" @increaseLike="increaseLike($event)"/>
<Modal :data="data" :isModal="isModal" :selectedMovie="selectedMovie" @closeModal="isModal=false"/>
</template>
<script>
import data from './assets/movie.js';
import Navbar from './components/Navbar.vue';
import Modal from './components/Modal.vue';
import Event from './components/Event.vue';
import Movies from './components/Movies.vue';
import Searchbar from './components/Searchbar.vue';
export default{
name: 'App',
data(){
return {
isModal: false,
data: data, // 원본
//원래있던 데이터 복사
data_temp: [...data], // 사본본
selectedMovie: 0,
text: "NEPLIX 경기 크러처!!",
}
},
methods: {
increaseLike(i){
this.data[i].like ++;
},
searchMovie(title){
// 영화제목이 포함된 데이터를 가져옴
this.data_temp = this.data.filter(movie => {
return movie.title.includes(title);
})
}
},
components: {
Navbar: Navbar,
Event: Event,
Modal: Modal,
Movies: Movies,
Searchbar: Searchbar,
}
}
</script>
<style>
* {
box-sizing: border-box;
margin: 0;
}
body {
max-width: 768px;
margin: 0 auto;
padding: 20px;
}
h1, h2, h3 {
margin-bottom: 1rem;
}
p {
margin-bottom: 0.5rem;
}
button {
margin-right: 10px;
margin-top: 1rem;
}
.item {
width: 100%;
border: 1px solid #ccc;
display: flex;
margin-bottom: 20px;
padding: 1rem;
}
.item figure{
width: 30%;
margin-right: 1rem;
}
.item img {
width: 100%;
}
.item .info {
width: 100%;
}
</style>
-components
-- Event.vue
<template>
<div class="event" :class="{show : isOpen}">
<p>{{text}}</p>
<button @click="isOpen=false">x</button>
</div>
</template>
<script>
export default {
name: 'EventComponent',
props: {
text: String,
},
data(){
return {
isOpen: true,
}
}
}
</script>
<style>
.event {
background-color: forestgreen;
padding: 10px 20px;
color: #fff;
text-align: center;
font-size: small;
display: flex;
justify-content: space-between;
align-items: center;
display: none;
}
.event p {
margin: 0;
}
.show {
display: flex;
}
.event button {
margin: 0;
}
</style>
-- Modal.vue
<template>
<div class="modal" v-if="isModal">
<div class="inner">
<h3>{{data[selectedMovie].title}}</h3>
<p>영화 상세정보</p>
<button @click="$emit('closeModal')">닫기</button>
</div>
</div>
</template>
<script>
export default {
name: 'ModalComponent',
props: {
data: Array,
isModal: Boolean,
selectedMovie: Number,
}
}
</script>
<style>
.modal {
background: rgba(0,0,0,0.7);
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.modal .inner {
background: #fff;
width: 80%;
padding: 20px;
border-radius: 10px;
}
</style>
-- Movies.vue
<template>
<div class="container">
<h1>영화 정보</h1>
<div v-for="(movie, i) in data" :key="i" class="item">
<figure>
<img :src="`${movie.imgUrl}`" :alt="movie.title">
</figure>
<div class="info">
<h3 class="bg-yellow" :style="textRed" >{{movie.title}}</h3>
<p>개봉: {{movie.year}}</p>
<p>장르: {{movie.category}}</p>
<button @click="$emit('increaseLike', i)">좋아요</button>
<span>{{movie.like}}</span>
<p>
<button @click="$emit('openModal', i)">상세보기</button>
</p>
</div>
</div>
</div>
</template>
<script>
export default{
name: 'MoviesComponent',
props: {
data: Array,
}
}
</script>
<style>
.container {
padding: 20px;
}
</style>
-- Navbar.vue
<template>
<nav class="navbar">
<a href="#">Home</a>
<a href="#">Movies</a>
<a href="#">About</a>
</nav>
</template>
<script>
export default {
name: 'NavbarComponent',
}
</script>
<style>
.navbar {
background: #000;
padding: 20px;
text-align: center;
}
.navbar a {
color: #fff;
text-decoration: none;
padding: 1em;
}
</style>
-- Searchbar.vue
<template>
<div class="search-box">
<input
type="search"
@change="
$emit('searchMovie', $event.target.value)
inputText=$event.target.value;
$event.target.value = ''
"
placeholder="검색어 입력"
>
<button>검색</button>
</div>
</template>
<script>
export default {
name: "SearchbarComponent",
data() {
return {
inputText: '',
}
},
props: {
data: Array,
},
watch: {
inputText(name) {
// 입력한 영화제목이 데이터에 있는지 확인
// data는 부모 -> 자식으로 props 로부 받은 data를 의미함
// this를 쓰는 이유는 props로 받은 값이라도 접근할 때는 this.propName으로 해야하기 때문
const findName = this.data.filter(movie => {
return movie.title.includes(name);
})
console.log(findName);
if(findName.length == 0){
alert("해당하는 영화는 없습니다.");
}
}
}
}
</script>
<style>
.search-box {
padding: 10px;
display: flex;
justify-content: center;
}
.search-box input {
padding: 5px 10px;
}
.search-box button {
margin: 0;
}
</style>
'프로젝트' 카테고리의 다른 글
| [ 추천 시스템 프로젝트 기록 ] LLM 기반 Contents Based Filtering (0) | 2025.09.18 |
|---|---|
| [ 추천 시스템 프로젝트 기록 ] Steam Game Score Algorithm (0) | 2025.09.17 |
| [ bible Cash ] stmp를 이용한 서버 종료 이메일 받기 (0) | 2025.02.05 |
| [ bible Cash ] 주간 읽은 양 랭킹 기능 추가 (1) | 2025.02.05 |
| [ bible Cash ] 로그인 시, 아이디 존재하지 않는 경우 처리, 추가로 읽은 말씀 기능 (1) | 2025.02.04 |