[2023.04.17] TIL 3일차

김선민·2024년 4월 17일

[ 본캠프 3일차 기록 ]

🖥️ 오늘 공부한 내용 🖥️

팀프로젝트 진행 (Firebase)

1. 이미지 업로드 기능 구현

firebase storage로 이미지 업로드 구현

index.html

// 헤더 설정

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Firebase Image Upload</title>
  
  // Firebase의 JavaScript SDK를 불러오는 스크립트 태그
  <script src="https://www.gstatic.com/firebasejs/8.6.8/firebase-app.js"></script>
  <script src="https://www.gstatic.com/firebasejs/8.6.8/firebase-storage.js"></script>
</head>
// 이미지 업로드 요소

  <div class="imageUpload">
  	// 1번
    <input type="file" class="inp" onchange="getImageData(event)" style="display: none;"/>
    
  	// 2번 
    <button onclick="selectImage()" class="selectImage">Select Images</button>
    
  	// 3번   
    <span class="filedata"></span>
    
    // 4번
    <div class="progressBar">
      <div class="progress"></div>
    </div>
    
    // 5번
    <button onclick="uploadImage()" class="upload">Upload</button>
    
    // 6번
    <span class="loading">Loading...</span>
    
    // 7번
    <img class="img" id="uploadedImage" />
  </div>

1번

  • input에 type을 file로 지정해서 파일 업로드 필드로 지정
  • onChane 이벤트로 이미지 데이터 가져오는 함수(getImageData(event)) 호출
    // 파일 선택 시 파일 데이터를 가져오는 함수
    const getImageData = (e) => {
     // 이벤트 객체에서 선택된 파일 가져옴
     // "e.target.files"는 파일 input에서 선택된 파일들의 목록을 나타내는 객체
      file = e.target.files[0];
      
     // 파일 이름을 랜덤으로 생성하여 파일명 중복 방지
      fileName = Math.round(Math.random() * 9999) + file.name;
      
     // 파일 이름을 화면에 표시
     // 파일이 선택되었다면, 파일 정보를 보여주는 요소인 FileData를 화면에 보여줘라
      if (fileName) {
        fileData.style.display = "block";
      }
      // fileData의 내용을 새로운 파일 이름으로 설정해줘라
      fileData.innerHTML = fileName;
    };

2번

  • 이미지 선택 버튼
  • onChane 이벤트로 이미지 선택하는 함수(selectImage())를 호출
    // 이미지 선택 버튼을 클릭하면 파일 선택 input을 클릭하는 함수
    const selectImage = () => {
    
    // Js의 'click()' 메소드를 사용해서 파일 선택 input을 대신 클릭해줌
    // 기존 input 버튼 대신 직접 만든 버튼이 같은 동작을 하도록 지정하는 작업
      inp.click();
    };

3번

  • 파일 정보를 나타냄 (파일명 보여줌)

4번

  • progressBar : 업로드 진행 상황을 보여주는 진행바
  • progress : 실제 진행 상황을 나타내는 바

5번

  • 이미지 업로드 버튼
  • input 필드로 가져온 이미지 데이터를 storage로 업로드하는 함수(uploadImage())를 호출

    // 이미지를 firebase storage에 업로드하고, 그 과정에서 로딩 중임을 나타내는 함수
    const uploadImage = () => {
    
     // 로딩중임을 나타내는 요소 'loding'을 화면에 보이도록 스타일 지정 (1번의 block 부분과 유사)
      loading.style.display = "block"; // 로딩 표시
      
     // firebase storage에서 이미지를 저장할 위치를 설정
     // "storage.ref()"는 firebase 스토리지의 루트 디렉토리를 나타냄 
     // "child("myimages")"는 "myimages"라는 디렉토리(폴더)를 생성하거나 참조 (위 사진 참고)
      const storageRef = storage.ref().child("myimages");
      
     // 업로드 할 이미지 파일에 대한 참조를 설정
     // "myimages" 디렉토리 내에 "fileName"으로 가져온 파일명을 참조해 저장하기 위함 (위 사진 참고)
      const folderRef = storageRef.child(fileName);
      
      // 파일 업로드 작업을 생성
      // "put()" 메소드는 파일 업로드하는 작업을 생성
      // "file"은 업로드 할 이미지 파일을 가리킴
      // "uploadtask"는 이 작업들을 나타내는 객체
      const uploadtask = folderRef.put(file); // 파일 업로드 작업 생성
      
      
      // 업로드 상태 변경 이벤트 (progress바에 대한 부분)
      uploadtask.on(
        "state_changed",
        (snapshot) => {
          progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;   		 // 업로드 진행률 계산
          progress = Math.round(progress); // 소수점 제거
          progressbar.style.width = progress + "%"; // 프로그레스 바 업데이트
          progressbar.innerHTML = progress + "%"; // 진행률 표시
          uploadedFileName = snapshot.ref.name; // 업로드된 파일 이름 저장
        },
        (error) => {
          console.log(error); // 에러 발생 시 콘솔에 로그 출력
        },
        () => {
        
        
          // 업로드 완료 시 실행되는 콜백 함수
          storage
          	
            // firebase storage에서 업로드된 이미지의 참조를 가져옴
            // myimages : 이미지를 저장한 디렉토리
            // uploadfiles : 업로드된 이미지 파일 이름
            .ref("myimages")
            .child(uploadedFileName)
            
            // 이미지가 업로드된 후에 해당 이미지의 다운로드 URL을 가져오는 메소드
            // 업로드된 이미지를 다시 다운로드할 때 사용
            .getDownloadURL()
            
            // Promise(외부 리소스 적근하는 작업)가 성공적으로 처리되면 실행되는 함수
            // 이 함수는 이미지의 다운로드 URL을 매개변수 'url'로 받아와 처리
            .then((url) => {
            
              // 업로드된 이미지의 다운로드 URL을 로컬 스토리지에 저장
              // 이를 통해 나중에 페이지를 새로고침해도 업로드된 이미지 다시 표시 가능
              localStorage.setItem("uploadedImageUrl", url); 
              
              // 이미지 요소의 'src' 속성을 업로드된 이미지의 URL로 설정함
              // 화면에 업로드된 이미지 표시
              img.setAttribute("src", url); // 이미지 업데이트
              
              // 이미지가 성공적으로 업로드되었으므로 로딩 중임을 나타내는 요소를 화면에서 숨김
              loading.style.display = "none";
            })
            
            // 에러 발생 시 콘솔에 에러 메세지 출력
            .catch((error) => {
              console.error('Error getting download URL:', error);
            });
        }
      );
    };

6번

  • 업로드중임을 나타냄

7번

  • 업로드된 이미지를 표시하는 img 태그

8번

  • 추가 코드
  • 페이지 로드 시 local storage에서 이미지 URL을 가져와서 이미지 표시
 	// 페이지 로드될 때 발생하는 이벤트
    window.onload = function() {
    
      // localStorage에서 "uploadedImageUrl"이라는 키를 가진 데이터를 가져온다
      // 이 데이터는 이미지의 URL을 포함
      const uploadedImageUrl = localStorage.getItem("uploadedImageUrl");
      
      // 가져온 이미지 URL이 존재한다면 실행된다
      // localStorage에서 이미지 URL을 성공적으로 가져왔는지 확인
      if (uploadedImageUrl) {
      
      	// 이미지 요소의 'src' 속성을 가져온 이미지 URL로 설정힌다
        // 이미지가 화면에 표시되게 한다
        img.setAttribute("src", uploadedImageUrl);
      }
    };

전체 코드

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Firebase Image Upload</title>
  <script src="https://www.gstatic.com/firebasejs/8.6.8/firebase-app.js"></script>
  <script src="https://www.gstatic.com/firebasejs/8.6.8/firebase-storage.js"></script>
</head>
<body>
  <div class="imageUpload">
    <input type="file" class="inp" onchange="getImageData(event)" style="display: none;"/>
    <button onclick="selectImage()" class="selectImage">Select Images</button>
    <span class="filedata"></span>
    <div class="progressBar">
      <div class="progress"></div>
    </div>
    <button onclick="uploadImage()" class="upload">Upload</button>
    <span class="loading">Loading...</span>
    <img class="img" id="uploadedImage" />
  </div>
  
  <script>
    // Firebase 프로젝트 설정 (본인 firebase 앱키 가져오기)
    const firebaseConfig = {
      apiKey: "",
      authDomain: "",
      projectId: "",
      storageBucket: "",
      messagingSenderId: "",
      appId: "",
      measurementId: ""
    };

    // Firebase 앱 초기화
    const app = firebase.initializeApp(firebaseConfig);
    // Firebase 스토리지 사용
    const storage = firebase.storage();

    // 필요한 DOM 요소들을 가져오기
    const inp = document.querySelector(".inp");
    const progressbar = document.querySelector(".progress");
    const img = document.querySelector(".img");
    const fileData = document.querySelector(".filedata");
    const loading = document.querySelector(".loading");
    let file;
    let fileName;
    let progress;
    let isLoading = false;
    let uploadedFileName;
    
    const selectImage = () => {
      inp.click();
    };

    const getImageData = (e) => {
      file = e.target.files[0];
      fileName = Math.round(Math.random() * 9999) + file.name;
      if (fileName) {
        fileData.style.display = "block";
      }
      fileData.innerHTML = fileName;
    };

    const uploadImage = () => {
      loading.style.display = "block";
      const storageRef = storage.ref().child("myimages");
      const folderRef = storageRef.child(fileName);
      const uploadtask = folderRef.put(file);

      uploadtask.on(
        "state_changed",
        (snapshot) => {
          progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
          progress = Math.round(progress);
          progressbar.style.width = progress + "%";
          progressbar.innerHTML = progress + "%";
          uploadedFileName = snapshot.ref.name;
        },
        (error) => {
          console.log(error);
        },
        () => {
          storage
            .ref("myimages")
            .child(uploadedFileName)
            .getDownloadURL()
            .then((url) => {
              localStorage.setItem("uploadedImageUrl", url);
              img.setAttribute("src", url);
              loading.style.display = "none";
            })
            .catch((error) => {
              console.error('Error getting download URL:', error);
            });
        }
      );
    };

    // 페이지 로드 시 로컬 스토리지에서 이미지 URL을 가져와서 이미지 표시
    window.onload = function() {
      const uploadedImageUrl = localStorage.getItem("uploadedImageUrl");
      if (uploadedImageUrl) {
        img.setAttribute("src", uploadedImageUrl);
      }
    };
  </script>
</body>
</html>
profile
웹 프론트엔드

0개의 댓글