내일 제이쿼리
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
단계가 중요함
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)
querySelector
를 document.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 태그 부분만 작업하기