(34) 23.11.09[JS]

DANA·2023년 11월 9일

KDT-구디아카데미

목록 보기
34/56

submit.html

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>실습 - submit 이슈</title>
  <script>
    // 이벤트가 전이되는 것을 차단하기 - e.preventDefault()
    // 테스트 시나리오 - preventDefault를 했을 때와 안 했을 때(없을 때)
    // preventDefault가 없으면 새로고침 됨 - submit 전송 - 새로고침(부작용)
    // get방식 -> query string 사용자가 입력한 값이 올라탄다 ?mem_id=kiwi
    // 콘솔에 찍고 싶은데 잠깐 보여줬다가 사라짐. 왜? 새로고침이 일어나니까(날라가는 것)
    // preventDefault를 했을 때는 새로고침이 안 일어나니까 콘솔창에서 볼 수 있다
    function login(event){
      console.log(event.target);
      console.log('로그인 호출 성공');
      document.getElementById('f_login').submit();
    }
  </script>
</head>
<body>
  <form id="f_login" method="get" action="">
    <input type="text" name="mem_id" id="mem_id">
    <input type="button" value="로그인" onclick="login(event)">
    <button id="btnLogin">로그인2</button>
  </form>
    <script>
      const flogin = document.querySelector("#f_login");
      const login2 = (event) => {
        // event.preventDefault();
        event.preventDefault();
        console.log(event);
      }
      flogin.addEventListener('submit',login2); // 콜백함수
    </script>
</body>
</html>

구조분해할당

  • 구조 분해 할당 구문: 배열이나 객체의 속성을 해체하여 그 값을 개별 변수에 담을 수 있게 하는 JavaScript 표현식

구조분해1.js

// 구조분해 할당
// 1. 배열
const colors = ['red','green','blue'];
// ES5
const color1 = colors[0];
const color2 = colors[1];
const color3 = colors[2];
// ES6 - 구조분해할당 문법 지원
const[c1, c2, c3] = colors;
console.log(c1+c2+c3); // 'redgreenblue'

// 2. 객체
const dept = {
  deptno: 10,
  dname: '개발부',
  loc: '서울'
}

const {deptno, dname, loc} = dept
// ES5
console.log(dept.deptno);
console.log(dept['dname']);
console.log(deptno);
console.log(dname);
console.log(loc);

구조분해2.js

  • Array.prototype.filter()
    : Array 인스턴스의 filter() 메서드는 주어진 배열의 일부에 대한 얕은 복사본을 생성하고, 주어진 배열에서 제공된 함수에 의해 구현된 테스트를 통과한 요소로만 필터링 함
// 배열 -> filter -> 얕은복사 or 깊은복사
const words = ['spray', 'elite', 'exuberant', 'destruction', 'present'];
// -> filter는 다른 여러 객체에서도 재사용할 수 있는 prototype
// -> filter함수는 리턴타입이 배열이다. 그런데 깊은 복사이다 - 새로운 배열이다
// 결론: 두 배열이 주소번지가 다른 것이다
const result = words.filter((word) => word.length > 6);
console.log(typeof result);
console.log(result.length);
words.push('abcdefg');
console.log(words);
console.log(result); // filter타입 -> 깊은 복사라는 걸 알아야 한다
console.log(result);
// Expected output: Array ["exuberant", "destruction", "present"]
// 배열에 대한 초기화를 한 줄로 끝냄 - 구조분해 할당 -> react -> props
const [r1,r2,r3] = result;
console.log(r1);
console.log(r2);
console.log(r3);

Google

  • express를 쓰지 않고서도 사용이 가능할까?

service-firebase

import { initializeApp } from 'https://www.gstatic.com/firebasejs/9.22.1/firebase-app.js';

const firebaseConfig = { 
  firebase에서 apikey 정보 담기
};

// Initialize Firebase
export const app = initializeApp(firebaseConfig);

service-authLogic.js

import {
  getAuth,
  GithubAuthProvider,
  GoogleAuthProvider,
} from 'https://www.gstatic.com/firebasejs/9.22.1/firebase-auth.js';
class AuthLogic {
  constructor() {
    this.auth = getAuth();
    this.gitProvider = new GithubAuthProvider();
    this.googleProvider = new GoogleAuthProvider();
  }
  getUserAuth = () => {
    return this.auth;
  };
  getGoogleAuthProvider = () => {
    return this.googleProvider;
  };
} // end of AuthLogic
// import { AuthLogic } from "./service/authLogic.js"
// export 뒤에 default가 있을 때는 좌중괄호 우중괄호 안 됨
export default AuthLogic;
// import { loginGoogle, loginKakao, logout } from "./service/authLogic.js"
// (authLogic.loginGoogle 이렇게 쓰고 싶지 않음) 
// 클래스의 주소번지 없이도 html,js에서(css는 X) 호출하고 싶다면
// 함수 선언 앞에 export 붙인다
// 로그아웃 할 때(html에서 버튼누를 때) 호출되는 함수이다
// 파라미터에는 auth가 필요하다
// 이 auth는 어떤 과정을 거쳤나: firebase.js 통과 - app을 얻게 됨 - 이 app을 통해 getAuth(인증정보가 있을 것이다)
// 파라미터로 auth를 넣어줘야 signOut() 호출이 가능하다
// 이 때 에러가 발생하면(인증토큰 없다 - 우리 가족이 아니다 - 너 url로 접근하려는 거야?)
// 인정한 통로가 아닌 곳으로 오는 너는 침입자 - catch -> 403
// catch에 잡힌 너는 reject에서 처리할게 - 인터셉트
export const logout = (auth) => {
  return new Promise((resolve, reject) => {
    auth. signOut().catch(e=>reject(alert(e+":로그아웃 에러 발생")))
    // 원서비스에서는 세션에서 관장해야 한다 - 구글 서버측에서 담당 -> signOut()
    localStorage.removeItem('uid'); // uid를 쥐고 있다는 건 구글 서버로부터 정상적으로 토큰을 받았고 그 결과 uid 갖게 됨
    resolve()
  })
}

export const loginGoogle = (params) => {
  return new Promise((resolve, reject) => {
    signInWithEmailAndPassword(auth, googleProvider)
      .then((result) => {})
      .catch((error) => {
        const errorCode = error.code;
        const errorMessage = error.message;
      });
  });
}; //end of loginGoogle
export const loginKakao = (params) => {
  return new Promise((resolve, reject) => {
    try {
      const response = axios({
        method: 'get',
        url: '카카오토큰을 받아올 URL주소 -카카오개발자 센터 긁어옴',
        params: params,
      });
      console.log(response);
      resolve(response);
    } catch (error) {
      reject(error);
    }
  });
}; 

index.html

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>도서관리시스템 - html활용코드</title>
</head>
<body>
  <button id="btnLogin">로그인</button>
  <button id="btnLogout">로그아웃</button>
  <script type="module">
    import { firebaseApp } from "../service/firebase.js"
    import { getAuth } from "https://www.gstatic.com/firebasejs/9.22.1/firebase-auth.js";
    import AuthLogic from "../service/authLogic.js"
    const auth = getAuth(firebaseApp);
    console.log(auth);
    // authLogic.js에서 구현한 클래스를 인스턴스화 하기
    const authLogic = new AuthLogic();
    // 객체생성이 되었으니까 전변을 호출할 수 있다
    // console.log(authLogic.googleProvider);
    // console.log(authLogic['googleProvider']);
  </script>
</body>
</html>

firebase 문서 - 빌드 - 인증 - 웹
https://firebase.google.com/docs/auth/web/google-signin?hl=ko

도서관리시스템
도서목록(조건검색조회포함)
페이징처리
도서상세보기 - 모달

카카오페이, 카카오지도, 네이버로그인, 토스증권 결제

import { firebaseApp } from "../service/firebase.js"; // 초기화 작업함 - 준비과정 - app객체를 돌려받음
/* 돌려받은 app 객체로 무엇을 했나?
-> getAuth함수를 호출할 때 파라미터 자리에 앱 객체를 넣었다
const auth = getAuth(app);

auth는 어떤 정보를 쥐고 있나?
localhost:5500/xxxx/index.html -> 로그인버튼 -> 전처리(로그인 위한 사전단계) 필요함 -> auth 쥐고 있어야 한다

auth 객체는 어떻게, 언제, 왜 쥐어야 하나?
-> auth 객체가 있어야 로그인하는 함수호출이 가능하니까 콜백함수로 로그인을 누르기 전까지 쥐어야 함

  • 콜백함수는 구글 측에서 콜을 하는 것. 그럼 콜 한 것에 대한 응답이 다운로드 되는 것. 이 다운로드 된 정보를 우리가 콘솔로그에 찍었던 것 ex.log(auth)

*/
import { getAuth } from "https://www.gstatic.com/firebasejs/9.22.1/firebase-auth.js";
import AuthLogic from "../service/authLogic.js"
import { loginGoogle } from "../service/authLogic.js"
const auth = getAuth(firebaseApp);

/
팝업은 누가 띄웠나? 구글. 구글에서 만들어놓은 모달이 출력됨
signInWithPopup(auth, 서비스제공업체-google: 전역변수로 googleProvider)
이 함수가 호출되었을 때 팝업이 열림
-> 처리단계 진행(구글서버가 진행) -> 구글에서 처리해주는 시간이 있으니 지연 발생 -> waiting이 벌어짐 -> 그런데 자바스크립트는 절차지향적이어서 순서가 그 다음으로 진행하는데, 그러면 안 되니까 우리는 응답을 받을 때까지 기다리라고 해야 한다 -> 비동기처리를 해야 함 -> 이 비동기 처리를 위해 async 예약어를 함수 앞에 붙이고 await을 콜 -> await loginGoogle(auth, googleProvider) -> 기다림 -> 응답 -> 알림이 옴 -> 메세지로 push -> 듣게 됨 -> 들은 내용을 가지고 처리 -> 처리가 되면 콜백함수를 쓰는 것 then((result)=>{})(콘솔로그에 result를 찍어본다) -> 이걸 문자열로 바꿔야 하니 stringify
고차함수 return new Promise((resolve[성공],reject[실패])=>{})
성공해서 돌려받은 데이터를 resolve의 파라미터로 넘겨준다. 왜? 리턴받아야 index.html에서 출력할 수 있으니까
돌려받은 건 authLogic.js에서 돌려받았는데 이걸 사용하는 것은 index.html에서 사용해야 하니까 반환값을 사용함
/
파이어베이스 콘솔
Authentification: 등록 -> 프로젝트 생성 -> API key 받음
npm 방식(로컬처리방식 - npm i firebase) or cdn 방식(url을 통해서 import)이 있음 - 5500 포트를 사용하고 있음(Live Server가 제공하는 포트)
npm 방식으로 한다면 추가 설정 필요(build와 관련된 작업이 필요) - build 파셀, 웹팩, babel...

구글개발자 콘솔
clientID 발급 받음 -> 도메인 추가함 -> 승인된 도메인이 클라이언트 도메인이 추가돼있어야 함
단, 구글개발자 콘솔에서 프로젝트를 생성하고 받은 키는 필요없었음
Youtube 라이브러리
도메인을 추가할 때 127.0.0.1은 등록이 안 되므로 사용 X


login.js

<!DOCTYPE html>
<html>
  <head>
    <title>한빛출판사</title>
    <link rel="stylesheet" href="/stylesheets/style.css" />
    <link
      href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css"
      rel="stylesheet"
      integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65"
      crossorigin="anonymous"
    />
    <script
      src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"
      integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4"
      crossorigin="anonymous"
    ></script>
    <script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.9.0/slick.min.js"></script>
    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.9.0/slick.min.css"
    />
    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.9.0/slick-theme.min.css"
    />
  </head>
  <body>
    <div class="container">
      <%-include("header.ejs")%>
      <div id="loading" class="row my-5">
        <div class="col my-5">
          <img src="/images/loading.gif" alt="로딩이미지" />
        </div>
      </div>
      <%-include(pageName)%> <%-include("footer.ejs")%>
    </div>
  </body>
  <script>
    // DOM이 다 그려진 거야?
    $(document).on('ready', () => {
      setTimeout(() => {
        $('#loading').hide();
      }, 1000);
    });
  </script>
</html>

login.ejs

<div class="row my-5 justify-content-center">
  <div class="col-8 col-md-6 col-lg-4">
    <h3 class="text-center mb-5">로그인</h3>
    <form name="frm" method="post">
      <div class="input-group my-2">
        <div class="input-group-text">이 메 일</div>
        <input class="form-control" name="email" value="tomato@hot.com" />
      </div>
      <div class="input-group">
        <div class="input-group-text">비밀번호</div>
        <input
          class="form-control"
          name="password"
          type="password"
          value="12345678"
        />
      </div>
      <div class="my-3">
        <!-- 
          <input type=button> or <button> 기본적으로 submit속성이 내장됨
         -->
        <button class="btn btn-success w-100">로그인</button>
      </div>
      <!-- 회원가입 링크경로는 반드시 router/ 생각할 것 -->
      <div class="text-end mt-3"><a href="/users/join">회원가입</a></div>
    </form>
  </div>
</div>
<script type="module">
  import { app } from '/javascripts/firebase.js';
  import {
    getAuth,
    signInWithEmailAndPassword,
  } from 'https://www.gstatic.com/firebasejs/9.22.1/firebase-auth.js';
  const auth = getAuth(app);
  console.log(auth);

  //로그인 버튼을 눌렀을 때
  //submit이슈 - submit이벤트를 처리할때 캡쳐링으로 인한 이벤트 전이가 발생함 - 방어해야함
  $(frm).on('submit', function (e) {
    console.log('로그인버튼 클릭');
    e.preventDefault();
    //사용자가 화면에 입력한 이멜 주소 담기
    let email = $(frm.email).val();
    //사용자가 화면에 입력한 비번 담기
    let password = $(frm.password).val();
    console.log(`${email} ${password}`);
    //https://firebase.google.com/docs/auth/web/start?hl=ko&authuser=0
    //기존 사용자가 자신의 이메일 주소와 비밀번호를 사용해 로그인할 수 있는 양식을 만듭니다.
    //사용자가 양식을 작성하면 signInWithEmailAndPassword 메서드를 호출합니다.
    
    signInWithEmailAndPassword(auth, email, password)
      .then((response) => {
        // Signed in
        const user = response.user;
        //JSON.stringify(user) -> string으로 변환이 되어서 글자를 알아볼 수 있다 - Object를 출력하지 않고
        console.log(`user ===> ${JSON.stringify(user)}`); //[object, Object]  - JSON.parse():JSON-Array
        console.log(`uid ====> ${user.uid}`);
        console.log(`email ====> ${user.email}`);
        localStorage.setItem('uid', `${user.uid}`); //로컬 브라우저 저장소에 담음
        localStorage.setItem('email', `${user.email}`); //로컬 브라우저 저장소에 담음
        location.href = '/';
      })
      .catch((error) => {
        const errorCode = error.code;
        const errorMessage = error.message;
      });
  });
</script>

index.js

var express = require('express');//외부 프레밍워크 가져올때
var router = express.Router();//페이지 전환

/* GET home page. 
express가 Restful API를 지원해서 웹 서비스를 제공할 수 있게 해준다.(서블릿, JSP)
router는 페이지 전환 해주는 API로 - 화면 전환 처리 이벤트
get함수의 첫번째 파라미터가 요청에 대한 URL 주소이다.
URL주소마다 자바단에서는 메소드를 설계(구현)해야 한다.
*/
router.get('/', function(req, res, next) {
  res.render('index', { title: '도서관리시스템' , pageName:"home.ejs"});
});
router.get('/login', function(req, res, next) {//app.js -> path 라이브러리 __dirname, views
  res.render('index', { title: '로그인',  pageName: "auth/login.ejs" });
});

module.exports = router;

join.ejs

<div class="row my-5 justify-content-center">
  <div class="col-8 col-md-6 col-lg-4">
    <h3 class="text-center mb-5">회원가입</h3>
    <form name="frm" method="post">
      <div class="input-group my-2">
        <div class="input-group-text">이 메 일</div>
        <input class="form-control" name="email" value="tomato@hot.com" />
      </div>
      <div class="input-group">
        <div class="input-group-text">비밀번호</div>
        <input
          class="form-control"
          name="password"
          type="password"
          value="12345678"
        />
      </div>
      <div class="my-3">
        <button class="btn btn-success w-100">회원가입</button>
      </div>
      <div class="text-end mt-3"><a href="/login">로그인</a></div>
    </form>
  </div>
</div>
<script type="module">
  import { app } from '/javascripts/firebase.js';
  import {
    getAuth,
    createUserWithEmailAndPassword,
  } from 'https://www.gstatic.com/firebasejs/9.22.1/firebase-auth.js';
  const auth = getAuth(app);
  console.log(auth);

  $(frm).on('submit', function (e) {
    console.log('회원가입 버튼 클릭');
    e.preventDefault();
    let email = $(frm.email).val();
    // 사용자가 화면에 입력한 비번 담기
    let password = $(frm.password).val();
    console.log(`${email} ${password}`);

    createUserWithEmailAndPassword(auth, email, password)
      .then((response) => {
        // 회원가입에 성공하면
        console.log(response);
        location.href = '/login';
      })
      .catch((error) => alert(error.message));
  }); // end of createUserWithEmailAndPassword
</script>

users.js

var express = require('express');
var router = express.Router();

/* GET users listing. */
router.get('/', function (req, res, next) {
  res.send('respond with a resource');
});
router.get('/join', function (req, res, next) {
  res.render('index', { title: '회원가입', pageName: 'users/join.ejs' });
});
router.get('/cart', function (req, res, next) {
  // res.send();파라미터 문자열이 출력되고 나는 장바구니 화면을 출력할거니까 render함수 호출함
  res.render('index', { title: '장바구니', pageName: 'users/cart.ejs' });
});
router.get('/mypage', function (req, res, next) {
  res.render('index', { title: '마이페이지', pageName: 'users/mypage.ejs' });
});

module.exports = router;

handlebars

deptList.html

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>실습 - Handlebars[템플릿엔진]</title>
    <link
      href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css"
      rel="stylesheet"
      integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65"
      crossorigin="anonymous"
    />
    <script
      src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"
      integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4"
      crossorigin="anonymous"
    ></script>
    <!-- cdn: 가장 가까운 서버에서 -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/3.0.1/handlebars.js"></script>
    <script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
  </head>
  <body>
    <!-- 
      x-handlebars-template sub mime type은 표준이 아니다?
      표준이 아니라는 건 재해석이 필요하다 - 모르는 애
      핸들바스로 되어있는 템플릿 컴파일 합니다
     -->
    <script id="tb-dept" type="text/x-handlebars-template">
      <table class='table'>
        <!-- header 영역 시작 -->
        <thead>
          <tr>
            <th scope='col'>부서번호</th>
            <th scope='col'>부서명</th>
            <th scope='col'>지역</th>
          </tr>
        </thead>
        <!-- header 영역 끝 -->
        <!-- 데이터셋 추가하는 화면 제공되는 영역 시작 -->
        <tbody>
          {{#depts}}
            <tr>
              <td>{{deptno}}</td>
              <td>{{dname}}</td>
              <td>{{loc}}</td>
            </tr>
          {{/depts}}
        </tbody>
        <!-- 데이터셋 추가하는 화면 제공되는 영역 끝 -->
      </table>
    </script>
  </body>
  <script>
    // 핸들바스 템플릿을 가져옵니다
    const tb_dept = $('#tb-dept').html();
    const template = Handlebars.compile(tb_dept);
    // 핸들바스 템플릿에 바인딩 될 데이터셋입니다 - 내부는 Array
    const data = {
      depts: [
        { deptno: 10, dname: '개발1팀', loc: '서울' },
        { deptno: 20, dname: '운영팀', loc: '제주' },
        { deptno: 30, dname: '품질관리팀', loc: '세종' },
      ],
    };
    // 핸들바 템플릿에 데이터를 바인딩해서 html을 새로 생성함
    const deptList = template(data);
    // 위에서 생성된 템플릿을 body태그에 붙인다(추가)
    $('body').append(deptList);
  </script>
</html>
<!-- 
  select된 결과가 3건이라면 for문을 돌려서 한 개 로우씩 3번 반복되어야 한다
  문제제기:자바코드와 태그코드가 섞이는게 불편하다
  : 1. 가독성 - DOM Tree -> 태그로만 작성해 본다(이쪽이 더 유리)
  : 2. 디자인과 로직은 분리되어야 한다
  : 좌중괄호 우중괄호 짝이 안 맞으면 500번 에러가 발생
  -> 대안으로 템플릿 엔진을 지원하게 되었다
 -->

URL 파라미터 가져오기
https://gurtn.tistory.com/126

0개의 댓글