자바스크립트 이어서
조건문
기본형식과 예시
if (조건) {
내용
} else {
내용
}
}
사실 그냥 if if if if 해서 쓸수 있는데, else를 쓰는 경우는 우리가 생각하지 못한 예외까지 포함하기 때문.
예시 : 어떤 값이 90보다 작으면 작다고, 크면 크다고 알려주는 함수
예시 : 딕셔너리 사용하기
* 조건이 여러개일 때 사용하는 연산자 : and , or
설명
and : 기호는 && 이며, 두개의 조건 모두 true여야만 ture를 낸다.
or : 기호는 || 이며, 두 개의 조건 중 하나만 true여도 true를 낸다. 물론 둘 다 false라면 false를 낸다.
예시
나이가 20과 같거나 크고 30보다 작은 경우, 즉 20대인지 여부를 알려주는 함수.
or (||) 도 아래와 동일한 방식으로 하면 된다.
* 조건이 여러개 있는 경우 : else if
설명
일반 조건문에서 else 대신 else if , else if ... 쭉 가다가 마지막에 else 로 마무리할 수 있다.
그냥 if if if if 를 하면 되는데 왜 else if 를 쓰는가? if는 무조건 실행하게 되어있다. 따라서 if를 여러개 쓰는 경우, 선행 if가 완료되어도 그다음 if를 무조건 실행한다. 하지만 else if는 선행 if가 되었으면 else if는 수행하지 않는다.
예시
여기서 만약 else if를 if로 했다면, 120 보다 큰거 검사 해서 와 19세기 태어났군요 나오고 끝나는게 아니고, 이거 나오고 또 80세이상! 이것도 나온다. 즉 모든 if를 다 실행해버림.
보통 if if if 이런식으로 잘 안쓸 것 같은데, 의도적으로 쓰는 경우가 있긴 있다. 여러개 검사를 꼭 해야 할때 등.. 암튼 필요할 수 있다. 실제로 업무에서는 복잡한 if문은 잘 안쓰고, 단순한 걸 많이 쓰게 된다고 한다. (else도 없는..)
반복문
만약 0부터 99까지 출력하라고 한다면, console.log(0) 부터 시작해서 99까지 할 순 없다. 이걸 간단하게 하는게 반복문이며, for 문이라고 한다. 대부분의 프로그램들은 반복문이 for 이다.
# 참고 : 대부분의 프로그래밍 기본 패턴은 조건문+반복문이 조합된다.
* 반복문의 형태
반복문에는 3가지가 들어가며, 세미콜론으로 구분된다. for문이 시작하면, 먼저 시작조건을 검사하고, 아래 액션을 수행한 후 3번째인 반복후액션을 수행하고 종료조건을 검사하고 조건이 참이면 다시 아래 구문을 실행한다. 이걸 반복한다. 반복하면서 종료조건에서 false가 나오면 안에 구문 실행하지 않고 종료조건에서 바로 종료된다.
for (시작조건; 반복조건; 매 반복후 할일) {
실행할것;
}
- 시작조건 : 시작할때의 조건
- 반복조건 : 해당 조건이 false가 되면 반복문이 끝난다.
- 매 반복 후 할일 : 반복문 안에 본문 실행 후에 여기 있는걸 하고, 다시 반복조건을 검사한다.
# 참고 : 카운터변수 i
i++ : i에다가 1을 더해서 다시 i에 넣어라 라는 뜻.
i는 프로그래밍에서 카운터변수(counter variable)라고 하며 보통 for문에서 관습적으로 많이 사용한다.
기본예시
let wizards = ['덤블도어','맥고나걸','스네이프','해리','허마이오니','론']
// 리스트이름.length 기억나시죠? 리스트의 길이!
// i가 1씩 증가하면서, 마법사들 wizards의 원소를 차례대로 불러올 수 있게 됩니다.
// 이렇게 하면 리스트의 모든 원소를 한번에 출력할 수 있겠죠?
for (let i = 0 ; i < wizards.length ; i++) {
console.log(wizards[i])
}
* 반복문과 리스트, 딕셔너리
반목문은 리스트와 단짝이다. 함께 자주 쓰인다. 리스트와 반복문이 쓰일때는, 리스트를 처음부터 끝까지 검사하기 위해 "리스트명.length" 형식으로 반복조건을 많이 사용한다.
자주 쓰는 패턴 중 하나는 먼저 "리스트+딕셔너리" 를 선언하고, 반복문에서 출력할 수 있다.
예시 : 리스트 내의 딕셔너리를 모두 출력하기
let wizardsInfo = [
{'name':'덤블도어', 'age':116},
{'name':'맥고나걸', 'age':85},
{'name':'스네이프', 'age':60},
{'name':'해리', 'age':40},
{'name':'허마이오니', 'age':40},
{'name':'론', 'age':40},
]
for (let i = 0 ; i < wizardsInfo.length ; i++) {
console.log(wizardsInfo[i]);
}
예시 :아래는 70살 미만인 마법사 이름을 출력하는 반복문 (위에 변수를 그대로 사용)
i는 0부터 시작하고, wizardinfo의 길이가 6이므로, i가 6보다 작으면 계속 진행한다. i는 매번 1씩 올린다. 만약 위자드정보에서 age가 70보다 적으면, 예시와 같이 console.log로 이름을 출력하고 아니면 암것도 안하고 이걸 반복한다.
* 반복문 예시
연습1 - 반복문, 합을 구하는 함수 만들기
0부터 n-1까지 더하는 함수를 만들고 싶다면? ( 0부터 n-1 이라는 것은, 0이 들어가기 때문에 1개를 빼는것임..)
function calculateSum(n) {
let sum = 0
for (let i = 0; i < n; i++) {
sum += i; // sum을 i만큼 증가시켜라. sum = sum + i 와 동일!
}
return sum
}
let result = calculateSum(10); // return 결과인 sum이 result에 저장
console.log(result) // 45를 출력
처음에 sum
연습2 - 다음 리스트에서 딸기는 몇 개일까?
이 연습은 프로그래밍의 기본에서 매우 중요함. 반복되는 코드를 이렇게 함수로 만들고, 확장해나가는 것.
let fruitsBasket = ['사과','감','감','배','포도','포도','딸기','포도','감','수박','딸기']
function countFruit(name) {
let count = 0;
for (let i = 0; i < fruitsBasket.length; i++) {
let fruit = fruitsBasket[i];
if (fruit == name) {
count += 1;
}
}
return count;
}
// 함수로 만들어두면! 같은 코드을 또 적을 필요가 없죠!
let gamCount = countFruit("감");
console.log(gamCount);
let subakCount = countFruit("수박");
console.log(subakCount);
연습3 - 오픈api일부를 가져와서, 미세먼지(pm10)의 값이 25미만인 측정소 (msrste_nm)과 미세먼지 수치 출력하기
이 패턴도 익숙해져야 한다. open api는 아래서 자세히 배울 것이다. 해당 값은 서울시에서 제공하는 특정 시점의 미세먼지 수치 중 일부이다. 이 값은 리스트+딕셔너리 형식이다. 이 값을 가지고 아래 문제를 풀어보자.
let cityAir = [
{
MSRDT: "201912052100",
MSRRGN_NM: "도심권",
MSRSTE_NM: "중구",
PM10: 22,
PM25: 14,
O3: 0.018,
NO2: 0.015,
CO: 0.4,
SO2: 0.002,
IDEX_NM: "좋음",
IDEX_MVL: 31,
ARPLT_MAIN: "O3",
},
{
MSRDT: "201912052100",
MSRRGN_NM: "도심권",
MSRSTE_NM: "종로구",
PM10: 24,
PM25: 18,
O3: 0.013,
NO2: 0.016,
CO: 0.4,
SO2: 0.003,
IDEX_NM: "좋음",
IDEX_MVL: 39,
ARPLT_MAIN: "PM25",
},
{
MSRDT: "201912052100",
MSRRGN_NM: "도심권",
MSRSTE_NM: "용산구",
PM10: 0,
PM25: 15,
O3: 0.012,
NO2: 0.027,
CO: 0.4,
SO2: 0.003,
IDEX_NM: "점검중",
IDEX_MVL: -99,
ARPLT_MAIN: "점검중",
},
{
MSRDT: "201912052100",
MSRRGN_NM: "서북권",
MSRSTE_NM: "은평구",
PM10: 36,
PM25: 14,
O3: 0.019,
NO2: 0.018,
CO: 0.5,
SO2: 0.005,
IDEX_NM: "좋음",
IDEX_MVL: 42,
ARPLT_MAIN: "PM10",
},
{
MSRDT: "201912052100",
MSRRGN_NM: "서북권",
MSRSTE_NM: "서대문구",
PM10: 28,
PM25: 9,
O3: 0.018,
NO2: 0.015,
CO: 0.6,
SO2: 0.004,
IDEX_NM: "좋음",
IDEX_MVL: 37,
ARPLT_MAIN: "PM10",
},
{
MSRDT: "201912052100",
MSRRGN_NM: "서북권",
MSRSTE_NM: "마포구",
PM10: 26,
PM25: 8,
O3: 0.012,
NO2: 0.021,
CO: 0.5,
SO2: 0.003,
IDEX_NM: "좋음",
IDEX_MVL: 36,
ARPLT_MAIN: "NO2",
},
{
MSRDT: "201912052100",
MSRRGN_NM: "동북권",
MSRSTE_NM: "광진구",
PM10: 17,
PM25: 9,
O3: 0.018,
NO2: 0.016,
CO: 0.6,
SO2: 0.001,
IDEX_NM: "좋음",
IDEX_MVL: 31,
ARPLT_MAIN: "O3",
},
{
MSRDT: "201912052100",
MSRRGN_NM: "동북권",
MSRSTE_NM: "성동구",
PM10: 21,
PM25: 12,
O3: 0.018,
NO2: 0.017,
CO: 0.4,
SO2: 0.003,
IDEX_NM: "좋음",
IDEX_MVL: 33,
ARPLT_MAIN: "PM25",
},
{
MSRDT: "201912052100",
MSRRGN_NM: "동북권",
MSRSTE_NM: "중랑구",
PM10: 27,
PM25: 10,
O3: 0.015,
NO2: 0.019,
CO: 0.4,
SO2: 0.003,
IDEX_NM: "좋음",
IDEX_MVL: 34,
ARPLT_MAIN: "PM10",
},
{
MSRDT: "201912052100",
MSRRGN_NM: "동북권",
MSRSTE_NM: "동대문구",
PM10: 26,
PM25: 9,
O3: 0.016,
NO2: 0.017,
CO: 0.4,
SO2: 0.003,
IDEX_NM: "좋음",
IDEX_MVL: 34,
ARPLT_MAIN: "PM10",
},
{
MSRDT: "201912052100",
MSRRGN_NM: "동북권",
MSRSTE_NM: "성북구",
PM10: 27,
PM25: 8,
O3: 0.022,
NO2: 0.014,
CO: 0.5,
SO2: 0.003,
IDEX_NM: "좋음",
IDEX_MVL: 37,
ARPLT_MAIN: "PM10",
},
{
MSRDT: "201912052100",
MSRRGN_NM: "동북권",
MSRSTE_NM: "도봉구",
PM10: 25,
PM25: 12,
O3: 0.024,
NO2: 0.011,
CO: 0.3,
SO2: 0.002,
IDEX_NM: "좋음",
IDEX_MVL: 41,
ARPLT_MAIN: "O3",
},
{
MSRDT: "201912052100",
MSRRGN_NM: "동북권",
MSRSTE_NM: "강북구",
PM10: 30,
PM25: 15,
O3: 0.022,
NO2: 0.02,
CO: 0.4,
SO2: 0.002,
IDEX_NM: "좋음",
IDEX_MVL: 39,
ARPLT_MAIN: "PM10",
},
];
아래 두 질문에 대답하기 전에, 먼저 위 스크립트 내용을 그대로 복붙하여 cityAir라는 변수를 선언하고 값들을 넣는다.
Q1. "PM10" 수치가 25㎍/㎥보다 작은 측정소(MSRSTE_NM) 를 모두 출력해보세요.
for (let i = 0; i < cityAir.length; i++) {
let mise = cityAir[i];
if (mise["PM10"] < 25) {
let guName = mise["MSRSTE_NM"];
let guMise = mise["PM10"];
console.log("25㎍/㎥보다 작은 구: " + guName + ", " + guMise);
}
}
Q2. 함수 만들기 - 입력받은 미세먼지 수치보다 작은 측정소(MSRSTE_NM) 를 출력하는 함수를 만들어보세요.
function showUnderMise(index) {
for (let i = 0; i < cityAir.length; i++) {
let mise = cityAir[i];
if (mise["PM10"] < index) {
let guName = mise["MSRSTE_NM"];
let guMise = mise["PM10"];
console.log(index + "보다 작은 구: " + guName + ", " + guMise);
}
}
}
jquey란?
jQuery
What is jQuery? jQuery is a fast, small, and feature-rich JavaScript library. It makes things like HTML document traversal and manipulation, event handling, animation, and Ajax much simpler with an easy-to-use API that works across a multitude of browsers.
jquery.com
자바스크립트를 일일이 다 치는 것은 비효율적이다. 여느 프로그래밍 언어와 마찬가지로 있는걸 가져다 쓰는 능력이 중요하다. jquery는 html의 요소들을 조작하고 화면의 움직임을 처리하는 등 편리하고 자주 쓰이는 자바스크립트 코드를 미리 작성해놓은 묶음이다. 즉 자바스크립트의 라이브러리 중 하나. 또한 함수들의 명시적이라 알아보기도 편하다.
자바스크립트로도 뭐든 기능을 구현할 수 있지만(버튼 글씨 바꾸기, 숨기기 등), jquery를 쓰면 복잡한코드르 줄일 수 있고, 브라우저간 호환성도 고려해야 해서, jquery라는 라이브러리가 등장했다.(브라우저 호환성은 좀 옛날얘기)
# 참고 : 라이브러리란?
공통으로 사용할 수 있는 특정 기능이나 함수들의 모음이다. 1주차에서 javascript 배울 때, 소문자를 대문자로 바꾸는 함수, 문자를 나누는 함수 등을 썼는데, 이건 자바스크립트에서 기본으로 제공하는 라이브러리를 사용한 것이다. 즉 추가 라이브러리를 넣을 수 있고, 라이브러리를 사용하면 내가 모든 걸 다 만들지 않아도 라이브러리에 있는 함수를 가져다 쓸 수 있다.
# 참고 : 동일한 기능을 자바스크립트로 썼을 때와 jquery를 썼을 때 비교
자바스크립트 : document.getElementById("element").style.display = "none";
jquery : $('#element').hide();
jquery 시작하기
미리 작성된 자바스크립트 코드를 가져오는 것을 import라고 하는데, jquery도 부트스트랩처럼 임포트를 해야 함. jquery는 자바스크립트와 다른 특별한 게 아니고, 미리 작성된 javascript 코드들의 모음이다. 전문 개발자들이 짜 놓은 것. 이걸 임포트하는 것이다.
* import 방법
<head></head>사이에 아래 한 줄을 넣으면 완료.
<script src="<https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js>"></script>
여기 보면 버전이 3.5.1 인 jquery를 확인할 수 있다. 이 jquery의 버전과 부트스트랩의 버전도 호환되는지 확인해야 할 필요가 있을 수 있다. 현재 3.5.1은 부트스트랩과 호환된다고 한다.
# 참고 : 더 자세히 살펴보기
jquery 시작하기 : https://www.w3schools.com/jquery/jquery_get_started.asp
jquery 관련 정보 : https://code.jquery.com/ (공식CDN)
JQUERY 사용하기
jquery도 특정 태그에 어떤 액션을 해라 라고 할 수 있어서, jquery도 css처럼 선택자를 쓸 수 있고, 선택자로 id라는 걸 씀. (css에서는 선택자로 class를 썼다. (마침표를 앞에 붙이는 방식)
jquery는 id라는 선택자 값을 통해 특정버튼,인풋박스,div등을 가리키는 게 일반적이다.
예를들어, 특정 인풋박스의 값을 -> 가져와라 / 특정 DIV를 -> 안보이게 해라. 이런식이다.
특정 태그에 jquery로 접근하려면 id를 정의해야 함. post-url은 id로 input 태그에 들어가있다. id로 정의한 곳을 선택하고 함수를 적용하거나 html에서 사용할 수 있다.
$('#id로 정의한 이름')
jquery 패턴 연습하기
절대 모든 jquery를 외울필요 없다. 스크롤을 감지하는 함수, 화면 사이즈를 변경할 때 반응하는 함수, 여러가지 엄청 많다. 이런것도 필요에 따라 구글링을 해야 한다.
1. 사용자가 입력한 값을 가져오기
이 내용은 아래 태그인데, 여기서 post-url 을 주목하자.
val() 함수(입력된 값을 가져옴)를 사용하여 아래와 같이 사용할 수 있다.
$('#post-url').val();
그러면 efsdfd를 출력하게 된다. 다시 정리하면, #post-url은 html 내에 post-url이라는 id를 찾으라는 의미이며, 그 값을 가져와서 jquery에 정의된 함수 중 하나인 val()을 사용하라는 것이다.
아래처럼 값을 가져온다. 즉 유저가 입력한 값을 받아올 수 있음.
아래처럼 변수에다 이 결과를 넣을수도 있다.
추가로, 아래처럼 직접 텍스트를 입력하면 직접 입력하지 않고 입력할수도 있다.
$('#post-url').val('여기에 텍스트를 입력하면!');
즉, val 함수는 해당 텍스트박스에 글을 넣느냐 받느냐 등을 할 수 있다.
2. 개체를 없앴다가 나오게 하기
개체를 사라지게 하는 함수는 hide() 이고, 나오게 하는 함수는 show() 이다.
post-box라는 id를 가진 개체에 대해, 다음과 같이 적용할 수 있다.
$('#post-box').hide();
$('#post-box').show();
보면 맨 윗단 div에 post-box가 적용되어 있으므로, 이 div에 대해 hide를 하기도 하고 show를 할수도 있는 것이다.
3. CSS 속성값을 가져오고 수정해보기
실제로 hide() 함수로 숨겼지만, 이 hide() 함수는 CSS의 어떤 값을 변경한 것 뿐이다. 어떤 작업을 했는지 확인해보자.
css() 함수를 사용한다. css(속성) 으로 쓸 수 있다.
위와 같이, hide를 한 후에 해당 post-box의 css속성 중 display를 보니 none 라는 결과가 나왔다. 이제 show를 한 후, 다시 속성을 확인해보니 block이라고 나왔다.
즉 hide 함수는 css 속성 중 display속성에 대해 none 값을 줘서 숨기는 것이고, show는 css 속성 중 display 속성에 대해 block 값을 줘서 나오게 하는 것이라고 이해할 수 있다. 이걸 jquery를 안쓰고 할려면 복잡한데, jquery를 쓰니 쉽게 할 수 있는 것이다.
이렇게 속성을 확인해야 하는 이유는, 조건문이나 반복문 등을 사용할 때, 이런 것(none, block)을 조건으로 할 수 있기 때문이다.
속성을 가져올 수 있다면, 속성을 변경할수도 있다. 아래 예시는 width 값을 바꾸는 예시이다.
현재 post-box의 width를 확인한 후, 300px로 변경했다.
원래 이랬는데,
요롷게 바뀌었다.
그렇다면, jquery를 쓰지 않고도, 속성을 변경해서 개체를 숨기거나 보이게 할 수 있다.
참고 : 여기서 개체는 안보이거나 보이는거지 없애거나 만드는 게 아니다.
4. 글자를 바꾸기
text() 함수를 사용하여 개체의 글자를 바꿀 수 있다. 원하는 대상이 되는 개체(아래 예시에서는 버튼)에 id값을 주고, text() 함수를 적용하면 글자를 바꿀 수 있다. 아래 코드는 btn-post-box라는 id를 가지고 있다.
<button onclick="openClose()" id="btn-post-box" type="button" class="btn btn-primary">포스팅 박스 열기 </button>
$('#btn-post-box').text('포스팅 박스 닫기'); 를 입력하면, 아래와 같이 변경된다.
5. html 코드 자체를 삽입하기
append() 함수를 사용하여, html 코드 자체를 삽입할 수 있다.
다음과 같이 변수를 생성한다.
let tempHtml = '<button>나는 추가될 버튼이다!</button>';
아래처럼, card-box라는 곳에 위 html 코드를 붙여넣는다. (이 상태는 html이 아니고 문자열 상태임. 이 문자열이, html에 들어가서 html이 되는 것)
$('#cards-box').append(tempHtml);
아래처럼 card-box를 찾을 수 있다.
이런식으로 붙는걸 볼 수 있다. 여러번하면, 여러개 생긴다.
이제 이런 작은 내용 말고, 하나의 카드를 넣어보자.
저기 tempHtml 옆에 <div> 로 시작하는 큰 html 값이 변수에 들어가서 해당 값을 붙여넣을 수 있다. 이 변수에는 엄청 큰 html값도 들어갈 수 있다고 한다.
카드가 붙는데, 붙는 순서가 좀 이상하다..;; 이건 이렇게부트스트랩에서 정해놓은거라 순서를 직접 조절하긴 조금 어렵다.
# 중요! : 백틱
백틱 ( ` ) 은 html코드에다가 자바스크립트 변수를 사용하고 싶을 떄, 홀따옴표가 아닌 백틱으로 감싸야 한다. 이것은 약속이므로 꼭 지켜야 한다.
여긴 백틱이 안들어간다. 내용에 자바스크립트 변수가 없으니까.
여긴 백틱이 들어간다. 자바스크립트 변수가 있으니까.
또한, 백틱 안에 html을 넣으면, 줄바꿈상관없이 한 문장으로 인식한다.
`<divclass="card">
<imgclass="card-img-top"
src="https://www.eurail.com/content/dam/images/eurail/Italy%20OCP%20Promo%20Block.adaptive.767.1535627244182.jpg"
alt="Cardimagecap">
<divclass="card-body">
<ahref="#"class="card-title">여기기사제목이들어가죠</a>
<pclass="card-text">기사의요약내용이들어갑니다.동해물과백두산이마르고닳도록하느님이보우하사우리나라만세무궁화삼천리화려강산...</p>
<pclass="card-textcomment">여기에코멘트가들어갑니다.</p>
</div>
</div>`
실습 : 나홀로 메모장에 여러가지 설정해보기
완성된 모습 : 열기 버튼을 누르면 아래 붉은 네모칸 내용이 생기게 해야 함.
여기서 핵심은 "포스팅 박스 열기" 버튼에 자바스크립트 넣는 것이다.
해당 버튼을 누르면 :
- 버튼의 글자가 변경 (열기 <-> 닫기)
- 포스팅 박스 상태 변경 (나오기 <-> 숨기기)
두 가지를 해야 한다.
1. 버튼에 onclick 속성과 함수 적용
- 아래와 같이 onclick 속성 (클릭하면 액션을 취함) 을 주고, openClose()라는 함수를 설정한다.
<button onclick="openClose()" id="btn-post-box" type="button" class="btn btn-primary">포스팅 박스 열기</button>
2. 없어졌다 보였다 할 개체인 post-box에 id 적용
아래 html이 위에 붉은네모칸 표시한 포스트박스이다. id를 post-box라고 정의했다.
3. 버튼을 눌렀을 때 발동할 함수를 생성
처음부터 post-box를 감춰두고, 누르면 열리고 누르면 닫히게 하고, 글씨도 닫기/열기 변경하도록.
4. 최종 결과물
<!Doctype html>
<html lang="ko">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="<https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css>"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
crossorigin="anonymous">
<!-- JS -->
<script src="<https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js>"></script>
<script src="<https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js>"
integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
crossorigin="anonymous"></script>
<!-- 구글폰트 -->
<link href="<https://fonts.googleapis.com/css?family=Stylish&display=swap>" rel="stylesheet">
<title>스파르타코딩클럽 | 나홀로 메모장</title>
<!-- style -->
<style type="text/css">
* {
font-family: 'Stylish', sans-serif;
}
.wrap {
width: 900px;
margin: auto;
}
.comment {
color: blue;
font-weight: bold;
}
#post-box {
width: 500px;
margin: 20px auto;
padding: 50px;
border: black solid;
border-radius: 5px;
}
</style>
<script>
function openClose() {
// id 값 post-box의 display 값이 block 이면(= 눈에 보이면)
if ($('#post-box').css('display') == 'block') {
// post-box를 가리고
$('#post-box').hide();
// 다시 버튼을 클릭하면, 박스 열기를 할 수 있게 텍스트 바꿔두기
$('#btn-post-box').text('포스팅 박스 열기');
} else {
// 아니면(눈에 보이지 않으면) post-box를 펴라
$('#post-box').show();
// 다시 버튼을 클릭하면, 박스 닫기를 할 수 있게 텍스트 바꿔두기
$('#btn-post-box').text('포스팅 박스 닫기');
}
}
</script>
</head>
<body>
<div class="wrap">
<div class="jumbotron">
<h1 class="display-4">나홀로 링크 메모장!</h1>
<p class="lead">중요한 링크를 저장해두고, 나중에 볼 수 있는 공간입니다</p>
<hr class="my-4">
<p class="lead">
<button onclick="openClose()" id="btn-post-box" type="button" class="btn btn-primary">포스팅 박스 열기
</button>
</p>
</div>
<div id="post-box" class="form-post" style="display:none"> 이부분을 위에 <style> 태그 안에 있는 $post-box 에다가 display: none 해도 됨
<div>
<div class="form-group">
<label for="post-url">아티클 URL</label>
<input id="post-url" class="form-control" placeholder="">
</div>
<div class="form-group">
<label for="post-comment">간단 코멘트</label>
<textarea id="post-comment" class="form-control" rows="2"></textarea>
</div>
<button type="button" class="btn btn-primary">기사저장</button>
</div>
</div>
<div id="cards-box" class="card-columns">
<div class="card">
<img class="card-img-top"
src="<https://www.eurail.com/content/dam/images/eurail/Italy%20OCP%20Promo%20Block.adaptive.767.1535627244182.jpg>"
alt="Card image cap">
<div class="card-body">
<a href="#" class="card-title">여기 기사 제목이 들어가죠</a>
<p class="card-text">기사의 요약 내용이 들어갑니다. 동해물과 백두산이 마르고 닳도록 하느님이 보우하사 우리나라만세 무궁화 삼천리 화려강산...</p>
<p class="card-text comment">여기에 코멘트가 들어갑니다.</p>
</div>
</div>
<div class="card">
<img class="card-img-top"
src="<https://www.eurail.com/content/dam/images/eurail/Italy%20OCP%20Promo%20Block.adaptive.767.1535627244182.jpg>"
alt="Card image cap">
<div class="card-body">
<a href="#" class="card-title">여기 기사 제목이 들어가죠</a>
<p class="card-text">기사의 요약 내용이 들어갑니다. 동해물과 백두산이 마르고 닳도록 하느님이 보우하사 우리나라만세 무궁화 삼천리 화려강산...</p>
<p class="card-text comment">여기에 코멘트가 들어갑니다.</p>
</div>
</div>
<div class="card">
<img class="card-img-top"
src="<https://www.eurail.com/content/dam/images/eurail/Italy%20OCP%20Promo%20Block.adaptive.767.1535627244182.jpg>"
alt="Card image cap">
<div class="card-body">
<a href="#" class="card-title">여기 기사 제목이 들어가죠</a>
<p class="card-text">기사의 요약 내용이 들어갑니다. 동해물과 백두산이 마르고 닳도록 하느님이 보우하사 우리나라만세 무궁화 삼천리 화려강산...</p>
<p class="card-text comment">여기에 코멘트가 들어갑니다.</p>
</div>
</div>
<div class="card">
<img class="card-img-top"
src="<https://www.eurail.com/content/dam/images/eurail/Italy%20OCP%20Promo%20Block.adaptive.767.1535627244182.jpg>"
alt="Card image cap">
<div class="card-body">
<a href="#" class="card-title">여기 기사 제목이 들어가죠</a>
<p class="card-text">기사의 요약 내용이 들어갑니다. 동해물과 백두산이 마르고 닳도록 하느님이 보우하사 우리나라만세 무궁화 삼천리 화려강산...</p>
<p class="card-text comment">여기에 코멘트가 들어갑니다.</p>
</div>
</div>
<div class="card">
<img class="card-img-top"
src="<https://www.eurail.com/content/dam/images/eurail/Italy%20OCP%20Promo%20Block.adaptive.767.1535627244182.jpg>"
alt="Card image cap">
<div class="card-body">
<a href="#" class="card-title">여기 기사 제목이 들어가죠</a>
<p class="card-text">기사의 요약 내용이 들어갑니다. 동해물과 백두산이 마르고 닳도록 하느님이 보우하사 우리나라만세 무궁화 삼천리 화려강산...</p>
<p class="card-text comment">여기에 코멘트가 들어갑니다.</p>
</div>
</div>
<div class="card">
<img class="card-img-top"
src="<https://www.eurail.com/content/dam/images/eurail/Italy%20OCP%20Promo%20Block.adaptive.767.1535627244182.jpg>"
alt="Card image cap">
<div class="card-body">
<a href="#" class="card-title">여기 기사 제목이 들어가죠</a>
<p class="card-text">기사의 요약 내용이 들어갑니다. 동해물과 백두산이 마르고 닳도록 하느님이 보우하사 우리나라만세 무궁화 삼천리 화려강산...</p>
<p class="card-text comment">여기에 코멘트가 들어갑니다.</p>
</div>
</div>
</div>
</div>
</body>
</html>
추가실습
실습1 : jqury + javascript 조합
다음과 같은 사이트를 만들고,
이름을 쓰고, 이름붙이기 버튼을 누르면 아래에 계속 누적되고, 다지우기 버튼을 누르면 다 없어지는 식.
그래서, "이름붙이기" 에 함수 , "다지우기" 에 함수 2개의 함수를 만들고, 각 함수를 버튼에 적용하면 된다.
# 참고 : 자바스크립트 내에서 변수를 쓸 때는 그냥 변수명만 명시하면 되는데, html 안에서 자바스크립트 변수를 쓸 때는 백틱`` 안에 넣어야 하고 또 변수 이름을 ${} 안에 넣어야 한다.
리스트에다가 jquery 값을 넣어야 함.
1. 인풋내용을 받아서
2. 그 내용을 html로 덧붙일 수 있어야 하고
3. 버튼을 누르면 2번이 작동해야 하고
4. 다지우기 누르면 싹 다 날림.
정답
<!doctype html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>jQuery 연습하고 가기!</title>
<!-- JQuery를 import 합니다 -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<style type="text/css">
div.question-box {
margin: 10px 0 20px 0;
}
</style>
<script>
function showName() {
let inputName = $('#input-name').val();
if (inputName == '') {
alert("아무것도 안썼쟈너..ㅜㅜ");
retrun; // 써도 되고 안써도 됐다. 뭐가 다를까?
}
let tagName = `<li>${inputName}</li>`; 실제로 붙는 쪽에 html을 보자. 딱 <li></li> 이다.
$('#names').append(tagName);
}
function removeNames() {
$('#names').empty()
// 1. names의 내부 태그를 모두 비운다.(jQuery의 $('....').empty()를 이용하면 굿!)
}
</script>
</head>
<body>
<h1>jQuery + Javascript의 조합을 연습하자!</h1>
<div class="question-box">
<h2>HTML 붙이기/지우기 연습</h2>
<h5>1. 이름을 입력하면 아래 나오게 하기</h5>
<h5>2. 다지우기 버튼을 만들기</h5>
<input id="input-name" type="text" placeholder="여기에 이름을 입력" />
<button onclick="showName()">이름 붙이기</button>
<button onclick="removeNames()">다지우기</button>
<ul id="names">
<li>김스파</li>
<li>박르탄</li>
</ul>
</div>
</body>
</html>
실습2 : 조건문 - 1,2,3,4 .. 높여가며 누른 횟수를 보여주는 onclick 함수 만들어보기
<!doctype html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Javascript를 연습하자!</title>
<style type="text/css">
div.question-box {
margin: 10px 0 20px 0;
}
</style>
<script>
// 버튼을 누른 횟수를 저장할 변수 선언
let count = 0;
function showButtonCount() {
count += 1;
if (count < 20) {
alert(`안녕! ${count}번 누르셨네요!`);
} else {
alert('앗.. 더이상 누르면 안돼버렷!');
}
}
// 1. 버튼을 누를 때마다(함수를 호출할 때마다) 누른 횟수 증가
// 2. 누른 횟수가 20 미만이면 "안녕! {{실제 누른 횟수}} 번 누르셨네요!" alert 창 띄우기
// 3. 누른 횟수가 20번 이상이면,'앗. 그만 누르세요 이제!' alert 창 띄우기
</script>
</head>
<body>
<h1>Javascript를 연습하자!</h1>
<div class="question-box">
<h2>누른 횟수를 보여주는 함수 만들기</h2>
<h5>1. 버튼을 누를 때마다(함수를 호출할 때마다) 누른 횟수 증가</h5>
<h5>2. 누른 횟수가 20 미만이면 "안녕! {{실제 누른 횟수}} 번 누르셨네요!" alert 창 띄우기</h5>
<h5>3. 누른 횟수가 20번 이상이면,'앗. 그만 누르세요 이제!' alert 창 띄우기</h5>
<button onclick="showButtonCount()">클릭</button>
</div>
</body>
</html>
실습3 : 짝수 번 눌렀을 때는 "짝짝짝👏", 홀수 번 눌렀을 때는 "홀홀홀🎅" 얼럿을 띄우는 버튼을 만들기
<!DOCTYPEhtml>
<htmllang="ko">
<head>
<metacharset="UTF-8">
<metaname="viewport"content="width=device-width,initial-scale=1.0">
<title>스파르타코딩클럽|자바스크립트연습</title>
<script>
letnum=0;
functionhandleClick(){
num+=1;
alert(`${num}번눌렀습니다.`)
if(num%2==0){//즉,짝수인경우
alert("짝짝짝");
}else{
alert("홀홀홀");
}
}
</script>
</head>
<body>
<buttononclick="handleClick()">이버튼을눌러보세요</button>
</body>
</html>
실습4 : 따릉이 정보 확인하기
다음 데이터를 크롬 개발자도구에 입력후, 개발자도구에서 진행한다.
let bikes = [
{
rackTotCnt: "7",
stationName: "101. (구)합정동 주민센터",
parkingBikeTotCnt: "4",
shared: "14",
stationLatitude: "37.54956055",
stationLongitude: "126.90575409",
stationId: "ST-3",
},
{
rackTotCnt: "22",
stationName: "102. 망원역 1번출구 앞",
parkingBikeTotCnt: "17",
shared: "5",
stationLatitude: "37.55564880",
stationLongitude: "126.91062927",
stationId: "ST-4",
},
{
rackTotCnt: "16",
stationName: "103. 망원역 2번출구 앞",
parkingBikeTotCnt: "11",
shared: "13",
stationLatitude: "37.55495071",
stationLongitude: "126.91083527",
stationId: "ST-5",
},
{
rackTotCnt: "15",
stationName: "104. 합정역 1번출구 앞",
parkingBikeTotCnt: "11",
shared: "0",
stationLatitude: "37.55062866",
stationLongitude: "126.91498566",
stationId: "ST-6",
},
{
rackTotCnt: "7",
stationName: "105. 합정역 5번출구 앞",
parkingBikeTotCnt: "1",
shared: "0",
stationLatitude: "37.55000687",
stationLongitude: "126.91482544",
stationId: "ST-7",
},
{
rackTotCnt: "12",
stationName: "106. 합정역 7번출구 앞",
parkingBikeTotCnt: "8",
shared: "8",
stationLatitude: "37.54864502",
stationLongitude: "126.91282654",
stationId: "ST-8",
},
{
rackTotCnt: "7",
stationName: "107. 신한은행 서교동금융센터점 앞",
parkingBikeTotCnt: "5",
shared: "14",
stationLatitude: "37.55751038",
stationLongitude: "126.91850281",
stationId: "ST-9",
},
{
rackTotCnt: "12",
stationName: "108. 서교동 사거리",
parkingBikeTotCnt: "9",
shared: "8",
stationLatitude: "37.55274582",
stationLongitude: "126.91861725",
stationId: "ST-10",
},
{
rackTotCnt: "12",
stationName: "109. 제일빌딩 앞",
parkingBikeTotCnt: "8",
shared: "33",
stationLatitude: "37.54769135",
stationLongitude: "126.91998291",
stationId: "ST-11",
},
{
rackTotCnt: "22",
stationName: "110. 사천교",
parkingBikeTotCnt: "16",
shared: "5",
stationLatitude: "37.56819916",
stationLongitude: "126.91784668",
stationId: "ST-13",
},
{
rackTotCnt: "12",
stationName: "111. 상수역 2번출구 앞",
parkingBikeTotCnt: "9",
shared: "25",
stationLatitude: "37.54787064",
stationLongitude: "126.92353058",
stationId: "ST-15",
},
{
rackTotCnt: "12",
stationName: "112. 극동방송국 앞",
parkingBikeTotCnt: "8",
shared: "25",
stationLatitude: "37.54920197",
stationLongitude: "126.92320251",
stationId: "ST-16",
},
{
rackTotCnt: "27",
stationName: "113. 홍대입구역 2번출구 앞",
parkingBikeTotCnt: "24",
shared: "22",
stationLatitude: "37.55749893",
stationLongitude: "126.92380524",
stationId: "ST-18",
},
{
rackTotCnt: "17",
stationName: "114. 홍대입구역 8번출구 앞",
parkingBikeTotCnt: "14",
shared: "129",
stationLatitude: "37.55706024",
stationLongitude: "126.92442322",
stationId: "ST-20",
},
{
rackTotCnt: "17",
stationName: "115. 사루비아 빌딩 앞",
parkingBikeTotCnt: "1",
shared: "0",
stationLatitude: "37.55893326",
stationLongitude: "126.92711639",
stationId: "ST-12",
},
{
rackTotCnt: "7",
stationName: "116. 일진아이윌아파트 옆",
parkingBikeTotCnt: "1",
shared: "0",
stationLatitude: "37.56454086",
stationLongitude: "126.92707062",
stationId: "ST-14",
},
{
rackTotCnt: "27",
stationName: "117. 홍은사거리",
parkingBikeTotCnt: "9",
shared: "0",
stationLatitude: "37.59115982",
stationLongitude: "126.94132996",
stationId: "ST-17",
},
{
rackTotCnt: "12",
stationName: "118. 광흥창역 2번출구 앞",
parkingBikeTotCnt: "9",
shared: "67",
stationLatitude: "37.54773331",
stationLongitude: "126.93176270",
stationId: "ST-19",
},
{
rackTotCnt: "12",
stationName: "119. 서강나루 공원",
parkingBikeTotCnt: "9",
shared: "17",
stationLatitude: "37.54528427",
stationLongitude: "126.93105316",
stationId: "ST-21",
},
{
rackTotCnt: "7",
stationName: "120. 신수동 사거리",
parkingBikeTotCnt: "3",
shared: "0",
stationLatitude: "37.54524231",
stationLongitude: "126.93411255",
stationId: "ST-22",
},
{
rackTotCnt: "17",
stationName: "121. 마포소방서 앞",
parkingBikeTotCnt: "11",
shared: "24",
stationLatitude: "37.54976654",
stationLongitude: "126.93317413",
stationId: "ST-23",
},
{
rackTotCnt: "12",
stationName: "122. 신성기사식당 앞",
parkingBikeTotCnt: "6",
shared: "0",
stationLatitude: "37.54745865",
stationLongitude: "126.93837738",
stationId: "ST-24",
},
{
rackTotCnt: "22",
stationName: "123. 문화촌 공원",
parkingBikeTotCnt: "7",
shared: "0",
stationLatitude: "37.59432983",
stationLongitude: "126.94738770",
stationId: "ST-25",
},
{
rackTotCnt: "22",
stationName: "124. 서강대 정문 건너편",
parkingBikeTotCnt: "7",
shared: "0",
stationLatitude: "37.55113983",
stationLongitude: "126.93698883",
stationId: "ST-26",
},
{
rackTotCnt: "17",
stationName: "125. 서강대 남문 옆",
parkingBikeTotCnt: "13",
shared: "0",
stationLatitude: "37.54948425",
stationLongitude: "126.93894958",
stationId: "ST-27",
},
{
rackTotCnt: "22",
stationName: "126. 서강대 후문 옆",
parkingBikeTotCnt: "17",
shared: "5",
stationLatitude: "37.55041122",
stationLongitude: "126.94384766",
stationId: "ST-28",
},
{
rackTotCnt: "22",
stationName: "128. 신촌역(2호선) 1번출구 옆",
parkingBikeTotCnt: "14",
shared: "5",
stationLatitude: "37.55549622",
stationLongitude: "126.93634033",
stationId: "ST-30",
},
{
rackTotCnt: "17",
stationName: "129. 신촌역(2호선) 6번출구 옆",
parkingBikeTotCnt: "8",
shared: "0",
stationLatitude: "37.55505371",
stationLongitude: "126.93756866",
stationId: "ST-31",
},
{
rackTotCnt: "12",
stationName: "130. 신촌역(2호선) 7번출구 앞",
parkingBikeTotCnt: "8",
shared: "17",
stationLatitude: "37.55485916",
stationLongitude: "126.93615723",
stationId: "ST-32",
},
{
rackTotCnt: "25",
stationName: "131. 증산2교",
parkingBikeTotCnt: "17",
shared: "4",
stationLatitude: "37.58417130",
stationLongitude: "126.91110229",
stationId: "ST-33",
},
{
rackTotCnt: "17",
stationName: "133. 해담는다리",
parkingBikeTotCnt: "11",
shared: "12",
stationLatitude: "37.58203125",
stationLongitude: "126.90899658",
stationId: "ST-35",
},
{
rackTotCnt: "10",
stationName: "134. 연세로 명물길",
parkingBikeTotCnt: "6",
shared: "20",
stationLatitude: "37.55789185",
stationLongitude: "126.93807983",
stationId: "ST-36",
},
{
rackTotCnt: "12",
stationName: "135. 명물길 원형무대 앞",
parkingBikeTotCnt: "10",
shared: "0",
stationLatitude: "37.55910110",
stationLongitude: "126.93917847",
stationId: "ST-37",
},
{
rackTotCnt: "9",
stationName: "136. 대흥동 주민센터",
parkingBikeTotCnt: "1",
shared: "11",
stationLatitude: "37.55600357",
stationLongitude: "126.94229889",
stationId: "ST-38",
},
{
rackTotCnt: "12",
stationName: "137. NH농협 신촌지점 앞",
parkingBikeTotCnt: "4",
shared: "0",
stationLatitude: "37.55681229",
stationLongitude: "126.94318390",
stationId: "ST-39",
},
{
rackTotCnt: "12",
stationName: "138. 신촌동 제1공영주차장 앞",
parkingBikeTotCnt: "7",
shared: "25",
stationLatitude: "37.55917740",
stationLongitude: "126.93452454",
stationId: "ST-40",
},
{
rackTotCnt: "15",
stationName: "139. 연세대 정문 건너편",
parkingBikeTotCnt: "13",
shared: "7",
stationLatitude: "37.55979538",
stationLongitude: "126.93447876",
stationId: "ST-43",
},
{
rackTotCnt: "22",
stationName: "140. 이화여대 후문",
parkingBikeTotCnt: "6",
shared: "0",
stationLatitude: "37.56000900",
stationLongitude: "126.94073486",
stationId: "ST-41",
},
{
rackTotCnt: "22",
stationName: "141. 연대 대운동장 옆",
parkingBikeTotCnt: "13",
shared: "5",
stationLatitude: "37.56238174",
stationLongitude: "126.93264771",
stationId: "ST-42",
},
{
rackTotCnt: "13",
stationName: "142. 아현역 4번출구 앞",
parkingBikeTotCnt: "1",
shared: "0",
stationLatitude: "37.55720139",
stationLongitude: "126.95566559",
stationId: "ST-200",
},
{
rackTotCnt: "11",
stationName: "143. 공덕역 2번출구",
parkingBikeTotCnt: "7",
shared: "0",
stationLatitude: "37.54457855",
stationLongitude: "126.95021820",
stationId: "ST-201",
},
{
rackTotCnt: "12",
stationName: "144. 공덕역 8번출구",
parkingBikeTotCnt: "6",
shared: "0",
stationLatitude: "37.54357910",
stationLongitude: "126.95132446",
stationId: "ST-202",
},
{
rackTotCnt: "11",
stationName: "145. 공덕역 5번출구",
parkingBikeTotCnt: "8",
shared: "36",
stationLatitude: "37.54425049",
stationLongitude: "126.95163727",
stationId: "ST-203",
},
{
rackTotCnt: "14",
stationName: "146. 마포역 2번출구 뒤",
parkingBikeTotCnt: "6",
shared: "0",
stationLatitude: "37.53993607",
stationLongitude: "126.94582367",
stationId: "ST-204",
},
{
rackTotCnt: "9",
stationName: "147. 마포역 4번출구 뒤",
parkingBikeTotCnt: "4",
shared: "0",
stationLatitude: "37.53927231",
stationLongitude: "126.94591522",
stationId: "ST-205",
},
{
rackTotCnt: "17",
stationName: "150. 서강대역 2번출구 앞",
parkingBikeTotCnt: "13",
shared: "65",
stationLatitude: "37.55295563",
stationLongitude: "126.93434143",
stationId: "ST-207",
},
{
rackTotCnt: "12",
stationName: "151. 망원1동주민센터",
parkingBikeTotCnt: "11",
shared: "58",
stationLatitude: "37.55568695",
stationLongitude: "126.90554810",
stationId: "ST-208",
},
{
rackTotCnt: "32",
stationName: "152. 마포구민체육센터 앞",
parkingBikeTotCnt: "8",
shared: "31",
stationLatitude: "37.55661011",
stationLongitude: "126.89801788",
stationId: "ST-209",
},
{
rackTotCnt: "12",
stationName: "153. 성산2교 사거리",
parkingBikeTotCnt: "7",
shared: "17",
stationLatitude: "37.56469727",
stationLongitude: "126.91261292",
stationId: "ST-210",
},
{
rackTotCnt: "15",
stationName: "154. 마포구청역 ",
parkingBikeTotCnt: "9",
shared: "0",
stationLatitude: "37.56090927",
stationLongitude: "126.90549469",
stationId: "ST-211",
},
{
rackTotCnt: "17",
stationName: "155. 가좌역1 번출구 뒤",
parkingBikeTotCnt: "14",
shared: "0",
stationLatitude: "37.56855011",
stationLongitude: "126.91451263",
stationId: "ST-212",
},
{
rackTotCnt: "12",
stationName: "156. 서울서부지방법원 앞",
parkingBikeTotCnt: "9",
shared: "0",
stationLatitude: "37.54990387",
stationLongitude: "126.95514679",
stationId: "ST-213",
},
{
rackTotCnt: "14",
stationName: "157. 애오개역 4번출구 앞",
parkingBikeTotCnt: "1",
shared: "0",
stationLatitude: "37.55300140",
stationLongitude: "126.95668793",
stationId: "ST-214",
},
{
rackTotCnt: "17",
stationName: "158. 독립문 어린이 공원",
parkingBikeTotCnt: "1",
shared: "0",
stationLatitude: "37.57125854",
stationLongitude: "126.96047974",
stationId: "ST-215",
},
{
rackTotCnt: "9",
stationName: "159. 이대역 4번 출구",
parkingBikeTotCnt: "1",
shared: "0",
stationLatitude: "37.55695343",
stationLongitude: "126.94634247",
stationId: "ST-216",
},
{
rackTotCnt: "22",
stationName: "160. 북아현동 가구거리",
parkingBikeTotCnt: "15",
shared: "0",
stationLatitude: "37.55754852",
stationLongitude: "126.95938110",
stationId: "ST-217",
},
{
rackTotCnt: "10",
stationName: "161. 무악재역1번 출구",
parkingBikeTotCnt: "0",
shared: "0",
stationLatitude: "37.58224487",
stationLongitude: "126.95064545",
stationId: "ST-218",
},
{
rackTotCnt: "17",
stationName: "162. 봉원고가차도 밑",
parkingBikeTotCnt: "8",
shared: "0",
stationLatitude: "37.56526947",
stationLongitude: "126.94624329",
stationId: "ST-219",
},
{
rackTotCnt: "9",
stationName: "163. 명지전문대학교 정문 앞",
parkingBikeTotCnt: "0",
shared: "0",
stationLatitude: "37.58369827",
stationLongitude: "126.92496490",
stationId: "ST-220",
},
{
rackTotCnt: "12",
stationName: "164. 북가좌1동 주민센터 ",
parkingBikeTotCnt: "7",
shared: "25",
stationLatitude: "37.57447815",
stationLongitude: "126.91004944",
stationId: "ST-221",
},
{
rackTotCnt: "22",
stationName: "165. 중앙근린공원",
parkingBikeTotCnt: "9",
shared: "0",
stationLatitude: "37.57513809",
stationLongitude: "126.91394043",
stationId: "ST-222",
},
{
rackTotCnt: "22",
stationName: "166. 가재울 초등학교",
parkingBikeTotCnt: "6",
shared: "0",
stationLatitude: "37.57327652",
stationLongitude: "126.91967773",
stationId: "ST-223",
},
{
rackTotCnt: "17",
stationName: "167. 연가초등학교 옆",
parkingBikeTotCnt: "12",
shared: "0",
stationLatitude: "37.57946014",
stationLongitude: "126.91712952",
stationId: "ST-224",
},
{
rackTotCnt: "17",
stationName: "169. 북가좌 삼거리",
parkingBikeTotCnt: "6",
shared: "0",
stationLatitude: "37.57300186",
stationLongitude: "126.90779877",
stationId: "ST-226",
},
{
rackTotCnt: "12",
stationName: "170. 가재울 뉴타운 주유소 옆",
parkingBikeTotCnt: "9",
shared: "33",
stationLatitude: "37.57311249",
stationLongitude: "126.92244720",
stationId: "ST-227",
},
{
rackTotCnt: "12",
stationName: "171. 임광빌딩 앞",
parkingBikeTotCnt: "9",
shared: "8",
stationLatitude: "37.56472397",
stationLongitude: "126.96727753",
stationId: "ST-228",
},
{
rackTotCnt: "10",
stationName: "173. 서대문역 8번출구 앞",
parkingBikeTotCnt: "4",
shared: "0",
stationLatitude: "37.56477737",
stationLongitude: "126.96614838",
stationId: "ST-230",
},
{
rackTotCnt: "22",
stationName: "175. 홍연2교옆",
parkingBikeTotCnt: "6",
shared: "0",
stationLatitude: "37.57807159",
stationLongitude: "126.93081665",
stationId: "ST-231",
},
{
rackTotCnt: "12",
stationName: "176. 명지대학교 도서관",
parkingBikeTotCnt: "0",
shared: "0",
stationLatitude: "37.58109665",
stationLongitude: "126.92402649",
stationId: "ST-555",
},
{
rackTotCnt: "10",
stationName: "177. 북가좌 초등학교",
parkingBikeTotCnt: "1",
shared: "0",
stationLatitude: "37.57767487",
stationLongitude: "126.90980530",
stationId: "ST-345",
},
{
rackTotCnt: "12",
stationName: "178. 증산3교 앞",
parkingBikeTotCnt: "0",
shared: "0",
stationLatitude: "37.57987595",
stationLongitude: "126.90634918",
stationId: "ST-349",
},
{
rackTotCnt: "17",
stationName: "179. 가좌역 4번출구 앞",
parkingBikeTotCnt: "14",
shared: "47",
stationLatitude: "37.56912231",
stationLongitude: "126.91479492",
stationId: "ST-232",
},
{
rackTotCnt: "12",
stationName: "180. 충정로역 7번출구 아래",
parkingBikeTotCnt: "10",
shared: "8",
stationLatitude: "37.55996704",
stationLongitude: "126.96246338",
stationId: "ST-233",
},
{
rackTotCnt: "17",
stationName: "181. 망원초록길 입구",
parkingBikeTotCnt: "9",
shared: "0",
stationLatitude: "37.55134201",
stationLongitude: "126.90267181",
stationId: "ST-339",
},
{
rackTotCnt: "12",
stationName: "182. 망원2빗물펌프장 앞",
parkingBikeTotCnt: "7",
shared: "0",
stationLatitude: "37.55156708",
stationLongitude: "126.90284729",
stationId: "ST-340",
},
{
rackTotCnt: "17",
stationName: "183. 하늘채코오롱아파트 건너편",
parkingBikeTotCnt: "10",
shared: "0",
stationLatitude: "37.56516647",
stationLongitude: "126.91939545",
stationId: "ST-341",
},
{
rackTotCnt: "11",
stationName: "184. SK망원동주유소 건너편",
parkingBikeTotCnt: "4",
shared: "0",
stationLatitude: "37.55894852",
stationLongitude: "126.90775299",
stationId: "ST-342",
},
{
rackTotCnt: "17",
stationName: "185. 마포 신수공원 앞",
parkingBikeTotCnt: "5",
shared: "0",
stationLatitude: "37.54254532",
stationLongitude: "126.93429565",
stationId: "ST-343",
},
{
rackTotCnt: "42",
stationName: "186. 월드컵공원",
parkingBikeTotCnt: "22",
shared: "10",
stationLatitude: "37.56396484",
stationLongitude: "126.89820862",
stationId: "ST-344",
},
{
rackTotCnt: "12",
stationName: "188. 홍은동 정원여중 입구",
parkingBikeTotCnt: "2",
shared: "0",
stationLatitude: "37.58638763",
stationLongitude: "126.93512726",
stationId: "ST-346",
},
{
rackTotCnt: "12",
stationName: "191. 서우빌딩(바른학원)",
parkingBikeTotCnt: "6",
shared: "0",
stationLatitude: "37.57889175",
stationLongitude: "126.91073608",
stationId: "ST-347",
},
{
rackTotCnt: "12",
stationName: "192. 연서어린이공원",
parkingBikeTotCnt: "0",
shared: "0",
stationLatitude: "37.57222748",
stationLongitude: "126.92306519",
stationId: "ST-348",
},
{
rackTotCnt: "12",
stationName: "194. 증산교 앞",
parkingBikeTotCnt: "2",
shared: "0",
stationLatitude: "37.57731628",
stationLongitude: "126.90296936",
stationId: "ST-350",
},
{
rackTotCnt: "12",
stationName: "195. 모래내고가차도 ",
parkingBikeTotCnt: "6",
shared: "42",
stationLatitude: "37.56765747",
stationLongitude: "126.91780853",
stationId: "ST-351",
},
{
rackTotCnt: "12",
stationName: "196. 연희교차로 인근",
parkingBikeTotCnt: "1",
shared: "0",
stationLatitude: "37.56612015",
stationLongitude: "126.92589569",
stationId: "ST-352",
},
{
rackTotCnt: "17",
stationName: "198. 충정2교",
parkingBikeTotCnt: "15",
shared: "0",
stationLatitude: "37.56213760",
stationLongitude: "126.96377563",
stationId: "ST-354",
},
{
rackTotCnt: "32",
stationName: "199. 서울 월드컵 경기장",
parkingBikeTotCnt: "7",
shared: "0",
stationLatitude: "37.56684494",
stationLongitude: "126.89644623",
stationId: "ST-443",
},
{
rackTotCnt: "22",
stationName: "200. 국회의원회관",
parkingBikeTotCnt: "8",
shared: "0",
stationLatitude: "37.52841568",
stationLongitude: "126.91391754",
stationId: "ST-45",
},
{
rackTotCnt: "17",
stationName: "201. 진미파라곤 앞",
parkingBikeTotCnt: "9",
shared: "6",
stationLatitude: "37.53123856",
stationLongitude: "126.92133331",
stationId: "ST-46",
},
{
rackTotCnt: "32",
stationName: "202. 국민일보 앞",
parkingBikeTotCnt: "21",
shared: "19",
stationLatitude: "37.52881622",
stationLongitude: "126.92453003",
stationId: "ST-47",
},
{
rackTotCnt: "17",
stationName: "203. 국회의사당역 3번출구 옆",
parkingBikeTotCnt: "14",
shared: "76",
stationLatitude: "37.52805710",
stationLongitude: "126.91870117",
stationId: "ST-51",
},
{
rackTotCnt: "15",
stationName: "204. 국회의사당역 5번출구 옆",
parkingBikeTotCnt: "10",
shared: "53",
stationLatitude: "37.52816391",
stationLongitude: "126.91702271",
stationId: "ST-50",
},
{
rackTotCnt: "22",
stationName: "205. 산업은행 앞",
parkingBikeTotCnt: "13",
shared: "0",
stationLatitude: "37.52626419",
stationLongitude: "126.92050934",
stationId: "ST-52",
},
{
rackTotCnt: "37",
stationName: "206. KBS 앞",
parkingBikeTotCnt: "24",
shared: "11",
stationLatitude: "37.52466583",
stationLongitude: "126.91802216",
stationId: "ST-53",
},
{
rackTotCnt: "42",
stationName: "207. 여의나루역 1번출구 앞",
parkingBikeTotCnt: "16",
shared: "0",
stationLatitude: "37.52698898",
stationLongitude: "126.93209839",
stationId: "ST-73",
},
{
rackTotCnt: "14",
stationName: "209. 유진투자증권빌딩 앞",
parkingBikeTotCnt: "12",
shared: "14",
stationLatitude: "37.52461243",
stationLongitude: "126.92783356",
stationId: "ST-55",
},
{
rackTotCnt: "23",
stationName: "210. IFC몰",
parkingBikeTotCnt: "16",
shared: "13",
stationLatitude: "37.52606583",
stationLongitude: "126.92553711",
stationId: "ST-56",
},
{
rackTotCnt: "15",
stationName: "211. 여의도역 4번출구 옆",
parkingBikeTotCnt: "2",
shared: "0",
stationLatitude: "37.52222824",
stationLongitude: "126.92463684",
stationId: "ST-57",
},
{
rackTotCnt: "37",
stationName: "212. 여의도역 1번출구 옆",
parkingBikeTotCnt: "9",
shared: "0",
stationLatitude: "37.52136230",
stationLongitude: "126.92346191",
stationId: "ST-58",
},
];
질문1 : 5대 이하 정류장의 이름 출력
for (let i = 0 ; i < bikes.length ; i++) {
if (bikes[i]["parkingBikeTotCnt"] <= 5) {
console.log(bikes[i]["stationName"]);
}
}
질문2 : 입력한 자전거 대수 이하 정류장의 이름을 출력하는 함수를 만들어주세요.
function checkcount(countNum) {
for (let i = 0; i < bikes.length; i++) {
if (bikes[i]["parkingBikeTotCnt"] <= countNum) {
let station = bikes[i]["stationName"];
console.log("현재 " + countNum + "대 이하 정류장은 : " + station + " 입니다.")
}
}
}
실습5 : 입력받은 칸이 빈 칸이면 경고 메시지를 띄우고, 그렇지 않으면 alert(입력값) 띄우기
<!Doctype html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>jQuery 연습하고 가기!</title>
<!-- JQuery를 import 합니다 -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<style type="text/css">
div.question-box {
margin: 10px 0 20px 0;
}
</style>
<script>
function isEmpty() {
let tempChar = $('#input-value').val();
if (tempChar != '') {
alert(tempChar);
} else {
alert("글자를 입력해 주세요")
}
}
</script>
</head>
<body>
<h1>jQuery + Javascript의 조합을 연습하자!</h1>
<div class="question-box">
<h2>빈칸 체크 함수 만들기</h2>
<h5>1-1. 버튼을 눌렀을 때 입력한 글자로 얼럿 띄우기</h5>
<h5>[완성본]1-2. 버튼을 눌렀을 때 칸에 아무것도 없으면 "입력하세요!" 얼럿 띄우기</h5>
<input id="input-value" type="text"/>
<button onclick="isEmpty()">클릭</button>
</div>
</body>
</html>
실습6 : 입력받은 이메일 형식이 유효한지 확인하기 (난이도 : ⭐️⭐️⭐️⭐️)
<!Doctype html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>jQuery 연습하고 가기!</title>
<!-- JQuery를 import 합니다 -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<style type="text/css">
div.question-box {
margin: 10px 0 20px 0;
}
</style>
<script>
function validateEmail() {
let mailAddress = $('#input-email').val();
if (mailAddress.includes('@')) {
let domain = mailAddress.split('@')[1].split('.')[0];
alert(domain);
} else {
alert('이메일 주소 형식이 아니네용?')
}
// 1. input-email 값을 가져온다.
// 2. 만약 가져온 값에 @가 있으면 (includes 이용하기 - 찾아보자!)
// 3. contact@gmail.com -> gmail 만 추출해서
// 4. alert(도메인 값);으로 띄우기
// 5. 만약 이메일이 아니면 '이메일이 아닙니다.' 라는 얼럿 띄우기
}
</script>
</head>
<body>
<h1>jQuery + Javascript의 조합을 연습하자!</h1>
<div class="question-box">
<h2>이메일 판별 함수 만들기</h2>
<h5>1. 버튼을 눌렀을 때 입력받은 이메일로 얼럿 띄우기</h5>
<h5>2. 이메일이 아니면(@가 없으면) '이메일이 아닙니다'라는 얼럿 띄우기</h5>
<h5>[완성본]3. 이메일 도메인만 얼럿 띄우기</h5>
<input id="input-email" type="text"/>
<button onclick="validateEmail()">클릭</button>
</div>
</body>
</html>
Ajax 통신과 API (application progamming interface)
ajax는 자바스크립트로 클라이언트와 서버가 통신하는 방식이다. 클라이언트가 서버에 데이터를 요청하고, 서버가 응답한 데이터를 받아 조작할 수 있다. 이 때 데이터 통신을 수행할 때 api를 통해서 수행한다.
API는 특정 프로그램을 쓰고 싶을 때 접근하는 인터페이스, 규칙이다. 서버쪽에서 api를 만들어 놓으며, 클라이언트는 이 api에 맞춰서 클라이언트 단으로 요청한다. 즉, 해당 데이터를 외부에서 접근할 수 있게끔 하나의 통로를 만든 것이며 규칙이 있다.
기본적으로 api는 http 주소이다. 아래 예시는 서울시 오픈API 중 하나인 실시간 대기 환경정보 API이다.
http://openapi.seoul.go.kr:8088/6d4d776b466c656533356a4b4b5872/json/RealtimeCityAir/1/99
일반 텍스트로 복잡하게 나온다면, jsonview라는 크롬 확장 프로그램을 설치하면 스샷과 같이 보기좋게 볼 수 있다. 사실상 필수.
https://chrome.google.com/webstore/detail/jsonview/chklaanhfefbnpoihckbnefhakgolnmc?hl=ko
이러한 URL을 접속한 것 자체가, 서버에 접속해서 데이터를 요청하는 행위이다.
# 참고 : 해당 API 페이지에서 -를 누르면 내용을 숨기거나 열 수 있다.
API 상세정보 확인하기
이 내용들은 api 제작처에서 정의하는 내용이다. 이것은 다 서울시에서 정의한것이다.
http://openapi.seoul.go.kr:8088/6d4d776b466c656533356a4b4b5872/json/RealtimeCityAir/1/99
6d4d 로 시작하는 건 인증키이다.
/json 은 json방식으로 가져오라는 것.
realtimeCityAir 은 해당 api의 이름
/ 1/99 는 1~99페이지부터 가져오라는것.
더 자세히 알기 위해, 서울시 api 자료를 보면 어떻게 api에 접근할지 나와있다. 이 api문서를 보면, 어떻게 사용하는지 무슨 정보를 쓰는지 어떻게 받는지 등을 확인할 수 있다. 사실 API를 쓰기 전는 당연히 이러한 문서를 봐야 한다.
http://data.seoul.go.kr/dataList/OA-15493/A/1/datasetView.do
인증키는 따로 신청해서 받아야 함.
맨뒤에 /1/5 는 1페이지부터 5페이지까지.
api는 무료 유료가 있고, 무료는 데이터 받아오는데 시간이 좀 걸릴 수 있으니 업데이트 하고 조금 기다려야 한다.
여러가지 API
API를 를 통해, 데이터를 가져다 쓸 수 있거나 기능을 편하게 사용할 수 있다. 대표적인 OpenAPI(공개API)로는 아래 예시와 함께 여러가지가 있다.
구글 API, 네이버 API, 카카오 API
서울 열린 데이터 광장(https://data.seoul.go.kr/),
공공데이터 포털(https://www.data.go.kr/)
경기도 오픈API
무료로 사용할 수 있는 API 모음(https://github.com/public-apis/public-apis)
json 데이터 형식
데이터 형식을 여러가지 종류가 있다. xml, excel, json 등등 이 중 json 형식은 실시간 데이터 형식에 많이 사용된다. 그 외에도 여러 용도가 많다. key:value 형태의 데이터 포맷이다. 자바스크립트 딕셔너리와 매우 유사하다. 위의 서울시 대기환경정보 내용의 형식이 json 형식이며, 딕셔너리와 리스트가 조합된 형태이다. 이렇게 "구조화"된 데이터를 주고받는다.
여기서는, row라는 key 값에 리스트 형태의 딕셔너리들이 value로써 들어가있다. 여기서 특정 데이터를 접근하려면 어떻게 해야할까?
일단, RealtimeCityAir 는 {}중괄호를 사용하므로딕셔너리이다.
그 아래에는 list_total_count , RESULT, row 라는 총 3가지의 key값이 있다.
list_total_count라는 key는 정수형 값인 25라는 value로 끝난다.
RESULT라는 KEY는 딕셔너리형 값으로써, CODE, MESSAGE 라는 KEY 2개를 가진다.
row라는 키는 []대괄호를 사용하므로 리스트형 값이며, 그 리스트에 딕셔너리형이 들어가있는 형태를 가진다.
다시 정리하면, RealtimeCityAir의 row의 0번째리스트의 MSRSTE_NM 값은 "중구" 가 된다.
API에서 클라이언트 <-> 서버 요청 모델
서버가 열어놓은 API에 클라이언트가 연결하여 요청을 하고 응답을 받는다. API는 은행창구와 비슷하며, 기업고객/개인고객, 대출/예금 등 다르듯이 요청 방식이 정해져 있고 그 방식에 따라 다르게 동작한다.
API의 요청방식은 많은 종류가 있지만 대표적으로 GET와 POST가 있다. 또 다른 방식들은 아래 링크에서 자세히 확인할 수 있다.
https://developer.mozilla.org/ko/docs/Web/HTTP/Methods
HTTP 요청 메서드
HTTP는 요청 메서드를 정의하여, 주어진 리소스에 수행하길 원하는 행동을 나타냅니다. 간혹 요청 메서드를 "HTTP 동사"라고 부르기도 합니다. 각각의 메서드는 서로 다른 의미를 구현하지만, 일부
developer.mozilla.org
브라우저는 http라는 프로토콜을 따른다. http는 클라이언트와 서버가 데이터를 서로 전송하기 위한 규칙이라고 이해하면 된다. 즉 GET, POST method들은 http 프로토콜의 방식 종류이다. http 통신에서 클라이언트는 서버의 api에게 request를 보내고, 데이터들(HTML, CSS, JS) 등을 response 받게 된다.
GET : 통상적으로 단순히 클라이언트가 서버에 접근하여 데이터를 조회할 때 사용
POST : 통상적으로 서버에 데이터 생성,변경,삭제를 요청할 때 사용. 서버에 데이터가 변경된다.
여기서 "통상적으로" 라는 것은, 사실 GET과 POST가 역할이 확실하게 정해져있다기 보단 통상적으로 데이터 조회를 할 때는 GET을 쓰기 때문에 그렇게 썼다. 그렇다면 이것을 누가 정하는가? 클라이언트 프로그래머와 서버 프로그래머가 미리 정해두는 것이다.
GET 톺아보기
통상적으로, 데이터를 조회(read) 할 때 사용된다. 예를들어, 영화 목록 조회라던지..
내가 어디 사이트에 들어갈려고 링크를 클릭하면, 그 행위가 http 통신 규약을 지켜서 GET 요청을 한 것이다. 다음 2가지 예시 주소를 보자. 이 주소에서 중요한 것은 ? 와 & 이다.
? : 여기서부터 전달할 데이터가 작성된다는 의미 (전달할 데이터는 항상 key=value 값 형태이다. 예 : google.com?q=북극곰)
& : 전달할 데이터가 더 있다는 의미
https:// - https 통신규약으로 통신한다.
movie.naver.com - 네이버 영화 주소로 들어간다. 요게 은행주소라고 생각하면 됨.
/movie/bi/mi/basic.nhn - 물음표 전까지이며, 이게 api 주소이다. 요게 창구이름이라고 생각하면 됨
code=161967 - code라는 key로, value 171967을 가지고 온 것이다. 만약 code가 아니라, 임의로 moviecode 로 하면? 안된다. 사전에 서버에서 code를 정의한 것이기 때문이다.
google.com - 구글 주소
/search - search api에 다음 정보를 전달한다.
q=해리포터 : 검색어 q의 값은 해리포터이다.
sourceid=chrome : 브라우저 정보 sourceid의 값은 chrome
ie=UTF-8 : 인코딩 정보 ie의 값은 UTF-8 이다.
이런식이다. 여기서 q가 뭔지, code가 뭔지, sourceid가 뭔지 이런것을 모두 서버가 정하는 것이다. 이런게 api이며 약속이다. 만약 서버단에서 정의하지 않은 값을 쓴다면, 예를들어 q 대신 qwer=해리포터 이런식으로 하면 서버에서 인식이 안되므로 (혹시나;; 서버단에서 qwer를 정의했을 수도 있겠지만 그건 제외) 그냥 주소에서 제외되게 된다.
다시 정리하면, 같은 서버주소와 api라도 값을 다르게 주면 결과가 다르게 나온다는 것을 이해할 수 있다.
# 다시한번 : code라는 이름으로 영화번호 데이터를 전달해주자라는것은 누가 정하는가?
프론트엔드 개발자와 백엔드 개발자가 미리 정해둔 약속이다.
- 백엔드 : 서버는 code로 영화번호 정보를 받는다고 정할게.
- 프론트엔드 : ㅇㅋ 그러면 클라이언트에서는 code라는 이름으로 영화번호를 넣어서 요청할게.
post란?
- 통상적으로, 데이터 생성/변경/삭제 (create/update/delete) 요청을 할 때 사용
- 예를들어, 회원가입, 회원탈퇴, 비밀번호 수정 등
- get와는 다르게 데이터를 전달할 때 주소에는 보이지 않으며, html body에 key:value 형태로 전달한다
서버 통신방식
여기서 서버 통신은, 위에서 http의 request - response 를 말하는 것이다. 이러한 방식은 동기/비동기 방식으로 나뉜다.
- 동기 : 작업을 하나 하고, 그 작업이 다 끝나야만 다음 작업을 할 수 있다.
- 비동기 : 작업 요청을 하고 결과가 오지 않아도 다른 작업을 처리. 즉 병렬 처리이다. 자원을 효율적으로 활용할 수 있다.
동기 방식은 반드시 1이 끝나야 2를 실행하고, 2가 끝나면 3을 실행하는 방식이다. 즉 시간이 많이 걸린다. 비동기 방식은 1,2,3,4를 동시에 수행한다. 동기방식인 경우 클라이언트가 서버에 연결해서 뭔가를 하고 있는데, 서버에서 페이지를 업데이트해버리면 문제가 생길 수 있다.
ajax는 비동기방식을 사용한다. ajax는 서버에 요청해놓고 응답 오기 전까지 다른 작업을 처리한다. 응답이 오면, 그 때 정해놓은 함수 (콜백함수 ; callback function)를 호출해 실행한다.
비동기 방식 덕분에 ajax를 사용하면 웹페이지 전체를 새로고침하지 않아도 작업을 수행할 수 있다. 즉 동작(event)가 일어났을 때, 전체 페이지가 아닌 일부분만 업데이트 할 수 있는 것.
ajax 사용하기
사전준비
ajax는 여러가지 방법으로 사용할 수 있는데, 그중 하나는 jquery를 사용하는 것이다. jquery에 ajax를 쓸수 있게 구현되어 있다. jquery를 사용하여 ajax를 해당 페이지에 import해야 한다. css와 동일한 방식이다.
페이지의 <head> 부분에 아래 부분을 넣는다.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
만약 ajax가 import 되지 않으면, 다음과 같이 메시지가 뜨게 된다.
# 참고 : jquery가 min 버전이 아닌 slim 버전이면 ajax가 포함되어 있지 않다. 그래서 min으로 할 것.
사용하기 : 구문
다음과 같이 type, url, data, success 4가지 요소로 이루어져 있다.
$.ajax({
type: "GET", // GET 방식으로 요청한다.
url: "http://openapi.seoul.go.kr:8088/6d4d776b466c656533356a4b4b5872/json/RealtimeCityAir/1/99",
data: {}, // 요청하면서 함께 줄 데이터 (GET 요청시엔 비워두세요)
success: function(response){ // 서버에서 준 결과를 response라는 변수에 담음
console.log(response) // 서버에서 준 결과를 이용해서 나머지 코드를 작성
}
})
type : GET, POST 등 요청방식이다.
url : 접속할 서버 경로이다. api 주소를 넣는다. 또한 여기다가 추가로 ?나 &등을 포함해서 확장할 수 있다.
data : get 방식은 주소 뒤에 요청할 방식,데이터등을 명시한다. 따라서 data에 아무것도 안씀. get 말고 post방식할 때 쓴다. get 방식은 요청 데이터가 없다. 주소 안에 ? 나 & 로 데이터들이 주소에 포함됨.
success : 성공했다면, 이런 걸 해라. 즉 요청한 결과를 어떻게 처리할 지 우리가 코딩하는 것이다.
success에서, 기본적으로 해당 api에서 가져온 결과 데이터는, response에 들어간다. 이 값은 당연히 "딕셔너리" 이다. 이 딕셔너리 안에 딕셔너리가 또있고 리스트도 있다. 이런 것을 복합 딕셔너리라고 한다.
success는 그것을 사용하는 function을 만들고 실행하는 것이다. 즉 위 예시대로 입력하면, 아래 내용 전체가 response에 들어가는것이다. 그래서 console.log(response)로 출력하면 아래내용이 그대로 나온다.
콘솔에서 해당 구문을 입력하면 동일하게 나오는 것을 확인할 수 있다.
참고로 실무에서는 이런 구문을 일일이 다 치기 보다는 복붙해서 수정해서 사용한다.
사용하기 : 내용 추출하기
위 예시에는 response에 서울시 대기 데이터 전체가 들어갔는데, 이 중 특정 데이터만 딱 뽑아보자.
success: function(response){
console.log(response['RealtimeCityAir']['row'][0]['MSRSTE_NM'])
}
이렇게 하면, 결과는 딱 "중구" 만 나온다. 이것과 반복문, if문을 잘하면 끝나는 것이다.
사용하기 : 예시
도봉구의 미세먼지값을 가져오기
$.ajax({
type: "GET",
url: "http://openapi.seoul.go.kr:8088/6d4d776b466c656533356a4b4b5872/json/RealtimeCityAir/1/99",
data: {},
success: function(response){
// 도봉구의 미세먼지 값만 가져와보기
let dobong = response["RealtimeCityAir"]["row"][11];
let guName = dobong['MSRSTE_NM'];
let guMise = dobong['PM10'];
console.log(guName, guMise);
}
})
모든 구의 미세먼지값을 가져오기
$.ajax({
type: "GET",
url: "http://openapi.seoul.go.kr:8088/6d4d776b466c656533356a4b4b5872/json/RealtimeCityAir/1/99",
data: {},
success: function (response) {
let cityAir = response["RealtimeCityAir"]["row"];
for (let i = 0; i < cityAir.length; i++) {
let mise = cityAir[i];
let guName = mise["MSRSTE_NM"];
let guMise = mise["PM10"];
console.log(guName, guMise);
}
},
});
실습
문제1 : 버튼을 누르면 서울시 미세먼지 데이터를 새로고침하고 전체를 보여준다. 또한 미세먼지 수치가 10이상인 곳은 빨갛게 표시한다.
API
http://openapi.seoul.go.kr:8088/6d4d776b466c656533356a4b4b5872/json/RealtimeCityAir/1/99
API 설명 페이지
<!Doctype html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>jQuery+Ajax의 조합을 연습하자!</title>
<!-- jQuery를 import 합니다 -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<style type="text/css">
div.question-box {
margin: 10px 0 20px 0;
}
.bad {
color: red;
}
</style>
<script>
function showMiseInfo() {
$('#mise-info').empty() // ajax 콜 하기 전에, 싹 다 지우는것.
$.ajax({
type: "GET",
url: "http://openapi.seoul.go.kr:8088/6d4d776b466c656533356a4b4b5872/json/RealtimeCityAir/1/99",
data: {},
success:
function (response) {
let cityAir = response["RealtimeCityAir"]["row"];
for (let i = 0; i < cityAir.length; i++) {
let mise = cityAir[i];
let guName = mise["MSRSTE_NM"];
let guMise = mise["PM10"];
let appendHtm = ''; // 빈값을 넣는거.. 쓰레기값이 들어가면 안되니.
if (guMise < 10) {
appendHtml = `<li>${guName} : ${guMise}</li>`
} else {
appendHtml = `<li>${guName} : <span class="bad">${guMise}</span></li>`
}
$('#mise-info').append(appendHtml);
}
},
});
}
</script>
</head>
<body>
<h1>jQuery+Ajax의 조합을 연습하자!</h1>
<hr/>
<div class="question-box">
<h2> 서울시 OpenAPI(실시간 대기환경 정보)를 이용하기</h2>
<p>모든 관측소(MSRSTE_NM)의 미세먼지 수치(PM10)를 표기해주세요</p>
<p>업데이트 버튼을 누를 때마다 지웠다 새로 씌여져야 합니다.</p>
<button onclick="showMiseInfo()">업데이트</button>
<ul id="mise-info">
<li>중구 : 82</li>
<li>종로구 : 87</li>
<li>용산구 : 84</li>
<li>은평구 : 82</li>
</ul>
</div>
</body>
</html>
문제2 : 서울시 실시간 따릉이 현황 이용 표 만들기, 추가로 사용할 수 있는 따릉이 대수가 5대 미만이면 빨간색으로 표시.
서울시 따릉이 API
http://openapi.seoul.go.kr:8088/6d4d776b466c656533356a4b4b5872/json/bikeList/1/99
API 정보
https://data.seoul.go.kr/dataList/OA-15493/A/1/datasetView.do
결과
<!Doctype html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Javascript + jQuery + Ajax 연습하기</title>
<!-- JQuery를 import 합니다 -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<style type="text/css">
div.question-box {
margin: 10px 0 20px 0;
}
table {
border: 1px solid;
border-collapse: collapse;
}
td,
th {
padding: 10px;
border: 1px solid;
}
.red {
color: red;
font-weight: bold;
border-color: black;
}
</style>
<script>
function showBikeInfo() {
$('#bike-info').empty()
$.ajax({
type: "GET",
url: "http://openapi.seoul.go.kr:8088/6d4d776b466c656533356a4b4b5872/json/bikeList/1/99",
data: {},
success:
function (response) {
let rentBike = response["rentBikeStatus"]["row"];
for (let i = 0; i < rentBike.length; i++) {
let bikeInfo = rentBike[i];
let bikeLoc = bikeInfo["stationName"];
let rackCnt = bikeInfo["rackTotCnt"];
let remainCnt = bikeInfo["parkingBikeTotCnt"];
// 위에는 변수 4개 선언을 했는데, 아래처럼 3개를 해도 된다.
// let bikeLoc = rentBike[i]["stationName"];
// let rackCnt = rentBike[i]["rackTotCnt"];
// let remainCnt = rentBike[i]["parkingBikeTotCnt"];
let bikeAppendInfo = '';
if (remainCnt < 5) {
bikeAppendInfo = `<tr><td class="red">${bikeLoc}</td><td class="red">${rackCnt}</td><td class="red">${remainCnt}</td></tr>`;
} else {
bikeAppendInfo = `<tr><td>${bikeLoc}</td><td>${rackCnt}</td><td>${remainCnt}</td></tr>`;
}
$('#bike-info').append(bikeAppendInfo);
}
},
});
}
</script>
</head>
<body>
<h1>Javascript + jQuery + Ajax 연습하기</h1>
<hr/>
<div class="question-box">
<h2>서울시 OpenAPI(실시간 따릉이 현황)를 이용하기</h2>
<p>모든 거치대(stationName)와 거치대 수(rackTotCnt), 남은 따릉이 수(parkingBikeTotCnt)를 보여주세요</p>
<p>업데이트 버튼을 누를 때마다 데이터가 지웠다 새로 씌여져야 합니다.</p>
<button onclick="showBikeInfo()">업데이트</button>
<table>
<thead>
<tr>
<td>거치대 위치</td>
<td>거치대 수</td>
<td>현재 거치된 따릉이 수</td>
</tr>
</thead>
<tbody id="bike-info">
<tr>
<td>102. 망원역 1번출구 앞</td>
<td>22</td>
<td>0</td>
</tr>
<tr>
<td>103. 망원역 2번출구 앞</td>
<td>16</td>
<td>0</td>
</tr>
<tr>
<td>104. 합정역 1번출구 앞</td>
<td>16</td>
<td>0</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
참고 : 리스트의 특정 데이터를 sort 하는 함수를 이용하면, 오름차순 내림차순도 가능하다.
문제3 : 랜덤 고양이 사진 API를 활용하여 고양이 사진을 랜덤으로 받기.
사용할 API : https://api.thecatapi.com/v1/images/search
api 정보 : https://docs.thecatapi.com/api-reference/images/images-search'
해당 api는 접속해보고 새로고침하면, 계속 새로운 게 나옴. api를 콜 할때마다 랜덤한 고양이가 나오는 것임.
이걸 새로고침하면 계속. 바뀐다. 이 결과가 딕셔너리이므로, 해당 요소에 접근하려면 response[0][키이름] 을 하면 데이터에 접근할 수 있다.
<!Doctype html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Javascript + jQuery + Ajax 연습하기</title>
<!-- JQuery를 import 합니다 -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<style type="text/css">
div.question-box {
margin: 10px 0 20px 0;
}
div.question-box > div {
margin-top: 30px;
}
</style>
<script>
function showCat() {
$.ajax ({
type: "GET",
url: "https://api.thecatapi.com/v1/images/search",
data: {},
success: function(response) {
let imgUrl = response[0]['url']
$('#img-cat').attr('src', imgUrl);
}
});
}
</script>
</head>
<body>
<h1>Javascript + jQuery + Ajax 연습하기</h1>
<hr/>
<div class="question-box">
<h2>랜덤 고양이 사진 API를 이용하기</h2>
<p>예쁜 고양이 사진을 보여주세요</p>
<p>업데이트 버튼을 누를 때마다 화면에 데이터가 지웠다 새로 씌여져야 합니다.</p>
<button onclick="showCat()">고양이를 보자</button>
<div>
<img id="img-cat" src="https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png"/>
</div>
</div>
</body>
</html>
추가문제
문제1 : 해리포터에 나오는 주문 보기, 추가로 저주 주문은 빨간색으로 보여주기.
사용 할 API 요청 URL : https://www.potterapi.com/v1/spells?key=$2a$10$LiNkiQtS86DQ8.NxC9G95.NN3.KkhNa917y/RZ6EjDILkjBaAJSLS
API 정보: https://www.potterapi.com/#spell-routes
정답
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>해리 포터 주문보기</title>
<!-- JQuery를 import 합니다 -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<style type="text/css">
div.question-box {
color: white;
margin: 10px 0 20px 0;
background-image: url('https://images.pexels.com/photos/1900185/pexels-photo-1900185.jpeg?cs=srgb&dl=4k-wallpaper-christmas-lights-harry-potter-magic-1900185.jpg&fm=jpg');
background-position: center;
}
table {
border: 1px solid;
border-collapse: collapse;
}
td,
th {
padding: 10px;
border: 1px solid;
}
.curse {
color: red;
}
</style>
<script>
$(document).ready(function () {
$('#spell-info').empty();
});
function showSpell() {
$('#spell-info').empty();
$.ajax({
type: "GET",
url: "https://www.potterapi.com/v1/spells?key=$2a$10$LiNkiQtS86DQ8.NxC9G95.NN3.KkhNa917y/RZ6EjDILkjBaAJSLS",
data: {},
success: function(response) {
for (i = 0; i < response.length; i++) {
let types = response[i]['type'];
let spells = response[i]['spell'];
let effects = response[i]['effect'];
if (types == 'Curse') {
$('#spell-info').append(`<tr class="curse"><td>${types}</td><td>${spells}</td><td>${effects}</td></tr`)
} else {
$('#spell-info').append(`<tr><td>${types}</td><td>${spells}</td><td>${effects}</td></tr`)
}
// 이런 방법도 가능
// if(spellType === 'Curse'){
// tempHtml = `<tr class="curse">\
// <td>${spellType}</td>
// <td>${spell}</td>
// <td>${effect}</td>
// </tr>`;
//
//
// }else {
// tempHtml = `<tr>\
// <td>${spellType}</td>
// <td>${spell}</td>
// <td>${effect}</td>
// </tr>`;
// }
// $('#spell-info').append(tempHtml);
}
}
})
}
</script>
</head>
<body>
<h1>Javascript + jQuery + Ajax 연습하기</h1>
<hr/>
<div class="question-box">
<h2>해리 포터 시리즈에 나오는 마법 주문 API 이용하기</h2>
<p>모든 주문 타입(type),주문(spell)과 효과(effect)를 화면에 보여주세요</p>
<p>업데이트 버튼을 누를 때마다 데이터가 지웠다 새로 씌여져야 합니다.</p>
<button onclick="showSpell()">업데이트</button>
<table>
<thead>
<tr>
<td>종류</td>
<td>주문</td>
<td>효과</td>
</tr>
</thead>
<tbody id="spell-info">
</tbody>
</table>
</div>
</body>
</html>
문제2 : 사랑에 관한 책 확인하기
사용 할 API 요청 URL : https://openlibrary.org/subjects/love.json?published_in=1900-2000
API 정보: https://openlibrary.org/dev/docs/api/subjects
정답
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>20세기 사랑 주제의 책 보기</title>
<!-- JQuery를 import 합니다 -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<style type="text/css">
div.question-box {
color: white;
margin: 10px 0 20px 0;
background-image: url("https://p0.pikist.com/photos/714/496/book-book-pages-novel-paperback-pitched-open-open-book-read-read-out.jpg");
background-position: center;
}
table {
border: 1px solid;
border-collapse: collapse;
}
td,
th {
padding: 10px;
border: 1px solid;
}
</style>
<script>
$(document).ready(function () {
// 창을 새로고침할 때마다 실행할 함수를 여기에 입력합니다.
$('#book-info').empty();
});
function showBookInfo() {
$('#book-info').empty();
$.ajax({
type: "GET",
url: "https://openlibrary.org/subjects/love.json?published_in=1900-2000",
data: {},
success: function(response) {
let works = response['works'];
for (i = 0; i < works.length; i++) {
let bookTitle = works[i]['title'];
let bootkAuthor = works[i]['authors'][0]['name'];
$('#book-info').append(`<tr><td>${bookTitle}</td><td>${bootkAuthor}</td></tr>`);
}
}
})
}
</script>
</head>
<body>
<h1>Javascript + jQuery + Ajax 연습하기</h1>
<hr/>
<div class="question-box">
<h2>20세기 사랑 주제의 책 보기</h2>
<p>모든 책의 제목(title),작가 이름(authors)을 화면에 보여주세요</p>
<p>업데이트 버튼을 누를 때마다 데이터가 지웠다 새로 씌여져야 합니다.</p>
<button onclick="showBookInfo()">업데이트</button>
<table>
<thead>
<tr>
<td>책 제목</td>
<td>작가명</td>
</tr>
</thead>
<tbody id="book-info">
</tbody>
</table>
</div>
</body>
</html>
문제3 : api 정보를 보고, 아래 조건의 출판으 책을 리스트업 하자.
사실상 2번과 동일한데, 좀 더 api쪽을 찾아보게 하는 예제.
- api 정보 : https://openlibrary.org/dev/docs/api/subject
- api 조건 : 21세기의 현재까지, 컴퓨터 주제
- 형식 : https://openlibrary.org/subjects/주제.json?published_in=연도
- 예시 : https://openlibrary.org/subjects/love.json?published_in=1900-2000
- 답 : https://openlibrary.org/subjects/computer.json?published_in=2000-2020
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>21세기 컴퓨터 주제 출판 책 보기</title>
<!-- JQuery를 import 합니다 -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<style type="text/css">
div.question-box {
color: white;
margin: 10px 0 20px 0;
background-image: url("https://p1.pxfuel.com/preview/62/205/156/technology-hands-agreement-ok-screen-computer.jpg");
background-position: center;
}
table {
border: 1px solid;
border-collapse: collapse;
}
td,
th {
padding: 10px;
border: 1px solid;
}
</style>
<script>
$(document).ready(function () {
$('#book-info').empty()// 창을 새로고침할 때마다 실행할 함수를 여기에 입력합니다.
});
function showBookInfo() {
$('#book-info').empty()
$.ajax({
type: "GET",
url: "https://openlibrary.org/subjects/computer.json?published_in=2000-2020",
data: {},
success: function(response) {
let works = response['works'];
for (i = 0; i < works.length; i++) {
let bookTitle = works[i]['title'];
let bootkAuthor = works[i]['authors'][0]['name'];
$('#book-info').append(`<tr><td>${bookTitle}</td><td>${bootkAuthor}</td></tr>`);
}
}
})
}
</script>
</head>
<body>
<h1>Javascript + jQuery + Ajax 연습하기</h1>
<hr/>
<div class="question-box">
<h2>21세기 컴퓨터 주제 출판 책 보기</h2>
<p>모든 책의 제목(title),작가 이름(authors)을 화면에 보여주세요</p>
<p>업데이트 버튼을 누를 때마다 데이터가 지웠다 새로 씌여져야 합니다.</p>
<!-- button 을 눌렀을 때 업데이트하려면 어떻게 해야할까요? -->
<button onclick="showBookInfo()">업데이트</button>
<table>
<thead>
<tr>
<td>책 제목</td>
<td>작가명</td>
</tr>
</thead>
<!-- tbody 에 정보를 업데이트 하려면 어떻게 해야할까요? 힌트! 가리킨다(select) -->
<tbody id="book-info">
</tbody>
</table>
</div>
</body>
</html>
문제4 : 숫자 의미 api 사용하기
각 숫자를 받아 그 숫자의 의미를 api를 통해 출력한다.
api 주소 및 설명
정답
<!Doctype html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Javascript + jQuery + Ajax 연습하기</title>
<!-- JQuery를 import 합니다 -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<style type="text/css">
div.question-box {
margin: 10px 0 20px 0;
}
</style>
<script>
function showNumMeaning() {
if ($('#magic-num').val() == '') {
alert("숫자를 입력하세요")
} else {
let inputVal = $('#magic-num').val();
let targetAddress = "http://numbersapi.com/" + inputVal
$.ajax({
type: "GET",
url: targetAddress,
data: {},
success: function (response) {
$("#meaning").text(response);
}
})
}
}
</script>
</head>
<body>
<h1>Javascript + jQuery + Ajax 연습하기</h1>
<hr/>
<div class="question-box">
<h2>랜덤 숫자 의미부여 API를 이용하기</h2>
<p>모든 숫자는 어떤 의미가 있습니다. 함께 살펴볼까요?</p>
<p>아무것도 입력하지 않으면, alert을 띄워주세요.</p>
<input type="number" id="magic-num">
<button onclick="showNumMeaning()">이 숫자의 의미는?</button>
<h5 id="meaning"></h5>
</div>
</body>
</html>
'SCC 9기' 카테고리의 다른 글
[SCC 9기] 4주차 (0) | 2020.08.11 |
---|---|
[SPC 9기] 3주차 (0) | 2020.07.25 |
[SPC 9기] 1주차 - 프론트엔드 (0) | 2020.07.16 |
[SCC 9기] 개발자를 위한 팁 (0) | 2020.07.16 |
[SPC 9기] 0주차 - 사전준비/과제 및 이론수업 (0) | 2020.06.11 |