공부방
Vue Axios 본문
AJAX
JavaScript는 Single thread가 하나이다.
- 비동기식 JavaScript와 XML
- 서버와 통신을 하기 위해서 XMLHttpRequest객체(옛날 방식)를 활용
- JSON, XML, HTML 그리고 일반 텍스트 형식 등을 포함한 다양한 포맷을 주고 받을 수 있음
- 페이지 전체를 '새로고침'하지 않고서도 수행되는 "비동기성"(일 부분만 업데이트 가능)
콜백
- 함수를 매개변수로 전달하여 나중에 실행하도록 하는 것
- 콜백이 중첩되면, 콜백 헬이 되어 해석하고 유지보수하기 힘든 코드가 될 우려(스파게트 코드)
Promise Object
- 비동기 작업을 마치 동기 작업처럼 값을 반환해서 사용 형태
- 미래의 완료 또는 실패와 그 결과 값을 나타냄
- 미래의 어떤 상황에 대한 약속
- new Promise(function(resolve, reject){})
- resolve(성공 시)
- reject(실패 시)
Promies Methods
- .then(callback)
- promise 객체를 리턴하고 두 개의 콜백 함수를 인수로 받는다.(이행했을 때, 거부했을 때)
- 콜백 함수는 이전 작업의 성공 결과를 인자로 전달받음
- .catch(callback)
- .then이 하나라도 실패하면(거부되면) 동작 (예외 처리 구문 유사)
- 이전 작업의 실패로 인해 생성된 error 객체는 catch 블록 안에서 사용 가능
- .finally(callback)
- Promise 객체 반환
- 결과 상관없이 무조건 실행
- 체이닝 가능
Axios
- 브라우저와 node.js에서 사용할 수 있는 Promise 기반 HTTP 클라이언트 라이브러리
- Vue에서 권고하는 HTTP 통신 라이브러리
Axios 설치
- CDN : <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
- NPM 방식
npm instaLL axios - CLI 방식
npm i axios
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<h1>Dog API</h1>
<button id="btn">불러와</button>
<img src="" alt="" id="dog-img" />
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<!-- cdn 방식으로 axios삽입 -->
<script>
const URL = "https://dog.ceo/api/breeds/image/random";
랜덤으로 강아지 사진을 가져오는 사이트
// 기본 방식
// function getDog() {
// const xhr = new XMLHttpRequest();
// xhr.onreadystatechange = function() {
// onreadystatechange : 콜백함수 지정
// if(xhr.readyState == xhr.DONE){
// if(xhr.status == 200){
// // console.log(JSON.parse(xhr.response).message)
// // console.log(JSON.parse(xhr.response)['message'])
// const imgSrc = JSON.parse(xhr.response)['message']
// const imgTag = document.querySelector("#dog-img")
// imgTag.src = imgSrc;
// // imgTag.setAttribute("src", imgSrc)
// }
// }
// }
// xhr.open("GET", URL)
// xhr.send();
// }
// axios방식
function getDog() {
axios.get(URL).then((response) => {
const imgSrc = response.data.message;
document.querySelector("#dog-img").setAttribute("src", imgSrc);
});
}
const btn = document.querySelector("#btn");
btn.addEventListener("click", getDog);
</script>
</body>
</html>

불러와를 누르면

강아지 사진들이 랜덤으로 나오고 불러와를 누를 때마다 다른 강아지 사진들이 나온다.
유투브 검색하여 썸네일 받아오기
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<title>Youtube 검색</title>
</head>
<body>
<h1>Youtube 검색</h1>
<input type="text" id="search" placeholder="검색어를 입력해주세요." />
<button id="search-btn">검색</button>
<hr />
<h2>검색 결과</h2>
<ul id="list"></ul>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
const URL = "https://www.googleapis.com/youtube/v3/search";
const API_KEY = "AIzaSyDUyMjPPHmd5LrlnchjptolFtKd7pHCZiE";
const btn = document.querySelector("#search-btn");
btn.addEventListener("click", () => {
const value = document.querySelector("#search").value;
axios({
url: URL,
method: "GET",
params: {
key: API_KEY,
part: "snippet",
q: value,
type: "video",
maxResults: 20,
},
})
.then((res) => {
return res.data.items;
})
.then((res) => {
const ulTag = document.querySelector("#list");
for (let i = 0; i < res.length; i++) {
let liTag = document.createElement("li");
let imgTag = document.createElement("img");
imgTag.src = res[i].snippet.thumbnails.default.url;
liTag.appendChild(imgTag);
ulTag.appendChild(liTag);
}
//아래와 같이 순회할 수도 있다.
// res.forEach(element => {
// console.log(element)
// });
})
.catch((err) => {
console.log(err);
});
});
</script>
</body>
</html>

Vue-Axios
views/YoutubeView.Vue
<template>
<div>
<h2>유튜브 전용페이지</h2>
<!-- <youtube-search @search-input="search"></youtube-search>
<youtube-search-result
:videos="videos"
></youtube-search-result> -->
</div>
</template>
<script>
export default {
name: "YoutubeView",
components: {
// YoutubeSearch,
// YoutubeSearchResult,
},
data() {
return {
videos: [],
};
},
};
</script>
<style scoped></style>
=================================================================
router/index.js
import Vue from "vue";
import VueRouter from "vue-router";
import HomeView from "../views/HomeView.vue";
import YoutubeView from "../views/YoutubeView.vue";
Vue.use(VueRouter);
const routes = [
{
path: "/",
name: "home",
component: HomeView,
},
{
path: "/youtube",
name: "youtube",
component: YoutubeView,
},
];
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes,
});
export default router;
=================================================================
App.vue
<template>
<div id="app">
<nav>
<router-link to="/">Home</router-link> |
<router-link to="/youtube">Youtube</router-link>
</nav>
<!-- <h2>이거 무슨색?</h2> -->
<router-view />
</div>
</template>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
nav {
padding: 30px;
}
nav a {
font-weight: bold;
color: #2c3e50;
}
nav a.router-link-exact-active {
color: #42b983;
}
</style>


유부브 전용페이지 색 변경하기
views/YoutubeView.Vue
<template>
<div>
<h2>유튜브 전용페이지</h2>
<!-- <youtube-search @search-input="search"></youtube-search>
<youtube-search-result
:videos="videos"
></youtube-search-result> -->
</div>
</template>
<script>
export default {
name: "YoutubeView",
components: {
// YoutubeSearch,
// YoutubeSearchResult,
},
data() {
return {
videos: [],
};
},
};
</script>
<style>
h2 {
color: red;
}
</style>

같은 페이지이지만 style속성을 주지 않았을 때 결과값은?
App.vue
<template>
<div id="app">
<nav>
<router-link to="/">Home</router-link> |
<router-link to="/youtube">Youtube</router-link>
</nav>
<h2>이거 무슨색?</h2>
<router-view />
</div>
</template>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
nav {
padding: 30px;
}
nav a {
font-weight: bold;
color: #2c3e50;
}
nav a.router-link-exact-active {
color: #42b983;
}
</style>

한 개로 다 같이 보기 때문에 style에 빨간색으로 색을 바꿔도 다른 곳에서 빨간색으로 바뀐다.
한 개만 style속성을 주기 위해
views/YoutubeView.Vue
<style scoped>
h2 {
color: red;
}
</style>
scoped를 넣어주면 그 페이지에서만 적용이 된다.

밑에 검색창 만들기
components/YoutubeSearch.Vue
<template>
<div>
<h3>검색 컴포넌트</h3>
<input type="text" v-model="keyword" />
<button @click="search">검색</button>
</div>
</template>
<script>
export default {
name: "YoutubeSearch",
data() {
return {
keyword: "",
};
},
};
</script>
<style>
</style>
===============================================================
views/YoutubeView.Vue
<template>
<div>
<h2>유튜브 전용페이지</h2>
<youtube-search></youtube-search>
</div>
</template>
<script>
import YoutubeSearch from "../components/youtube/YoutubeSearch.vue";
export default {
name: "YoutubeView",
components: {
YoutubeSearch,
// YoutubeSearchResult,
},
data() {
return {
videos: [],
};
},
};
</script>
<style scoped>
h2 {
color: red;
}
</style>

Search.vue에서 데이터를 YoutubeView로 보내기
youtube/YoutubeSearch.vue
<template>
<div>
<h3>검색 컴포넌트</h3>
<input type="text" v-model="keyword" />
<button @click="search">검색</button>
</div>
</template>
<script>
export default {
name: "YoutubeSearch",
data() {
return {
keyword: "",
};
},
methods: {
search(){
this.$emit('search-input', this.keyword)
}
},
};
</script>
<style>
</style>
===============================================================
views/YoutubeView.vue
<template>
<div>
<h2>유튜브 전용페이지</h2>
<youtube-search @search-input="search"></youtube-search>
</div>
</template>
<script>
import YoutubeSearch from "../components/youtube/YoutubeSearch.vue";
export default {
name: "YoutubeView",
components: {
YoutubeSearch,
},
data() {
return {
videos: [],
};
},
methods: {
search(value) {
console.log(value);
},
},
};
</script>
<style scoped>
h2 {
color: red;
}
</style>

Youtube API키를 받아 검색을 한 동영상들의 정보들을 가져오기
.env.local
# 키를 다른 사람이 확인할 수도 있기 때문에 다른 곳에만 저장하고
# 협업한다는 거를 생각하여 이 파일은 따로 전송하지 않는다.
VUE_APP_YOUTUBE_API_KEY=AIzaSyDUyMjPPHmd5LrlnchjptolFtKd7pHCZiE
=================================================================
views/YoutubeView.Vue
<template>
<div>
<h2>유튜브 전용페이지</h2>
<youtube-search @search-input="search"></youtube-search>
</div>
</template>
<script>
import YoutubeSearch from "../components/youtube/YoutubeSearch.vue";
import axios from "axios";
export default {
name: "YoutubeView",
components: {
YoutubeSearch,
},
data() {
return {
videos: [],
};
},
methods: {
search(value) {
console.log(value);
const URL = "https://www.googleapis.com/youtube/v3/search";
const API_KEY = process.env.VUE_APP_YOUTUBE_API_KEY;
axios({
url: URL,
method: "GET",
params: {
key: API_KEY,
part: "snippet",
q: value,
type: "video",
maxResults: 10,
},
})
// 체이닝
.then((res) => {
return res.data.items;
})
.then((res) => {
console.log(res);
this.videos = res;
})
.catch((err) => console.log(err));
},
},
};
</script>
<style scoped>
h2 {
color: red;
}
</style>

들어온 데이터들을 썸네일과 제목을 밑에 나열하기
views/YoutubeView.vue
<template>
<div>
<h2>유튜브 전용페이지</h2>
<youtube-search @search-input="search"></youtube-search>
<youtube-search-result :videos="videos"></youtube-search-result>
</div>
</template>
<script>
import YoutubeSearch from "../components/youtube/YoutubeSearch.vue";
import YoutubeSearchResult from "../components/youtube/YoutubeSearchResult.vue";
import axios from "axios";
export default {
name: "YoutubeView",
components: {
YoutubeSearch,
YoutubeSearchResult,
},
data() {
return {
videos: [],
};
},
methods: {
search(value) {
console.log(value);
const URL = "https://www.googleapis.com/youtube/v3/search";
const API_KEY = process.env.VUE_APP_YOUTUBE_API_KEY;
axios({
url: URL,
method: "GET",
params: {
key: API_KEY,
part: "snippet",
q: value,
type: "video",
maxResults: 10,
},
})
// 체이닝
.then((res) => {
return res.data.items;
})
.then((res) => {
console.log(res);
this.videos = res;
})
.catch((err) => console.log(err));
},
},
};
</script>
<style scoped>
h2 {
color: red;
}
</style>
===============================================================
youtube/YoutubeSearchResult.vue
<template>
<div>
<h3>검색 결과</h3>
<ul class="youtube-list">
<li v-for="video in videos" :key="video.id.videoId">
<img :src="video.snippet.thumbnails.default.url" />
{{ video.snippet.title }}
</li>
</ul>
</div>
</template>
<script>
export default {
name: "YoutubeSearchResult",
props: {
videos: Array,
},
};
</script>
<style scoped>
.youtube-list {
text-align: left;
}
</style>

'vue.js' 카테고리의 다른 글
Vuex (0) | 2023.05.11 |
---|---|
Vue Style Guide (0) | 2023.05.10 |
Vue Router (0) | 2023.05.09 |
Vue CLI (0) | 2023.05.08 |
Vue Component (0) | 2023.05.04 |