Almon Dev

모의해킹 공부 정리 10일차 (마이페이지) 본문

모의해킹/웹 개발

모의해킹 공부 정리 10일차 (마이페이지)

Almon 2024. 10. 26. 19:29

마이페이지 만들기

 

구상하기

처음에는 따로 마이페이지를 만들고자 했으나 프로필 페이지의 아랫부분이 많이 남아서
db를 통해 데이터를 가져온 뒤 프로필페이지의 아랫부분에 출력하기로 생각을 바꾸었습니다.

프로필 페이지


HTML 수정

 

login_successful.php

수정 전

<?php 
    $nickname = $_POST['nickname'];
?>

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Almond</title>
    <link rel="stylesheet" href="/css/login_successful.css">
    <script src="./script/logout.js" defer></script>
</head>
<body>
    <container class="profile-container">
        <div class="profile">
            <img src="/imgs/almond-profile.jpg" class="profile_img">
            <div class="profile_info">
                <h2 class="profile_name"><?php echo $nickname; ?></h2>
                <p class="profile_subs">구독자 <strong>0명</strong></p>
            </div>
        </div>
        
        <div class="profile_link">
            <a href="#" class="link_tab"><p>글쓰기</p></a>
            <a href="#" class="link_tab"><p>마이페이지</p></a>
            <?php
                printf('<button class="link_tab logout-btn" onclick=\'logout("%s")\'>로그아웃</button>', $nickname);
            ?>
        </div>
    </container>
</body>
</html>

 

수정 후

<?php 
    $nickname = $_POST['nickname'];
?>

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Almond</title>
    <link rel="stylesheet" href="/css/login_successful.css">
    <script src="./script/logout.js" defer></script>
    <script src="./script/mypage.js" defer></script>
</head>
<body>
    <container class="profile-container">
        <div class="profile">
            <img src="/imgs/almond-profile.jpg" class="profile_img">
            <div class="profile_info">
                <h2 class="profile_name"><?php echo $nickname; ?></h2>
                <p class="profile_subs">구독자 <strong>0명</strong></p>
            </div>
        </div>
        
        <div class="profile_link">
            <a href="#" class="link_tab"><p>글쓰기</p></a>
            <!-- <a href="mypage.php" class="link_tab"><p>마이페이지</p></a> -->
            <?php
                printf('<button class="link_tab mypage-btn" onclick=\'mypage("%s")\'>마이페이지</button>', $nickname);
                printf('<button class="link_tab logout-btn" onclick=\'logout("%s")\'>로그아웃</button>', $nickname);
            ?>
        </div>
        <div class="content"></div>
        <button class="mypageset-btn">수정하기</button>
    </container>
</body>
</html>

 

printf('<button class="link_tab mypage-btn" onclick=\'mypage("%s")\'>마이페이지</button>', $nickname);

a태그로 만들었던 마이페이지를 button태그로 변경하고 클릭 시 mypage(닉네임) 함수를 실행하도록 변경하였습니다.


mypage함수 생성

 

/script/mypage.js

function mypage(nick) {
  fetch('/mypage.php', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json; charset=utf-8',
    },
    body: JSON.stringify({
      nickname: nick,
    }),
  })
    .then((res) => res.json())
    .then((res) => {
      console.log(res);
      const id = res['id'];
      const email = res['email'];

      const contentTag = document.querySelector('.content');
      const btn = document.querySelector('.mypageset-btn');

      const html = `<p class="mypage id">아이디 : ${id}</p><br>
        <p class="mypage nickname">닉네임 : ${nick}</p><br>
        <p class="mypage email">이메일 : ${email}</p><br>`;

      contentTag.classList.add('on');
      contentTag.innerHTML = html;
      btn.classList.add('on');
    });
}

 

function mypage(nick) {
  fetch('/mypage.php', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json; charset=utf-8',
    },
    body: JSON.stringify({
      nickname: nick,
    }),
  })

mypage(닉네임) 함수를 실행하면 fetch를 이용해서 /mypage.php에 POST로 json으로 포장한 닉네임을 전송합니다.

fetch는 우리가 url을 이용해 웹페이지에 요청을 보내고 기다리는 동작을 대신해 주는 일종의 함수입니다.
fetch는 응답을 받으면 Promise라는 객체를 반환하는데 이 객체를 통해서
응답이 실패했는지 성공했는지를 알 수 있습니다.

 

.then((res) => res.json())

fetch에 응답이 오면 해당 응답을 json에서 자바스크립트 객체로 변환합니다.

.then은 Promise 객체가 완료됐을 경우(응답이 성공적일 경우) () 안에 코드를 실행합니다.

() => {}의 경우 화살표함수(arrow function)로 자바스크립트에서 사용되는 간단한 함수 작성 방법입니다.
(매개변수) => {실행코드}로 {}없이 코드를 작성한 경우 코드의 값이 바로 반환(return)됩니다.

json() 함수는 json을 파싱 하는 함수로 json값을 자바스크립트 객체로 변환해 줍니다.
json()의 작업이 완료되면 Promise객체를 반환합니다.

※then 이외에도 catch를 이용해서 에러 처리가 가능합니다.

 

    .then((res) => {
      console.log(res);
      const id = res['id'];
      const email = res['email'];

json으로 파싱 된 자바스크립트 객체로 id와 email의 값을 각각 대입합니다.  

json함수는 자바스크립트 객체 Object타입을 반환하지만
json이 배열로 이루어진 경우 array를 반환합니다.

 

      const contentTag = document.querySelector('.content');
      const btn = document.querySelector('.mypageset-btn');

querySelector를 이용해 클래스 이름이 content, mypageset-btn인 태그들을 변수로 지정합니다.

쿼리셀렉터(querySelector)의 경우 .은 클래스를 #은 id를 불러옵니다.

 

      const html = `<p class="mypage id">아이디 : ${id}</p><br>
        <p class="mypage nickname">닉네임 : ${nick}</p><br>
        <p class="mypage email">이메일 : ${email}</p><br>`;

html 변수에 추가할 마이페이지 내용을 html태그도 만들어줍니다.

자바스크립트에서 문자열을 만들 때 `를 이용하면 문자열 내부에서 ${}를 이용해서 변수를 사용할 수 있습니다.

 

      contentTag.innerHTML = html;
      btn.classList.add('on');

contentTag 내부에 html변수에 담긴 내용을 추가합니다.

mypageset-btn의 클래스에 on을 추가합니다.

innerHTML은 태그의 내부 html이 들어있는 속성입니다.
그렇기에 contentTag.innerHTML = "~";를 하는 경우 내부의 html이 모두 사라지고 ""안의 값으로 덮어씌워지니
유의해서 사용해야 합니다.

 

CSS 추가

 

login_successful.css

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: 'Arial', sans-serif;
}

html {
  height: 100%;
}

body {
  height: 100%;

  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;

  background-color: #f5e1c8;
}

button {
  border: 0;
  background-color: transparent;
}

.profile-container {
  padding: 2rem;
  width: 500px;
  height: 550px;

  text-align: center;

  border-radius: 8px;
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);

  background-color: #efdecd;
}

.profile {
  display: flex;
  flex-direction: row;
  justify-content: flex-start;
  align-items: center;
}

.profile_img {
  margin-right: 1rem;

  width: 130px;

  border: 2px solid #d2b48c;
  border-radius: 50%;
}

.profile_info {
  text-align: left;

  color: #6e4e37;
}

.profile_name {
  font-size: 1.5rem;
}

.profile_subs {
  padding-top: 0.3rem;
}

.profile_link {
  margin-top: 2rem;

  height: 48px;

  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;

  border: 1px solid #d2b48c;
  border-radius: 8px;
}

.profile_link .link_tab {
  font-size: 1.2rem;
  font-weight: bold;
  line-height: 1.3;
  color: #6e4e37;

  text-decoration: none;

  flex-basis: 33.33%;
  flex-grow: 1;
  text-align: center;

  transition: text-decoration 0.7s ease;
  transition: color 0.7s ease;
}

.profile_link .link_tab:hover {
  text-decoration: underline;
  text-decoration-color: #deb887;
  text-decoration-thickness: 2px;
  text-underline-offset: 4px;

  color: #deb887;
}

.profile_link .link_tab + .link_tab {
  position: relative;
}

.profile_link .link_tab + .link_tab::before {
  width: 1px;
  height: 20px;
  content: '';

  display: block;
  position: absolute;
  top: 50%;
  left: 0;
  transform: translateY(-50%);

  background-color: #d2b48c;
}

.content {
  height: 50%;
  padding-top: 1.5rem;
  padding-bottom: 1rem;

  display: flex;
  flex-direction: column;
  /* justify-content: space-between; */
  justify-content: space-around;
  align-items: flex-start;

  color: #6e4e37;
  font-weight: 600;
}

.content.on {
  border-radius: 8px;
}

.mypage {
  font-size: 1.2rem;
  font-weight: bold;
  line-height: 49.67px;

  flex-basis: 33.33%;
  flex-grow: 1;
}

.mypageset-btn {
  display: none;
  padding: 0.7rem 1rem;
  width: 100%;

  font-size: 1rem;
  font-weight: bold;
  line-height: 1.3;
  color: white;
  background-color: #d2b48c;

  line-height: 100%;

  border-radius: 8px;
  transition: background-color 0.3s ease;
  cursor: pointer;
}

.mypageset-btn.on {
  display: inline;
}

.mypageset-btn:hover {
  background-color: #deb887;
}

 

 

추가된 부분

.content {
  height: 50%;
  padding-top: 1.5rem;
  padding-bottom: 1rem;

  display: flex;
  flex-direction: column;
  /* justify-content: space-between; */
  justify-content: space-around;
  align-items: flex-start;

  color: #6e4e37;
  font-weight: 600;
}

.content.on {
  border-radius: 8px;
}

.mypage {
  font-size: 1.2rem;
  font-weight: bold;
  line-height: 49.67px;

  flex-basis: 33.33%;
  flex-grow: 1;
}

.mypageset-btn {
  display: none;
  padding: 0.7rem 1rem;
  width: 100%;

  font-size: 1rem;
  font-weight: bold;
  line-height: 1.3;
  color: white;
  background-color: #d2b48c;

  line-height: 100%;

  border-radius: 8px;
  transition: background-color 0.3s ease;
  cursor: pointer;
}

.mypageset-btn.on {
  display: inline;
}

.mypageset-btn:hover {
  background-color: #deb887;
}

 

 

지금까지 사용했던 css들을 짜깁기 해서 만든 것입니다.


완성 사진 및 영상