[231219] - IRISH APP 설계 및 제작(9)

IRISH·2023년 12월 19일
0

JS

목록 보기
28/80
post-thumbnail

참고 URL

설계

  1. 로그인 - 로그아웃 기능을 구현한다.
  2. 날씨 API를 활용해 도시 / 날씨 / 온도 / 날씨별 아이콘을 화면에 부른다.

결과 화면

  • 로그인 이전

  • 로그인 이후

로그인 - 로그아웃

  • 로그인이 안되어 있을 경우
    • 아이디 입력창 및 로그인 버튼 활성화
  • 로그인이 되어 있을 경우
    • 환영 문구 및 로그아웃 버튼 활성화

소스 코드

index.html

<!-- 좌측 상단 =>  로그인 / 시간 API / 날씨 API -->
<div class="leftTop">

  <!-- 로그인 폼 -->
  <form action id="login-form">
    <input
      required
      maxlength="15"
      type="text"
      placeholder="아이디를 입력하세요"
    />
    <input type="submit" value="Log In" />
  </form>

  <!-- <h1 id="greeting" class="hidden"></h1> -->

  <div id="divGreeting">
    <h1 id="greeting" class="hidden"></h1>

    <div id="divLogoutBtn">
      <form action id="logoutBtn" class="hidden">
        <input type="submit" value="Log Out" />
      </form>
    </div>
  </div>
</div>

js/greeting.js

/* 로그인 창*/
const loginForm = document.querySelector("#login-form");
const greeting = document.querySelector("#greeting");
const loginInput = document.querySelector("#login-form input");
const logoutBtn = document.querySelector('#logoutBtn');

const HIDDEN_CLASSNAME = "hidden";
const USERNAME_KEY = "username";

/* 유저명 제출 */
function onLoginSubmit(event) {
    event.preventDefault(); // 새로고침 방지
    loginForm.classList.add(HIDDEN_CLASSNAME);
    const username = loginInput.value;
    localStorage.setItem(USERNAME_KEY, username);
    paintGreetings(username);
}

/* 인삿말 출력 */
function paintGreetings(username) {
    greeting.innerText = `안녕하세요! ${username} 님!`;
    greeting.classList.remove(HIDDEN_CLASSNAME);
    logoutBtn.classList.remove(HIDDEN_CLASSNAME);
}

/*유저명 입력창 */
function usernameWrite(){
    loginForm.classList.remove(HIDDEN_CLASSNAME);
    loginForm.addEventListener("submit", onLoginSubmit);
}
  
/* 로그아웃 */
function onLogout(event) {
    event.preventDefault();
    localStorage.removeItem(USERNAME_KEY);
    greeting.classList.add(HIDDEN_CLASSNAME);
    logoutBtn.classList.add(HIDDEN_CLASSNAME);
    loginInput.value = null;
    usernameWrite();
}

const savedUsername = localStorage.getItem(USERNAME_KEY);

// 로컬 스토리지에 값 없으면, 로그인 폼 보여주기
if (savedUsername === null || savedUsername==="null") {
    usernameWrite();
} else { // 값 로컬 스토리지에 값 있으면, 로그인 폼 비활성화
    paintGreetings(savedUsername);
}

logoutBtn.addEventListener("click", onLogout);
  • 로그인을 하면
    • 아이디 입력창과 로그인 버튼이 비활성화
    • 환영 문구와 로그인 아웃 버튼이 활성화
  • 로그아웃을 하면
    • 아이디 입력창과 로그인 버튼이 활성화
    • 환영 문구와 로그인 아웃 버튼이 비활성화

날씨 API

  • OpenWeaterMap의 API를 받아와서 지역 / 날씨 / 온도 / 날씨별 아이콘을 출력한다.

소스 코드

index.html

<!-- 날씨 API -->
<div id="weather">
  <p></p>
  <p></p>
  
  <img class="weatherIcon" />
</div>

js/weater.js

/* 참고 url > https://velog.io/@yeonsubaek/JavaScript-%EB%82%A0%EC%94%A8-API-%EC%97%B0%EB%8F%99%EC%9D%B4-%EC%9D%B4%EB%A0%87%EA%B2%8C-%EC%89%BD%EB%8B%A4%EA%B3%A0-ft.-OpenWeatherMap */

const API_KEY = "c26d4c4ac4f63342e86215cd66b5ef2a";

function onGeoOk(position){
    const lat = position.coords.latitude; // 위도
    const lon = position.coords.longitude; // 경도
    //console.log("You Live In", lon, lon);
	
    /*api 받아오기*/
    const url = `https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${API_KEY}&units=metric`;
    //console.log(url);
    fetch(url).then(response => response.json()).then(data => {
        //console.log(data.name, data.weather[0].main)
        console.log(data);

        /* 지역 */
        const city = document.querySelector("#weather p:nth-child(1)");  // 지역
        if(data.name === 'Gunpo'){data.name='군포';}
        city.innerHTML = data.name;

        /* 날씨 및 온도(섭씨) */
        const weather = document.querySelector("#weather p:nth-child(2)"); // 날씨 및 온도
        let temp = Math.round(data.main.temp);
        weather.innerText = `날씨 : ${data.weather[0].main} / 온도 : ${temp}`;
        
        /* 날씨별 아이콘 */
        const weatherIconSection = document.querySelector(".weatherIcon");
        const weatherIcon = data.weather[0].icon;
        const weatherIconURL = `http://openweathermap.org/img/wn/${weatherIcon}@2x.png`;
        weatherIconSection.setAttribute('src', weatherIconURL);
    });
}

function onGeoError(){
    alert("Can't find you. No weather for you.")
}

/* getCurrentPosition 함수를 이용해 나의 현재 위치를 얻어옴
단, getCurrentPosition은 두 개의 파라미터를 보내줘야 함 => (성공시, 실패시)
성공시 쓸 함수 : onGeoOk / 실패시 쓸 함수 : onGeoError
*/
navigator.geolocation.getCurrentPosition(onGeoOk, onGeoError);

⇒ onGeoOk() 사용자 정의 함수에서 API의 URL을 담은 변수 ‘url’을 통해 가져온 데이터를 기반으로 json화 한다.

  • 이 data 변수를 통해 API로 호출된 위치의 지역 / 날씨 및 온도 / 아이콘 등을 가져올 수 있다.

전체 코드

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="css/style.css" />
    <title>Irish App</title>
  </head>
  <body id="background-image">
    <div id="container">
      <!-- 최상단 => 환영 문구 -->
      <div class="top">
        <h1>Welcome! This is Irish's Web Page.</h1>   
      </div>
  
      <!-- 좌측 상단 =>  로그인 / 시간 API / 날씨 API -->
      <div class="leftTop">

        <!-- 로그인 폼 -->
        <form action id="login-form">
          <input
            required
            maxlength="15"
            type="text"
            placeholder="아이디를 입력하세요"
          />
          <input type="submit" value="Log In" />
        </form>

        <!-- <h1 id="greeting" class="hidden"></h1> -->

        <div id="divGreeting">
          <h1 id="greeting" class="hidden"></h1>

          <div id="divLogoutBtn">
            <form action id="logoutBtn" class="hidden">
              <input type="submit" value="Log Out" />
            </form>
          </div>
        </div>
        
        <!-- <div id="divLogoutBtn">
          <form action id="logoutBtn" class="hidden">
            <input type="submit" value="Log Out" />
          </form>
        </div> -->

        <!-- 시간 API -->
        <div id="divClock">
          <h2 id="clock" style="color:orangered">00:00:00</h2>
        </div> 

        <!-- 날씨 API -->
        <div id="weather">
          <p></p>
          <p></p>
          
          <img class="weatherIcon" />
        </div> 
      </div>

      <!-- 좌측 하단 =>  자주 사용하는 웹 페이지 위젯 -->
      <div class="leftBottom">
        <div class="wrapBottom">
          <a href="https://google.com">
            <div class="logo_div logo_google"></div>
          </a>
          <a href="https://www.youtube.com/">
            <div class="logo_div logo_youtube"></div>
          </a>
          <a href="https://chat.openai.com/">
            <div class="logo_div logo_chatgpt"></div>
          </a>
          <a href="https://www.naver.com/">
            <div class="logo_div logo_naver"></div>
          </a>
        </div>
        
        <div class="wrapBottom">
          <a href="https://stackoverflow.com/">
            <div class="logo_div logo_stackoverflow"></div>
          </a>
          <a href="https://developer.mozilla.org/ko/">
            <div class="logo_div logo_mdn"></div>
          </a>
          <a href="https://www.coupang.com/">
            <div class="logo_div logo_coupang"></div>
          </a>
          <a href="https://www.musinsa.com/app/">
            <div class="logo_div logo_musinsa"></div>
          </a>

        </div>
      </div>

      <!-- 가운데 => TO DO LIST -->
      <div class="middle">
        <div>
          <h1>Middle Area</h1>  
        </div> 
        
        <div>
          <form id="todo-form">
            <input type="text" size=30 placeholder="Write a To Do and Press Enter" required />
          </form>
          
          <ul id="todo-list"></ul>
        </div>
      </div>

      <!-- 우측 => 깃허브 / VELOG / 노션 등 프로필 -->
      <div class="right">
        <h1>Right Area</h1>   
      </div>

      <!-- 최하단 => 유명 문구 -->
      <div class="bottom">
        <div id="quote">
          <span class="fontFaceText"></span> <br>
          <span class="fontFaceWriter"></span>
        </div> 
      </div>
      
      <!-- ======================================================== -->
      
      <!-- 로그인 영역 -->
      <!-- <form id="login-form">
        <input
          required
          maxlength="15"
          type="text"
          placeholder="INPUT YOUR ID"
        />
        <button class="btn-1">Button 1</button>
        <input type="submit" value="Log In" />
      </form> -->

      <!-- <h2 id="clock">00:00:00</h2>
      <h1 id="greeting" class="hidden"></h1>

      <form id="todo-form">
          <input type="text" placeholder="Write a To Do and Press Enter" required />
      </form>
      <ul id="todo-list"></ul> -->
      <!-- ======================================================== -->

    </div>

    <script src="js/greeting.js"></script>
    <script src="js/clock.js"></script>
    <script src="js/quotes.js"></script>
    <script src="js/todo.js"></script>
    <script src="js/background.js"></script>
    <script src="js/weather.js"></script>
  </body>
</html>

js/greeting.js

/* 로그인 창*/
const loginForm = document.querySelector("#login-form");
const greeting = document.querySelector("#greeting");
const loginInput = document.querySelector("#login-form input");
const logoutBtn = document.querySelector('#logoutBtn');

const HIDDEN_CLASSNAME = "hidden";
const USERNAME_KEY = "username";

/* 유저명 제출 */
function onLoginSubmit(event) {
    event.preventDefault(); // 새로고침 방지
    loginForm.classList.add(HIDDEN_CLASSNAME);
    const username = loginInput.value;
    localStorage.setItem(USERNAME_KEY, username);
    paintGreetings(username);
}

/* 인삿말 출력 */
function paintGreetings(username) {
    greeting.innerText = `안녕하세요! ${username} 님!`;
    greeting.classList.remove(HIDDEN_CLASSNAME);
    logoutBtn.classList.remove(HIDDEN_CLASSNAME);
}

/*유저명 입력창 */
function usernameWrite(){
    loginForm.classList.remove(HIDDEN_CLASSNAME);
    loginForm.addEventListener("submit", onLoginSubmit);
}
  
/* 로그아웃 */
function onLogout(event) {
    event.preventDefault();
    localStorage.removeItem(USERNAME_KEY);
    greeting.classList.add(HIDDEN_CLASSNAME);
    logoutBtn.classList.add(HIDDEN_CLASSNAME);
    loginInput.value = null;
    usernameWrite();
}

const savedUsername = localStorage.getItem(USERNAME_KEY);

// 로컬 스토리지에 값 없으면, 로그인 폼 보여주기
if (savedUsername === null || savedUsername==="null") {
    usernameWrite();
} else { // 값 로컬 스토리지에 값 있으면, 로그인 폼 비활성화
    paintGreetings(savedUsername);
}

logoutBtn.addEventListener("click", onLogout);

js/weather.js

/* 참고 url > https://velog.io/@yeonsubaek/JavaScript-%EB%82%A0%EC%94%A8-API-%EC%97%B0%EB%8F%99%EC%9D%B4-%EC%9D%B4%EB%A0%87%EA%B2%8C-%EC%89%BD%EB%8B%A4%EA%B3%A0-ft.-OpenWeatherMap */

const API_KEY = "c26d4c4ac4f63342e86215cd66b5ef2a";

function onGeoOk(position){
    const lat = position.coords.latitude; // 위도
    const lon = position.coords.longitude; // 경도
    //console.log("You Live In", lon, lon);
	
    /*api 받아오기*/
    const url = `https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${API_KEY}&units=metric`;
    //console.log(url);
    fetch(url).then(response => response.json()).then(data => {
        //console.log(data.name, data.weather[0].main)
        console.log(data);

        /* 지역 */
        const city = document.querySelector("#weather p:nth-child(1)");  // 지역
        if(data.name === 'Gunpo'){data.name='군포';}
        city.innerHTML = data.name;

        /* 날씨 및 온도(섭씨) */
        const weather = document.querySelector("#weather p:nth-child(2)"); // 날씨 및 온도
        let temp = Math.round(data.main.temp);
        weather.innerText = `날씨 : ${data.weather[0].main} / 온도 : ${temp}`;
        
        /* 날씨별 아이콘 */
        const weatherIconSection = document.querySelector(".weatherIcon");
        const weatherIcon = data.weather[0].icon;
        const weatherIconURL = `http://openweathermap.org/img/wn/${weatherIcon}@2x.png`;
        weatherIconSection.setAttribute('src', weatherIconURL);
    });
}

function onGeoError(){
    alert("Can't find you. No weather for you.")
}

/* getCurrentPosition 함수를 이용해 나의 현재 위치를 얻어옴
단, getCurrentPosition은 두 개의 파라미터를 보내줘야 함 => (성공시, 실패시)
성공시 쓸 함수 : onGeoOk / 실패시 쓸 함수 : onGeoError
*/
navigator.geolocation.getCurrentPosition(onGeoOk, onGeoError);
profile
#Software Engineer #IRISH

0개의 댓글