2021-11-18(목) 9일차

Jeongyun Heo·2021년 11월 18일
0

내일 제이쿼리
22일 평가
화요일에 평가?
구글 드라이브에 파일은 월요일에 하나 올리게끔 해놓고
내용물은 화요일에 작성하면 됨
폴더는 월요일에 만들어놓고
화요일에 구현하는 걸로

코드보다 어떤 순서로 프로그래밍하는지가 중요

그림 그리는 거랑 똑같다고 생각
기능에 대한 분석 단계를 거쳐서 나오는 게 명세

기능분석 → 명세

각 서버에 흩어져 있는 맛집 데이터를 활용

각 팀을 선택하면 지도에서 보여지고 리스트가 갱신됨

리스트에서 특정 가게

회의록은 남한테 양보하지말기

리스트에서 맛집을 선택하면 해당 맛집만 지도에 표시

여기까지가 기능명세

이 시스템을 구현하기 위해서 가장 중요한 데이터고
이 데이터는 어떻게 처리가 될 거고
구조는 어떻게

아키텍처
구조를 만들어주는 거
서로간의 커뮤니케이션이 돼야 함

오늘 디자인 없이 갈 거임

비슐랭..

나중에 카카오페이 붙여보기

데이터를 다루고 로직을 다루는 걸 서비스라고 부름

어제는 지도는 지도대로 띄우고 리스트는 리스트대로 띄움

모듈 패턴
클로저

오늘은 좀 더 깔끔하게 todo 만드는 거 해보겠음

즉시 실행 함수

css3 restaurant menu 검색

https://freebiesbug.com/code-stuff/3d-restaurant-menu-concept/

https://tympanus.net/Tutorials/3DRestaurantMenu/

오픈소스니까 코드 보기

뒤로가기까지 구현함

자바스크립트는 한 번 실행은 함
실행되는 순간에 메모리상에 storeService가 만들어짐

ex10.js 생성

const storeService = (function () {

    function loadData(){
        
    }

    return {loadData}
})()

ex10.html 생성

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script src="ex10.js"></script>
<script>
    console.log(storeService)
</script>
</body>
</html>

클로저 + 즉시 실행 함수

outer 실행하는 과정이 생략된 거라고 보면 됨

제이쿼리가 이렇게 진행함

const storeService = (function () {
    
    const storeArr = []

    function loadData(){

    }

    return {loadData}
    
})()

오늘은 로컬호스트에 있는 json 파일 쓰는 걸로

바꾸기 편해야 됨
자바스크립트의 객체리터럴
1일 때 이거
2일 때 이거
3일 때 이거
객체 리터럴이 표현하기 편함

const storeService = (function () {

    const storeArr = []

    function loadData(url){

    }

    return {loadData}

})()
const storeService = (function () {

    const storeArr = []

    function loadData(url){
        fetch(url)
            .then(response => response.json())
            .then(data => {
                console.log(data)
            })
    }

    return {loadData}

})()

json 데이터 로딩해와야 됨

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script src="ex10.js"></script>
<script>
    storeService.loadData("http://localhost:5555/w17/1team.json")
</script>
</body>
</html>

모듈 패턴을 이용해서 자바의 객체처럼 만든 거

storeArr가 가려져 있음

outer로 해도 괜찮은데 이 방법이 더 깔끔

맛집 데이터를 storeArr에 넣어줘야 됨

사실 data가 배열이라 바꿔치기 해도 상관없음

바꿔치기 할 거면 let으로 바꿔야 됨

전개연산자로 한 번에 push 해도 됨..

const storeService = (function () {

    let storeArr = []

    function loadData(url){
        fetch(url)
            .then(response => response.json())
            .then(data => {
                console.log(data)
                storeArr = data
            })
    }

    return {loadData}

})()

문제는 언제 가져올지 모른다는 거
원래는 원격지에 있는 걸 썼었
트래픽때문에 더 걸릴수도 있고

데이터만 바꿔치기 하면 끝나는 게 아님
화면에 리스트도 갱신해야 됨
'너 이거 다 끝나면 이런 거 해'
다음 지시를 같이 전달해줘야 됨
데이터를 읽어오는데 3초가 걸린다고 가정
3초 뒤에
목록도 갱신하고 지도도 갱신해야 됨
버튼을 클릭하면 제일 먼저 해야 되는 건
목록 바뀐 거 가지고 화면에 리스트 뿌리는 거
콜백함수를 하나 받게 만든다
내일 제이쿼리 쓸 때 계속 나올 애

callback

const storeService = (function () {

    let storeArr = []

    function loadData(url, callback){
        fetch(url)
            .then(response => response.json())
            .then(data => {
                console.log(data)
                storeArr = data
                callback()
            })
    }

    return {loadData}

})()

데이터 로딩이 끝나면 경고창 띄워라

<script>
    storeService.loadData("http://localhost:5555/w17/1team.json", () => {alert("AAA")})
</script>

비동기 통신이 일어난 거

목록을 갱신하는 함수

loadData가 끝나면 이 함수를 실행해

목록을 뿌리는 함수

가게의 배열을 받아서 리스트를 뿌리는 함수

callback(data) ← 파라미터가 생긴 거

data는 맛집 배열

const storeService = (function () {

    let storeArr = []

    function loadData(url, callback){
        fetch(url)
            .then(response => response.json())
            .then(data => {
                console.log(data)
                storeArr = data
                callback(data)
            })
    }

    return {loadData}

})()
<script>
    storeService.loadData("http://localhost:5555/w17/1team.json", (arr) => {alert("AAA")})
</script>
<script>
    storeService.loadData("http://localhost:5555/w17/1team.json", (arr) => {
        console.log("callback...................")
        console.log(arr)
    })
</script>

화면과 관련된 작업들은 분리된 로직에서 하지 않는다
html에서 다 하는 게 좋음
그래야 역할이 확실해짐
티오 패턴??

주석처리 해주기
// console.log(data)

const storeService = (function () {

    let storeArr = []

    function loadData(url, callback){
        fetch(url)
            .then(response => response.json())
            .then(data => {
                // console.log(data)
                storeArr = data
                callback(data)
            })
    }

    return {loadData}

})()

data 가지고 리스트 뿌리면 됨

리스트 만들어서 뿌리기

ul 태그 만들기

ul이랑 li 다루는 애가 필요함
얘도 클로저로 빼면 깔끔하게 뺄 수 있긴 한데

<body>

<ul class="storeList">

</ul>

<script src="ex10.js"></script>

<script>
    function makeList(arr) {
        const storeUlEle = document.querySelector(".storeList")

        let str = ''

        for (let i = 0; i < arr.length; i++) {
            console.log(arr[i])
            str += `<li data-name="${arr[i].name}" data-lat="${arr[i].lat}" data-lng="${arr[i].lng}">${arr[i].name}</li>`
        } // end for

        storeUlEle.innerHTML = str
    }

    storeService.loadData("http://localhost:5555/w17/1team.json", (arr) => {
        console.log("callback...................")
        console.log(arr)
        makeList(arr)
    })
</script>

어제 만든 코드보다 깔끔함

<div id="map" style="width:100vw;height:50vh;"></div>

<body>

<div id="map" style="width:100vw;height:50vh;"></div>

<ul class="storeList">

</ul>

<script src="ex10.js"></script>

<script>
    function makeList(arr) {
        const storeUlEle = document.querySelector(".storeList")

        let str = ''

        for (let i = 0; i < arr.length; i++) {
            console.log(arr[i])
            str += `<li data-name="${arr[i].name}" data-lat="${arr[i].lat}" data-lng="${arr[i].lng}">${arr[i].name}</li>`
        } // end for

        storeUlEle.innerHTML = str
    }

    storeService.loadData("http://localhost:5555/w17/1team.json", (arr) => {
        console.log("callback...................")
        console.log(arr)
        makeList(arr)
    })
</script>
</body>

카카오 script 복붙

let markers = [] ← 기존에 있는 마커 지울 때 씀

화면에 리스트도 나오고 마커도 나옴

1팀 2팀 3팀 버튼 만들기

버튼을 클릭하면 loadData 호출

버튼을 누르면 데이터를 change 하고 싶음

함수 하나 새로 만든다

    function changeData() {
        alert('changeData')
        storeService.loadData("http://localhost:5555/w17/1team.json", (arr) => {
            console.log("callback...................")
            console.log(arr)
            makeList(arr)
            showMarkers(arr)
        })
    }

매개변수에 url 입력 ↓
loadData 매개변수도 url로 변경 ↓

    function changeData(url) {
        alert('changeData')
        storeService.loadData(url, (arr) => {
            console.log("callback...................")
            console.log(arr)
            makeList(arr)
            showMarkers(arr)
        })
    }

클릭하면 마커 하나만 뜨게 해야 됨

내가 이 리스트에서 뭘 선택했는지 알아야 됨
문제는 여기 이벤트를 걸 수 없다는 거
동적으로 만들어지는 거임
onclick
li 태그를 만들 때 onclick으로 직접 집어넣는 방법도 있음
근데 그렇게 안 할 거임

진짜 클릭한 애를 알아와야 됨
target

클릭을 하면

    document.querySelector(".storeList").addEventListener("click", (e) => {
        e.preventDefault()
        e.stopPropagation()

        const target = e.target

        console.log(target)

    }, false)

내가 몇 번째 li를 클릭했는지

js get index of selected li 검색

li 번호 자체에 인덱스 번호가 있으면 편했을 거
그래서 data- 나옴

    function makeList(arr) {
        const storeUlEle = document.querySelector(".storeList")

        let str = ''

        for (let i = 0; i < arr.length; i++) {
            console.log(arr[i])
            str += `<li data-idx="${i}">${arr[i].name}</li>`
        } // end for

        storeUlEle.innerHTML = str
    }

    document.querySelector(".storeList").addEventListener("click", (e) => {
        e.preventDefault()
        e.stopPropagation()

        const target = e.target

        console.log("==================================")
        const idx = target.getAttribute("data-idx")
        console.log("idx: " + idx)

    }, false)

리팩토링

마틴 파울러 리팩토링 2판

ex10.js

const storeService = (function () {

    let storeArr = []

    function loadData(url, callback){
        fetch(url)
            .then(response => response.json())
            .then(data => {
                // console.log(data)
                storeArr = data // 바꿔치기
                callback(data)
            })

    }

    function getDataByIndex(index) {
        return storeArr[index]
    }

    return {loadData, getDataByIndex}

})()
    document.querySelector(".storeList").addEventListener("click", (e) => {
        e.preventDefault()
        e.stopPropagation()

        const target = e.target

        console.log("==================================")
        const idx = target.getAttribute("data-idx")
        // console.log("idx: " + idx)

        const store = storeService.getDataByIndex(idx)
        console.log(store)

        showMarkers([store])

    }, false)

키오스크 - w18/v1.html

w18/v1.html

단계가 중요함

v1
화면만 분할할 거임

상품 목록

UI, UX가 다 다름
퀵오더가 없음

주문 목록 : 총 합계

똑같은 상품을 여러 개 주문하면 수량만 올라가게 할 거임

json 연동하는 거 빼고

삭제 버튼

v2

레이아웃 잡는 방법

탭 메뉴처럼 되어 있음

1팀 2팀 3팀 버튼처럼

1팀은 커피
2팀은 주스
3팀은 케이크

커피 주스 케이크 버튼..

버튼 클릭할 때마다 화면 바꿀 거

옆에 주문 목록 있음

v1에서는 주문을 삭제하는 건 안 만들 거

레이아웃 잡는 방법

커피 c01.jpg
쥬스 j01.jpg
케이크 k01.jpg

v1.html 생성

div class="container" ← 전체를 담는 애

div class="row"

태그는 두 가지
block 태그 : 줄바꿈이 되는 태그
inline 태그

메뉴 안에 ul이랑 li가 필요하다는
메뉴 목록이 떨어져야 되니까
웹 앱에서는 데이터가 메인이다
자바스크립트가 메인이다

div 여러개를 겹쳐놓고 위치만 바뀌는 거

    .menuList {
        display: flex;
    }

css flex overflow 검색

동적으로 만들어진 애들을 클릭하는 방법
1. 바깥쪽 애한테 이벤트 걸기
2. onclick으로 이벤트 처리

data-

어차피 배열
클릭하면 배열의 인덱스 번호가 식별키처럼 동작
리액트로 이렇게 함
리액트는 고유한 키라는 걸 지정하게 함

메뉴를 클릭하면 클릭한 애의 번호를 가지고 처리하는 걸로

    menuList.addEventListener("click", (e) => {
        const target = e.target
        const idx = target.getAttribute("data-idx")
    })

    menuList.addEventListener("click", (e) => {
        const target = e.target
        const idx = target.getAttribute("data-idx")
        console.log(target)
        console.log(idx)
    })

li에 인덱스 번호가 있

트리구조 생각

내 바깥쪽 li 찾아 parent

js find closest parent with class 검색

img 클릭했는데 li까지 나옴

price 클릭했는데 li까지 나옴

data-idx가 li 태그에 있으니까

    menuList.addEventListener("click", (e) => {
        const target = e.target
        const liEle = target.closest("li")
        const idx = liEle.getAttribute("data-idx")
        console.log(target)
        console.log('IDX: ' + idx)
    })
    .pop {
        background-color: lightblue;
        width: 100vw;
        height: 100vh;
        position: absolute;
    }

z index

position: absolute

절대 위치

jquery lightbox

애니메이트 효과

div가 6개 있는 거

음수로 주면 뒤로 들어감
양수를 주면 앞으로 나옴

부트스트랩에 모달이라는 애가 있음

https://getbootstrap.com/docs/4.0/components/modal/

const popEle = document.querySelector(".pop")

토글 버튼 toggle

누르면 안으로 들어가고 한 번 더 누르면 나오는 거

나타나는 거 먼저 하겠음

메뉴를 클릭하면 class가 pop hide에서 pop show로 바뀌는 거

상품 클릭하면 setAttribute로 class를 pop show로 변경해서 팝업 보이게 하기

popEle.setAttribute("class", "pop show")

const popEle = document.querySelector(".pop")

popEle.setAttribute("class", "pop show")

한 번 더 클릭하면 setAttribute로 class를 pop hide로 바꾼다

const popEle = document.querySelector(".pop")

popEle.addEventListener("click", () => {
    popEle.setAttribute("class", "pop hide")
}, false)

transform: scale(0.5); 화면 전체에서 0.5 비율로 보고 싶다

pop 안에 있는 이미지를 바꿔치기 해줘야 됨

const targetMenu = menus[idx]

const targetPicture = targetMenu.picture

지금까지 document.querySelector로 썼었는데 popEle.querySelector("img")

popEle.querySelector("img").setAttribute("src", targetPicture)

    menuList.addEventListener("click", (e) => {
        const target = e.target
        const liEle = target.closest("li")
        const idx = liEle.getAttribute("data-idx")
        // console.log(target)
        console.log('IDX: ' + idx)

        const targetMenu = menus[idx]
        const targetPicture = targetMenu.picture
        popEle.querySelector("img").setAttribute("src", targetPicture)

        popEle.setAttribute("class", "pop show")
    }, false)

    popEle.addEventListener("click", () => {
        popEle.setAttribute("class", "pop hide")
    }, false)

수량 안 할 거임

담을 거냐 or 안 담을 거냐

담기 아니면 취소

취소하고 싶으면 화면 아무데나 누르면 됨

담기가 문제

pop 안에 버튼을 하나 추가

버튼 대신에 h3 태그 추가

<h3>ADD CART</h3>

<div class="pop hide">
    <img src="img/c01.jpg">
    <h3>ADD CART</h3>
</div>

ADD CART 누르면 orders라는 주문 목록에 들어가야 됨

<h3 onclick="addCart()">ADD CART</h3>

또 문제가 생김
내가 지금 ADD CART 하는 상품이 뭔지 알아야 됨

오늘 오전에 한 것 중에서 Element.closest() 제일 중요

img를 클릭하면 이미지를 바꿔치기 하는 것처럼

data-

새로운 함수 생성

function addCart

내가 어떤 상품을 담는지를 알아야만 작업을 할 수 있음

이 부분을 어떻게 할 것인가

내가 클릭을 할 때 상품에 대한 정보가 있어야 된다는 거

내가 이 상품을 클릭을 했을 때 이미지가 바뀌는 것처럼 h3 태그에도 뭔가를 바꿀 수 있지 않을까

전에는 맨날 document.querySelector로 document에서부터 찾음

이번에는 좀 더 편하게 document가 아니라 popEle에서부터 찾아내려간다

querySelector 예제는 전부 다 document.querySelector 밖에 없음

실제로는 안 그럼

어떤 element를 얻어와서 그 element에서부터 다시 querySelector로 타고 들어갈 수 있다

h3 태그에 setAttribute 해주면 될 거 같다

Element.setAttribute(속성이름, 값) : 특정 속성에 값을 지정한다. 없으면 속성을 추가한다.

클릭했을 때 메뉴가 뭔지 아니까

img 태그 src에 파일 경로 동적으로 계속 변경해주는 거

const popEle = document.querySelector(".pop")

const targetMenu = menus[idx]
const targetPicture = targetMenu.picture
popEle.querySelector("img").setAttribute("src", targetPicture)

querySelectordocument.querySelector 말고도

element.querySelector 로 쓸 수 있음

배열 몇 번째에 있는 메뉴인지 알 수 있음

h3 태그에 setAttribute로 data-idx 속성 추가

const popEle = document.querySelector(".pop")

const targetMenu = menus[idx]
const targetPicture = targetMenu.picture
popEle.querySelector("img").setAttribute("src", targetPicture)
popEle.querySelector("h3").setAttribute("data-idx", idx)

상품 클릭하니까 h3 태그에 data-idx 속성 생김

<h3>ADD CART</h3> ← 여기에 data-idx 속성 생긴 거

document.querySelector(".pop h3") => ADD CART 버튼

    document.querySelector(".pop h3").addEventListener("click", (e) => {
        e.stopPropagation()
        e.preventDefault()
        
        const target = e.target
        
        const menu = menus[target.getAttribute("data-idx")]
        console.log(menu)
    }, false)

­1. orders에 메뉴, 수량을 담을 거냐
2. 아니면 똑같이 다 담고 수량도 추가해서 넣을 거냐

구조화된 개념으로 보면 1번이 맞음
출력하거나 그러기엔 2번이 편할 거임

이번에는 2번 방법으로 하겠음

한 방에 하는 방법

const orders = [] 여기에 push 해줘야 됨

수량은 무조건 1로 할 거임

전개 연산자

전개 연산자를 사용한 객체 복사

orders.push({...menu, qty: 1})

배열에 토피넛라떼가 있는지 확인하고 있으면 qty만 올려주고
없으면 토피넛라떼 배열 새로 추가

filter 아니면 indexOf

총금액을 뿌려주는 부분

특정한

주문 목록 나오는 화면에 addCart 함수를 뿌려주면 되는 거

ul 태그 생성해준다

<ul class="orderList">

여기에 li 태그 만들어주면 되는 거

<div class="orderDiv">
    <h1>ORDER</h1>
    <ul class="orderList">
    
    </ul>
</div>

이 안에 주문목록 뿌려주는 거랑 총 금액 뿌려주는 거만 남음

함수를 하나 만들자

function showOrderItems()

orders 안에 내용물 출력해주는 거

const orderListEle = document.querySelector(".orderList") → ul 태그
이 안에서 루프 돌면서 li 뿌려주면 됨

    function showOrderItems() {
        const orderListEle = document.querySelector(".orderList")

        let str = ''

        for (let i = 0; i < orders.length; i++) {
            const orderItem = orders[i]
            str += `<li>${orderItem.name} =============== ${orderItem.qty}</li>`
        }
        orderListEle.innerHTML = str
    }

함수 만들었으니까 호출해줘야됨

addCart() 해서 변경이 됐으니까 showOrderItems()를 호출해준다

영수증 만들어줘야 됨

${orderItem.price * orderItem.qty}

총 금액도 만들어줘야됨

let sum = 0

sum += orderItem.price * orderItem.qty

<hr> : 수평선 그리기

str += `<hr/><h1>${sum}</h1>`
    function showOrderItems() {
        const orderListEle = document.querySelector(".orderList")

        let str = ''
        let sum = 0

        for (let i = 0; i < orders.length; i++) {
            const orderItem = orders[i]
            str += `<li>${orderItem.name} =============== ${orderItem.qty} =============== ${orderItem.price * orderItem.qty}</li>`
            sum += orderItem.price * orderItem.qty
        }
        str += `<hr/><h1>${sum}</h1>`
        orderListEle.innerHTML = str
    }

카테고리 누르면 카테고리에 해당하는 메뉴만 보이게 하는 거
filter() 이용하면 됨

수량을 올릴 수도 있고 취소할 수도 있고 새로 주문하기 눌러서

조금 아쉬웠던 점
배열에 인덱스 번호 쓴 거 별로 안 좋았음
배열의 인덱스 번호라는 건 고유한 값이 아님
상황에 따라서 바뀔 수 있는 값
좀 더 안전하게 하려면 고유의 번호가 있게끔 짰어야 함
고유의 id값
c1 c2 c3 처럼 고유한 번호를 땄으면 굉장히 안전했을 거
주문 목록에서 수량 다운하는 거?
주문 목록 라인 하나 삭제하는 거?

과제

1단계
객체 리터럴과 배열 선언을 할 수 있는가

2단계
화면에 뿌려줘야 됨
div 구성
div와 ul을 만든다
div와 ul을 이용하여 객체들을 출력할 수 있는가
menuList라는 ul태그를 생성하고 화면을 보여줄 수 있는가

3단계
클릭
특정한 메뉴를 클릭
li 태그에 click 이벤트를 걸 수 있나?
바깥쪽 ul 태그에 이벤트를 걸고 e.target을 이용해서 해당 메뉴의 인덱스 번호

4단계
orders 배열을 선언하고 클릭한 메뉴의 정보를 추가
추가할 때 전개 연산자 사용, qty 속성 추가, 중복 체크 X
최종 금액만 출력

본인들이 만든 코드

css 그대로
div 그대로

위에 있는 부분은 그대로 냅두고
script 태그 부분만 작업하기

0개의 댓글