window.onload()
메소드 인 것이다. <html>
<body>
<script>
window.onload = function() {
let a = document.getElementById('name');
a.style.color = "blue"
}
</script>
<p id="name">hello</p>
</body>
</html>
var popup = window.open(url, name, option);
url
: 새창(팝업창)에 보여질 주소 다. 선택적인 값으로 비워두면 빈창(about:blank)이 보이게 된다.
name
:새로 열릴 창의 속성 또는 창의 이름을 지정한다. 다음 속성들을 지정해 넣으면 된다.
1. _blank : 새 창으로 연다. (기본값)
2. _parent : 부모 프레임에 열린다.
3. _self : 현재 페이지를 대체한다.
4. _top : 로드된 프레임셋을 대체한다.
5. name(임의의 이름) : 새 창이 열리고 창의 이름을 지정한다. 동일한 이름에 다시 open() 을 하면 기존의 열린창의 내용이 바뀐다. 다른 이름을 사용하면 또다른 새창이 열린다.
option
//속성 지정하지 않은 기본창
window.open("http://eschyles.mireene.com/", "", "");
//메뉴바 없는 팝업
window.open("http://eschyles.mireene.com/", "", "menubar=1");
//풀스크린 방식
window.open("http://eschyles.mireene.com/", "", "fullscreen");
//채널모드
window.open("http://eschyles.mireene.com/", "", "channelmode");
// 상태표시바 있는 팝업
window.open("http://eschyles.mireene.com/", "", "width=400, height=300, status=1");
//크기 width400 height300 팝업창
window.open("http://eschyles.mireene.com/", "", "width=400, height=300");
//위치 left=500, top=400 에서 열리는 팝업창
window.open("http://eschyles.mireene.com/", "", "width=400, height=300, left=500, top=400");
//스크롤바 있는 팝업
window.open("http://eschyles.mireene.com/", "", "width=400, height=300, scrollbars=1");
//주소표시줄 있는 팝업
window.open("http://eschyles.mireene.com/", "", "width=400, height=300, left=100, location=1");
// 창 컨트롤 모두 활성 화
window.open("/popup.html", "_blank", "toolbar=yes,scrollbars=yes,resizable=yes,top=500,left=500,width=400,height=400");
var popup = window.open('팝업주소', '팝업창 이름', '팝업창 설정');
popup.close(); // 열었던 새창 닫기
[
나 ]
같은 특수문자는 반드시 인코딩 해야되기 때문이다. 그래야 브라우저 측에서 디코딩하여 사용할 수 있다.var uri = 'http://localhost:8080/viewer.html?key1=123123&key2=[1][2]';
var res1 = encodeURI(uri); // url문자를 반드시 먼저 인코딩한다.
window.open(res1, '', 'width=900,height=800');
<input type="button" onclick="alert('Hello world, ' + this.value);" value="button" />
// >> Hello world button
<button onclick="myHandler1(); myHandler2();">Click me</button>
<script>
function myHandler1() {
alert('myHandler1');
}
function myHandler2() {
alert('myHandler2');
}
</script>
<input type="button" id="target1" value="button1" />
<input type="button" id="target2" value="button2" />
<script>
var t1 = document.getElementById('target1');
var t2 = document.getElementById('target2');
function btn_listener(event){
switch(event.target.id){
case 'target1':
alert(1);
break;
case 'target2':
alert(2);
break;
}
}
t1.addEventListener('click', btn_listener); // btn_listener()가 아니다.
t2.addEventListener('click', "btn_listener()"); // btn_listener()를 쓰려면 문자열로 감싼다.
btn_listener()로 쓰면 함수자체를 쓰는게 아니라 리턴값을 받게된다.
</script>
<button class="btn">Button</button>
<script>
const btn = document.querySelector('.btn');
btn.addEventListener('click', function (e) {
console.log(this); // <button id="btn">Button</button>
console.log(e.currentTarget); // <button id="btn">Button</button>
console.log(this === e.currentTarget); // true
});
</script>
<!DOCTYPE html>
<html>
<body>
<p>클릭하세요. 클릭한 곳의 좌표가 표시됩니다.</p>
<em class="message"></em>
<script>
function showCoords(e) { // e: event object
const msg = document.querySelector('.message');
msg.innerHTML =
'clientX value: ' + e.clientX + '<br>' +
'clientY value: ' + e.clientY;
}
addEventListener('click', showCoords); // 참조하는게 없으면 기본 window 전역 객체
</script>
</body>
</html>
Event.target
: 실제로 이벤트를 발생시킨 요소를 가리킨다.Event.currentTarget
: 이벤트에 바인딩된 DOM 요소를 가리킨다. 즉, addEventListener 앞에 기술된 객체를 가리킨다. 따라서 이벤트 핸들러 함수 내에서 currentTarget과 this는 언제나 일치한다.<div>
<button>배경색 변경</button>
</div>
document.querySelector('div').addEventListener('click', function() {
// this: 이벤트에 바인딩된 DOM 요소(div 요소)
console.log('this: ', this);
// target: 실제로 이벤트를 발생시킨 요소(button 요소 또는 div 요소)
console.log('e.target:', e.target);
// currentTarget: 이벤트에 바인딩된 DOM 요소(div 요소)
console.log('e.currentTarget: ', e.currentTarget);
});
<ul id="post-list">
<li id="post-1">Item 1</li>
<li id="post-2">Item 2</li>
<li id="post-3">Item 3</li>
<li id="post-4">Item 4</li>
<li id="post-5">Item 5</li>
<li id="post-6">Item 6</li>
</ul>
function printId() {
console.log(this.id);
}
document.querySelector('#post-1').addEventListener('click', printId);
document.querySelector('#post-2').addEventListener('click', printId);
document.querySelector('#post-3').addEventListener('click', printId);
document.querySelector('#post-4').addEventListener('click', printId);
document.querySelector('#post-5').addEventListener('click', printId);
document.querySelector('#post-6').addEventListener('click', printId);
const msg = document.querySelector('.msg');
const list = document.querySelector('ul#post-list')
list.addEventListener('click', function (e) {
// 이벤트를 발생시킨 요소
console.log('[target]: ' + e.target);
// 이벤트를 발생시킨 요소의 nodeName
console.log('[target.nodeName]: ' + e.target.nodeName);
// li 요소 이외의 요소에서 발생한 이벤트는 대응하지 않는다.
if (e.target && e.target.nodeName === 'LI') {
msg.innerHTML = 'li#' + e.target.id + ' was clicked!';
}
});
이 방식에서는 이벤트 객체의 e.preventDefault() 메소드를 실행하면 기본 동작이 취소된다.
이 체크박스는 이벤트의 기본 동작을 취소할지를 결정하는 역할을 합니다. 체크박스가 체크되어 있으면 기본 동작이 취소됩니다.
<p>
<label>prevent event on</label>
<input id="prevent" type="checkbox" name="eventprevent" value="on" />
체크박스에서의 value: 체크박스는 사용자가 선택했는지 여부를 나타내며,
선택되었을 때만 값을 서버로 전송합니다.
</p>
<p>
<a href="http://opentutorials.org">opentutorials</a>
</p>
<p>
<form action="http://opentutorials.org">
<input type="submit" />
</form>
</p>
document.querySelector('a').addEventListener('click', function(e){
if(document.getElementById('prevent').checked)
e.preventDefault(); // 링크 동작 금지
});
document.querySelector('form').addEventListener('submit', function(e){
if(document.getElementById('prevent').checked)
e.preventDefault(); // 폼 submit(페이지갱신) 동작 금지
});
AJAX는 비동기 방식으로 데이터를 주고받을 수 있습니다. 즉, 페이지가 로드된 후에도 백그라운드에서 서버와 통신할 수 있습니다. 이로 인해 사용자 인터페이스가 부드럽게 유지됩니다.
전체 페이지를 새로 고치지 않고도 페이지의 일부를 업데이트할 수 있습니다. 예를 들어, 사용자가 버튼을 클릭했을 때 페이지의 일부만 변경될 수 있습니다.
AJAX는 서버에 요청을 보내고, 서버로부터 응답을 받아 페이지의 내용을 업데이트합니다. 이때 사용되는 데이터 형식으로는 XML, JSON, HTML, 또는 텍스트 등이 있습니다. JSON은 가장 일반적으로 사용됩니다.
fetch("https://jsonplaceholder.typicode.com/posts", option)
.then(res => res.text())
.then(text => console.log(text));
/* 'fetch('서버주소')' 는 웹 브라우저에게 '이 서버주소로 요청해줘' 라는 의미이고,
뒤에 .then이 붙으면 '요청 끝나고나서 이 할일을 해줘!' 라는 것이다. */
fetch("https://jsonplaceholder.typicode.com/posts/1") // posts의 id 1인 엘리먼트를 가져옴
.then((response) => response.json())
.then((data) => console.log(data))
{
"userId": 1,
"id": 1,
"title": "sunt aut facere optio reprehenderit",
"body": "quia et iet architecto"
}
fetch("https://jsonplaceholder.typicode.com/posts", {
method: "POST", // POST
headers: { // 헤더 조작
"Content-Type": "application/json",
},
body: JSON.stringify({ // 자바스크립트 객체를 json화 한다.
title: "Test",
body: "I am testing!",
userId: 1,
}),
})
.then((response) => response.json())
.then((data) => console.log(data))
fetch("https://jsonplaceholder.typicode.com/posts/1", {
method: "DELETE",
})
.then((response) => response.json())
.then((data) => console.log(data))
async function getData() {
const response = await fetch('https://jsonplaceholder.typicode.com/users/1');
const data = await response.json();
console.log(data):
}
fetch('https://jsonplaceholder.typicode.com/users/1'); 로 데이터를 가져올 때까지 기다린다.
비동기 프로그래밍은 웹에서 메인 스레드를 차단하지 않고 시간 소모적인 작업을 병렬적으로 수행할 수 있도록 하는 웹 개발의 필수적인 부분이다. 하지만 잘못 사용하면 병렬적으로 멀티로 처리할 수 있는 작업을 억지로 동기적으로 처리하게해서 속도가 더 느려질 수 있다.
사과와 바나나를 출력하는데 순서가 상관없다면 아래의 코드는 비효율적이다.
async function getFruites() {
let a = await getApple(); // getApple() 비동기 처리를 요청하고, 요청이 처리될때 까지 기다림 (1초 소요)
let b = await getBanana(); // getBanana() 비동기 처리를 요청하고, 요청이 처리될때 까지 기다림 (1초 소요)
console.log(`${a} and ${b}`); // 총 2초 소요
}
async function getFruites(){
let getApplePromise = getApple(); // async함수를 미리 논블록킹으로 실행한다.
let getBananaPromise = getBanana(); // async함수를 미리 논블록킹으로 실행한다.
// 이렇게 하면 각각 백단에서 독립적으로 거의 동시에 실행되게 된다.
console.log(getApplePromise)
console.log(getBananaPromise)
let a = await getApplePromise; // getApple의 결과를 기다림
let b = await getBananaPromise; // getBanana의 결과를 기다림
console.log(`${a} and ${b}`); // 본래라면 1초+1초 를 기다려야 하는데, 위에서 1초기다리는 함수를 바로 연속으로 비동기로 불려왔기 때문에, 대충 1.01초만 기다리면 처리된다.
})
Promise.all 메소드
: 또다른 방법으론 Promise.all() 정적 메서드를 사용하는 방법이 있다. 위와 같이 구성할 경우 비동기 처리 완료 시점을 가늠하기 힘들기 때문에 대부분의 실무에선 Promise.all()로 처리한다.
Promise.all() 은 배열 인자의 각 프로미스 비동기 함수들이 resolve가 모두 되야 결과를 리턴 받는다. 배열인자의 각 프로미스 함수들은 제각각 비동기 논블록킹으로 실행되어 시간을 단축 할 수 있다. 리턴값은 각 프로미스 함수의 반환값들이 배열로 담겨져 있다.
모든 프로미스가 성공적으로 완료되었을 때만 Promise.all이 완료된다. 하나라도 실패하면 전체가 실패로 간주되며, 모든 프로미스가 성공적으로 완료되면, 각 프로미스의 결과를 배열 형태로 받을 수 있다.
프로미스가 완료된 순서와 상관없이 제공된 순서대로 결과를 배열로 반환한다.
function getApple() {
return new Promise(resolve => setTimeout(() => resolve('Apple'), 1000));
}
function getBanana() {
return new Promise(resolve => setTimeout(() => resolve('Banana'), 1500));
}
function getOrange() {
return new Promise(resolve => setTimeout(() => resolve('Orange'), 500));
}
async function getFruits() {
try {
// 모든 프로미스를 동시에 실행
const [apple, banana, orange] = await Promise.all([getApple(), getBanana(), getOrange()]);
console.log(`${apple}, ${banana}, ${orange}`); // "Apple, Banana, Orange"
} catch (error) {
console.error('One of the promises failed:', error);
}
}
getFruits();
(async function func1() {
const res = await fetch(url); // 요청을 기다림
const data = await res.json(); // 응답을 JSON으로 파싱
console.log(data);
})();
// Top Level에선 async funciton 정의없이 곧바로 await 키워드 사용이 가능하다
const res = await fetch(url); // 요청을 기다림
const data = await res.json(); // 응답을 JSON으로 파싱
console.log(data);
다음 예제는 엔터를 누르면 focus() 메서드가 실행되어 바로 다음 입력창 요소로 포커싱하여서 연달아 바로바로 입력할수 있게 하는 응용법이다.
<FORM>
[개인정보 입력]<br>
이름 : <INPUT id=pname type=text size=10 onkeydown='moveFocus("age")'><br>
나이 : <INPUT id=age type=text size=10 onkeydown='moveFocus("sex")'><br>
성별 : <INPUT id=sex type=text size=10 onkeydown='moveFocus("confirm")'>
</FORM>
<script>
function moveFocus(next) {
if (event.keyCode == 13) { //엔터누를경우
document.getElementById(next).focus();//아규먼트id 노드로 이동해서 focus한다
}
}
</script>
<textarea id='textarea1'>textarea1</textarea>
<textarea id='textarea2'>textarea2</textarea>
<script>
document.addEventListener("mouseup", (showSelected) => {
alert(`${document.activeElement.id} 클릭 !!`);
});
</script>
<form action="/examples/media/action_target.php" method="get">
이름 : <input type="text" name="st_name"><br>
학번 : <input type="text" name="st_id" autofocus><br>
<!-- 페이지가 로드될 때 자동으로 포커스 -->
학과 : <input type="text" name="department"><br>
<input type="submit">
</form>
자바스크립트는 document.cookie
속성을 이용하여 쿠키를 create, delete, read 할 수 있다.
document.cookie= 는 getter와 setter같이 동작한다고 이해하면 된다.
setter를 수행할때 모든 쿠키를 덮어쓰지 않고, 명시된 쿠키인 user의 값만 갱신한다.
// Name이 user고, Value가 John인 쿠키 추가
// document.cookie = 했다고 초기화되는게 아니라, setter처럼 작동하게 된다.
// 그래서 = "user=John"하면 전체가 'user=john'이 되는게 아니라 '+= user=john'이 추가되게 된다.
document.cookie = "user=John";
encodeURIComponent
를 사용하여 이름과 값을 이스케이프 처리해 줘야 하는게 좋다.var x = document.cookie; // cookie1=value1; cookie2=value2;...
// Name이 user고, Value가 John인 쿠키 추가
// 그리고 속성값으로 path와 expires를 설정해서 추가
// 이 속성값은 쿠키 스트링에 저장되지는 않고 속성정보에 저장된다.
document.cookie = "user=John; path=/; expires=Tue, 19 Jan 2038 03:14:07 GMT"
// document.cookie = "쿠키이름=쿠키값"
document.cookie = "username = 홍길동";
// 만료기간을 넣어서 쿠키가 자동 만료 되도록 제작할 수 있다.(UTC time을 이용)
document.cookie = "username=John Doe; expires=Thu, 18 Dec 2013 12:00:00 UTC";
// 파라미터를 이용하여 쿠키가 어디 브라우저에 속할 수 있을지 알려줄 수 있다.
document.cookie = "username=John Doe; expires=Thu, 18 Dec 2013 12:00:00 UTC; path=/";
document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
또는
// max-age 사용
// 1시간 뒤에 쿠키가 삭제됩니다.
document.cookie = "max-age=3600";
// 만료 기간을 0으로 지정하여 쿠키를 바로 삭제함
document.cookie = "max-age=0";
// Name이 user고, Value가 John인 쿠키 추가
document.cookie = "user=John"
GMT 형식이나 UTC 형식
으로 날짜를 입력해야 한다.document.cookie = "user=John; path=/; expires=Tue, 19 Jan 2038 03:14:07 GMT"
// 1시간 뒤에 쿠키가 삭제됩니다.
document.cookie = "user=John; max-age=3600";
// 만료 기간을 0으로 지정하여 쿠키를 바로 삭제함
document.cookie = "user=John; max-age=0";
SSL
을 사용해서만 요청할 수 있다.document.cookie = "user=John; Secure"
// naver.com, www.naver.com, blog.naver.com, cafe.naver.com 서브 도메인도 모두 포함
document.cookie = "user=John; Domain=.naver.com"
document.cookie = "user=John; path=/"
쿠키는 클라이언트에서 자바스크립트로 조회할 수 있기 때문에 해커들은 자바스크립로 쿠키를 가로채고자 시도한다.
HTTP Only Cookie를 설정하면 브라우저에서 해당 쿠키로 접근할 수 없게 되지만, 쿠키에 포함된 정보의 대부분이 브라우저에서 접근할 필요가 없기 때문에 HTTP Only Cookie는 기본적으로 적용하는 것이 좋다.
document.cookie = "user=John; httpOnly"
localStorage
sessionStorage
localStorage.test = '123'; // 리터럴 방식
localStorage.setItem('test', '123'); // 메소드 방식
localStorage.test; // 리터럴 방식
localStorage.getItem('test'); // 메소드 방식
localStorage.getItem(); // 인자를 안주면, 전체 값 받아오기
localStorage.length // 항목 갯수 반환
localStorage.key(0); // 인자(인덱스)에 해당하는 key의 value값을 받아온다.
localStorage.removeItem('test');
// localStorage 객체에서 원하는 값을 지우는 방법
localStorage.clear();
// 한번에 저장된 모든 값을 삭제하는 방법
let keys = Object.keys(localStorage);
for(let key of keys) {
alert(`${key}: ${localStorage.getItem(key)}`);
}
localStorage.user = {name: "John"};
alert(localStorage.user); // [object Object]
단 JSON을 사용하면 객체와 배열을 저장할 수 있다.
localStorage.user = JSON.stringify({name: "John"});
let user = JSON.parse( localStorage.user );
alert( user.name ); // John
let arr = [1,2,3,4,5]
localStorage.setItem("data", JSON.stringify(arr));
let output = localStorage.getItem("data");
let arr = JSON.parse(output);
console.log(arr) // [1,2,3,4,5]
sessionStorage.setItem("domain", "webisfree.com");
// domain이란 키(key) 값을 사용하여 해당 텍스트를 저장함
sessionStorage.getItem("domain");
// 키에 저장된 값을 반환. 여기서는 webisfree.com 출력됨
sessionStorage.removeItem("domain");
// domain 키와 데이터 모두 삭제
sessionStorage.clear();
// 저장된 모든 값 삭제
// 사이트 주소 얻기
const link = window.location.href;
// "http://testurl.co.kr:8080/path/main.html?param1=1¶m2=3#top"
var url = new URL(link);
/* url 객체 정보 */
{
protocol: "http:" // 프로토콜
hostname: "testurl.co.kr" // 도메인, 아이피
port: "8080" // 포트
host: "testurl.co.kr:8080" // 서버 주소
origin: "http://testurl.co.kr:8080" // 프로토콜, 서버이름, 포트 포함
href: "http://testurl.co.kr:8080/path/main.html?param1=1¶m2=3#top" // 전체경로
pathname: "/path/main.html" // 서버 자원 위치
hash: "top" // #해시 위치
search: "?param1=1¶m2=3" // 쿼리스트링
searchParams: URLSearchParams {} // 쿼리스트링을 메소드를 통해 모듈화
username: "" // HTTP 인증이있는 경우 속성
password: "" // HTTP 인증이있는 경우 속성
}
const urlStr = 'https://gillog/post/1?tag=javascript&like=backend';
const url = new URL(urlStr);
const urlParams = url.searchParams;
// URLSearchParams 객체를 넣는다. 그러면 메소드를 사용할수 있게 된다.
const tag = urlParams.get('tag'); // 쿼리스트링에 tag라는 키의 값을 가져온다.
console.log(tag); // javascript
const like = urlParams.get('like');
console.log(like) // backend
// 쿼리스트링 부분을 URLSearchParams객체에 바로 줘서 사용할 수도 있다.
const urlParams = new URLSearchParams("?gil=test&log=what&gillog=holy");
const keys = urlParams.keys();
// gil
// log
// gillog
const values = urlParams.values();
// test
// what
// holy
const entries = urlParams.entries();
// gil, test
// log, what
// gillog, holy
const urlParams = new URLSearchParams("?gil=123&log=456&gillog=777");
// true
console.log(urlParams.has("gillog"));
// false
console.log(urlParams.has("loggil"));
let urlParams = new URLSearchParams("?gil=test");
urlParams.append("log", "yes");
urlParams.append("log", "no");
// ?gil=test&log=yes&log=no
console.log(urlParams);
let urlParams = new URLSearchParams("?gil=test&log=yes&log=no");
urlParams.set("gil", "yes");
urlParams.set("log", "wow");
urlParams.set("gillog", "good");
// ?gil=yes&log=wow&gillog=good
console.log(urlParams);
url.searchParams.delete("param1")
element.setCustomValidity('Custom error message');
ex)
var password = document.getElementById("password")
,confirm_password = document.getElementById("confirm_password");
function validatePassword(){
if(password.value != confirm_password.value) { // 만일 두 인풋 필드값이 같지 않을 경우
// setCustomValidity의 값을 지정해 무조건 경고 표시가 나게 하고
confirm_password.setCustomValidity("Passwords Don't Match");
}
else { // 만일 두 인풋 필드값이 같을 경우
// 오류가 없으면 메시지를 빈 문자열로 설정해야한다. 오류 메시지가 비어 있지 않은 한 양식은 유효성 검사를 통과하지 않고 제출되지 않는다.
// 따라서 빈값을 주어 submit 처리되게 한다
confirm_password.setCustomValidity('');
}
}
password.onchange = validatePassword;
confirm_password.onkeyup = validatePassword;
var isValid = element.reportValidity();
var willValidate = element.willValidate;
<!DOCTYPE html>
<html>
<head>
<title>willValidate Example</title>
</head>
<body>
<form id="myForm">
<label for="email">Email:</label>
<input type="email" id="email" name="email" required>
<br>
<label for="phone">Phone (Optional):</label>
<input type="tel" id="phone" name="phone">
<br>
<button type="submit">Submit</button>
</form>
<script>
var emailField = document.getElementById('email');
var phoneField = document.getElementById('phone');
console.log('Email field will validate:', emailField.willValidate); // true, because 'required' is set
console.log('Phone field will validate:', phoneField.willValidate); // false, because 'required' is not set
// Adding 'required' to phone field to check willValidate again
phoneField.required = true;
console.log('Phone field will validate after adding required:', phoneField.willValidate); // true, because 'required' is now set
</script>
</body>
</html>
-참고
https://inpa.tistory.com/ (이 글의 거의 모든 내용)