2024. 12. 24. 19:58ㆍ개발 회고/TIL
😊오늘 배운 내용
웹개발 종합반 강의 3주차 ~ 4주차
전체적으로 jquery, fetch, firebase firestroe 연동하기 를 배웠다.
[album 코드]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
crossorigin="anonymous"></script>
<title>나만의 추억앨범</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Black+Han+Sans&display=swap');
* {
font-family: "Black Han Sans", sans-serif;
font-weight: 400;
font-style: normal;
}
.mytitle {
color: white;
height: 300px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-image: url('https://images.unsplash.com/photo-1511992243105-2992b3fd0410?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1470&q=80');
background-position: center;
background-size: cover;
}
.mytitle>button {
width: 150px;
height: 50px;
background-color: transparent;
border: 1px solid white;
border-radius: 10px;
color: white;
margin-top: 20px;
}
.mycards {
width: 1200px;
margin: 30px auto 30px auto;
}
.mypostingbox {
width: 500px;
margin: 30px auto 30px auto;
padding: 20px;
box-shadow: 0px 0px 3px 0px gray;
border-radius: 5px;
}
.mybtn {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
.mybtn>button {
margin-right: 5px;
}
</style>
<script type="module">
// Firebase SDK 라이브러리 가져오기
import { initializeApp } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-app.js";
import { getFirestore } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-firestore.js";
import { collection, addDoc } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-firestore.js";
import { getDocs } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-firestore.js";
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
const firebaseConfig = {
};
// Firebase 인스턴스 초기화
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
$("#postingbtn").click(async function () {
let image = $('#image').val();
let title = $('#title').val();
let content = $('#content').val();
let date = $('#date').val();
let doc = {
'image': image,
'title': title,
'content': content,
'date': date
};
await addDoc(collection(db, "albums"), doc);
alert('기록 완료!');
window.location.reload();
})
$("#savebtn").click(async function () {
$('#postingbox').toggle();
})
let url = "http://spartacodingclub.shop/sparta_api/seoulair";
fetch(url).then(res => res.json()).then(data => {
let mise = data['RealtimeCityAir']['row'][0]['IDEX_NM'];
$('#msg').text(mise);
})
let docs = await getDocs(collection(db, "albums"));
docs.forEach((doc) => {
let row = doc.data();
console.log(row);
let image = row['image'];
let title = row['title'];
let content = row['content'];
let date = row['date'];
let temp_html = `
<div class="col">
<div class="card h-100">
<img src="${image}"
class="card-img-top" alt="...">
<div class="card-body">
<h5 class="card-title">${title}</h5>
<p class="card-text">${content}</p>
</div>
<div class="card-footer">
<small class="text-muted">${date}</small>
</div>
</div>
</div>`;
$('#card').append(temp_html);
});
</script>
</head>
<body>
<div class="mytitle">
<h1>나만의 추억앨범</h1>
<p>현재 서울의 미세먼지 : <span id="msg">좋음</span></p>
<button id="savebtn">추억 저장하기</button>
</div>
<div class="mypostingbox" id="postingbox">
<div class="form-floating mb-3">
<input type="email" class="form-control" id="image" placeholder="앨범 이미지">
<label for="floatingInput">앨범 이미지</label>
</div>
<div class="form-floating mb-3">
<input type="email" class="form-control" id="title" placeholder="앨범 제목">
<label for="floatingInput">앨범 제목</label>
</div>
<div class="form-floating mb-3">
<input type="email" class="form-control" id="content" placeholder="앨범 내용">
<label for="floatingInput">앨범 내용</label>
</div>
<div class="form-floating mb-3">
<input type="email" class="form-control" id="date" placeholder="앨범 날짜">
<label for="floatingInput">앨범 날짜</label>
</div>
<div class="mybtn">
<button id="postingbtn" type="button" class="btn btn-dark">기록하기</button>
<button type="button" class="btn btn-outline-dark">닫기</button>
</div>
</div>
<div class="mycards">
<div id="card" class="row row-cols-1 row-cols-md-4 g-4">
<div class="col">
<div class="card h-100">
<img src="https://images.unsplash.com/photo-1446768500601-ac47e5ec3719?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1446&q=80"
class="card-img-top" alt="...">
<div class="card-body">
<h5 class="card-title">앨범 제목</h5>
<p class="card-text">앨범 내용</p>
</div>
<div class="card-footer">
<small class="text-muted">앨범 날짜</small>
</div>
</div>
</div>
<div class="col">
<div class="card h-100">
<img src="https://images.unsplash.com/photo-1446768500601-ac47e5ec3719?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1446&q=80"
class="card-img-top" alt="...">
<div class="card-body">
<h5 class="card-title">앨범 제목</h5>
<p class="card-text">앨범 내용</p>
</div>
<div class="card-footer">
<small class="text-muted">앨범 날짜</small>
</div>
</div>
</div>
<div class="col">
<div class="card h-100">
<img src="https://images.unsplash.com/photo-1446768500601-ac47e5ec3719?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1446&q=80"
class="card-img-top" alt="...">
<div class="card-body">
<h5 class="card-title">앨범 제목</h5>
<p class="card-text">앨범 내용</p>
</div>
<div class="card-footer">
<small class="text-muted">앨범 날짜</small>
</div>
</div>
</div>
<div class="col">
<div class="card h-100">
<img src="https://images.unsplash.com/photo-1446768500601-ac47e5ec3719?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1446&q=80"
class="card-img-top" alt="...">
<div class="card-body">
<h5 class="card-title">앨범 제목</h5>
<p class="card-text">앨범 내용</p>
</div>
<div class="card-footer">
<small class="text-muted">앨범 날짜</small>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
[jquery]
컴포넌트를 사라졌다가 나타나게 할 수있는 .toggle()과 태그의 텍스트를 바꿀 수 있는 .text() 함수를 배웠다.
[fetch]
let url = "http://spartacodingclub.shop/sparta_api/seoulair";
fetch(url).then(res => res.json()).then(data => {
let mise = data['RealtimeCityAir']['row'][0]['IDEX_NM'];
$('#msg').text(mise);
})
fetch의 기본 구조로 url을 불러온다음 response로 받아온 데이터를 json으로 받아서 데이터의 키값과 인덱스로 접근해서 사용한다.
[새로고침]
사진 정보를 입력한다음 기록하기를 누르면 내가 입력한 데이터를 가지고 카드를 만들어서 생성하고 내가 입력한 정보는 사라지게 만들고 싶다. 그럴때는 새로고침을 해주면 된다.
alert('기록 완료!');
window.location.reload();
[firebase 연동]
script 태그를 다음과 같이 수정해준다. 해당 코드의 의미는 페이지를 다 로드 한 후 스크립트 코드를 실행하겠다는 의미다.
<script type="module">
다음과 같이 firbase를 연동해준다.
// Firebase SDK 라이브러리 가져오기
import { initializeApp } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-app.js";
import { getFirestore } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-firestore.js";
import { collection, addDoc } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-firestore.js";
import { getDocs } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-firestore.js";
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
const firebaseConfig = {
//본인 설정에 맞게 입력
//프로젝트 설정 -> 내 앱 -> 구성
};
// Firebase 인스턴스 초기화
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
[.click()]
script 태그에 type="module"설정을 해주면 onclick이 동작하지 않게 된다. 그래서 자바스크립트로 click을 직접 구현해주어야 한다.
$("#postingbtn").click(async function () {
let image = $('#image').val();
let title = $('#title').val();
let content = $('#content').val();
let date = $('#date').val();
let doc = {
'image': image,
'title': title,
'content': content,
'date': date
};
await addDoc(collection(db, "albums"), doc);
alert('기록 완료!');
window.location.reload();
})
위와 같이 특정 태그를 id로 지정하고 해당 태그를 클릭 했을 시 ~와 같이 동작한다고 구현한다.
[addDoc]
let image = $('#image').val();
let title = $('#title').val();
let content = $('#content').val();
let date = $('#date').val();
let doc = {
'image': image,
'title': title,
'content': content,
'date': date
};
await addDoc(collection(db, "albums"), doc);
input 태그로 입력받은 값들을 .val()로 얻어온다. 딕셔너리로 데이터 구조를 정의한다. addDoc 함수를 통해서 firbase 데이터베이스에 albums라고 저장한 데이터베이스에 저장한다.
[async, await]
이 코드를 기반으로 async, await을 설명하자면,
$("#postingbtn").click(async function () {
let image = $('#image').val();
let title = $('#title').val();
let content = $('#content').val();
let date = $('#date').val();
let doc = {
'image': image,
'title': title,
'content': content,
'date': date
};
await addDoc(collection(db, "albums"), doc);
alert('기록 완료!');
window.location.reload();
})
async는 이 함수는 비동기 작업이 포함되어 있다고 선언하는 뜻이다. 원래는 async 함수는 Promise를 반환한다. 그리고 await는 async 함수 내부에서만 사용할 수 있으며, Promise가 해결될 때까지 기다린다.
async function fetchData() {
const response = await fetch("https://api.example.com/data");
const data = await response.json();
console.log(data);
}
fetchData();
즉 fetch를 하면서 비동기 작업이 시작되고 fetch 작업이 끝날때까지 코드를 실행중지하고 기다린다. 그리고 또 response를 받을 때까지 기다린 후, 다음 코드가 실행된다. 쉬운말로 하면 await 다음 코드들에게 이 코드 먼저 실행 후 너희들이 실행되야하니 기다리라는 의미이다.
await을 사용하지 않는다면
addDoc(collection(db, "albums"), doc); // 저장 시작
alert('기록 완료!'); // 저장이 완료되기 전에 실행될 수 있음
window.location.reload(); // 페이지가 새로고침되어 데이터가 누락될 수 있음
데이터베이스로 값을 넘기기 전에 alert메세지를 띄울 수도 있고 그 전에 페이지가 새로고침되어 내가 데이터베이스로 넘긴 값이 반영이 되지 않고 페이지가 새로고침될 수 있다.
[getDocs]
let docs = await getDocs(collection(db, "albums"));
docs.forEach((doc) => {
let row = doc.data();
console.log(row);
let image = row['image'];
let title = row['title'];
let content = row['content'];
let date = row['date'];
let temp_html = `
<div class="col">
<div class="card h-100">
<img src="${image}"
class="card-img-top" alt="...">
<div class="card-body">
<h5 class="card-title">${title}</h5>
<p class="card-text">${content}</p>
</div>
<div class="card-footer">
<small class="text-muted">${date}</small>
</div>
</div>
</div>`;
$('#card').append(temp_html);
});
addDoc를 이용해 값을 데이터베이스로 넘겼다면 getDocs를 이용해 데이터베이스에 값을 가져온다. albums 데이터베이스에서 값을 가져오기까지 기다린 후 foreach문을 통해 값을 담은 row변수를 키값으로 접근하여 각각의 변수에 저장한다. 그리고 만들어서 붙일 카드 html 코드를 ``에 담고 데이터베이스에서 가져온 값으로 바뀌어야할 부분은 ${}로 감싸준다. 그리고 해당 카드들이 들어갈 div태그의 id값을 지정하고 .append() 해준다.
[화살표함수]
docs.forEach((doc) => {
let row = doc.data();
console.log(row);
...
자바스크립트에서 화살표함수를 볼 수 있다. 구조는 함수이름( (매개변수) => {함수내용}); 과 같다.
[어떤 문제가 있었는지]
CORS에러 :
fetch(url).then(res => res.json()).then(data => {
fetch를 할 때 다음과 같이 쓰는데 url을 써야할 부분을 'url'로 하니 CORS에러가 났었다. 단순한 오타 문제였지만 해결하다가 구글링을 보니 동일한 출처에서 fetch해오지 않을 때 발생하는 것 같다. 잘은 모르지만 나중에 볼 수도 있을 것 같은 에러 같았다...
html 줄바꿈:
3주차 강의의 숙제를 하다가
<p class="col-md-8 fs-4">본인만의 맛집을 소개하는 사이트입니다.<br>맛집을 소개해주세요!</p>
두 문장을 줄바꿈해야하는 요구사항이 있었다. 처음엔 어떻게 하는지 몰라 p태그 안에서 엔터를 쳤었다.
[내가 시도해본 것들]
CORS에러는 튜터님의 도움을 받았다. 줄바꿈 문제는 p태그 안에서 엔터도 쳐보고 p태그를 2개를 만들기도 해보았다. 그런데 줄 사이의 간격이 너무 멀어서 이게 정답이 아닌 것 같았다.
[어떻게 해결했는지]
구글링을 통해서 <br>태그의 존재를 알았다. <br>태그는 닫음태그같은 것 없이 그냥 줄바꿈 하고 싶은 문장과 문장사이에 넣어주면 된다.
[무엇을 새롭게 알았는지]
오늘은 jquery, fetch, firebase연동, async, await에 대해서 알게되었다. <br>태그도 알게 되었다. 이제 앞으로 개인 홈페이지를 내 스스로 만들어보면서 배운 것들을 익혀야겠다.😊
'개발 회고 > TIL' 카테고리의 다른 글
[12/31] TIL - Java 버퍼비우기, 동적배열 , 참조형 변수, 래퍼클래스 & Git branch 협업 (1) | 2024.12.31 |
---|---|
[12/30] TIL - 프로젝트 발표회에서 얻은 인사이트와 앞으로의 다짐 (1) | 2024.12.30 |
[12/27] TIL - 팀 프로젝트 최종 마무리와 Git merge, HTML 연동 방법 학습 (1) | 2024.12.27 |
[12/26] TIL (2) | 2024.12.26 |
[12/23] TIL (1) | 2024.12.23 |