2022. 12. 21. 00:46ㆍDevelopers 공간 [Basic]/Frontend
이번 시간에는 Interactive(인터랙티브) 웹을 구현하기 위한 Javascript에 대해서 설명하고자 합니다.
Javascript는 대부분의 웹개발자들이 배우는 대중적인 ‘웹 개발 언어’이며, 드롭다운(Dropdown)메뉴, 슬라이드 효과, 대화창을 비롯한 다양한 효과를 웹페이지에서 구현 가능하게 해줍니다.
흔히들 Javascript를 웹 개발자의 첫 번째 프로그래밍 언어라 부릅니다. 단, 물론 Javsascript는 진정한 프로그래밍 언어가 아니라 스크립트 언어라고 말하는 사람들도 있습니다.
CSS3에서 추가 기능이 생겨나면서 Javscript 없이도 멋진 기능을 만들어낼 수 있게 되었지만, 그렇다고 해서 Javascript가 더 이상 무용지물이 된 것은 아닙니다.
또한 서버에서 Node.JS가 돌아가고 있다면, 자바스크립트를 프런트엔드(frontend)는 물론이고, 백엔드(backend)에서도 활용하곤 합니다.
설명드릴 Javscript의 버전은 에크마스크립트2015(ES2015=ECMAScript2015=ES6) 이상이며, 22년 말 기준 최신 버전은 ES2022(=ECMAScript2022=ES13) 입니다.
Javascript을 활용해 렌더링 혹은 Interactive Web을 구현할 수 있는데, Interactive와 비슷한 혼용어들을 정리하면 아래와 같습니다.
- Responsive(반응형) Web Design : 다양한 기기와 다양한 browser screen size로 인해 변경
- Adaptive(적응형) Web Design : 다양한 기기(스마트폰, PC, 태블릿)에 맞게 해상도 및 레이아웃이 변경
- Interactive Web Design : Event를 통해 User의 요청에 동적인 결과를 가져다주는 비동기식 구현 방식
- Reactive Web Design : 서버로부터 웹사이트를 상시로 업데이트하고 계속해서 최신 형식을 보여주는 방식
<구성>
1. Javascsript 기초
a. 기본 구조
b. 객체 (Object)
2. Interactive Web
a. DOM을 얻는 방법
b. Javascript 와 HTML간의 관계
c. event추가 하기
글효과 분류1 : 코드
글효과 분류2 : 폴더/파일
글효과 분류3 : 용어설명
글효과 분류4 : 글 내 참조
1. Javascript기초
Javascrpt 가 HTML/CSS에서 다루는 Object의 단위는 DOM(Document Object Model)이라고 부릅니다. DOM 이란..
HTML의 Element들이 파싱된 DOM이라는 객체를 이해하기 위해서는 Browser Rendering과 관련된 내용을 참조하시면 더 확실히 아실 수 있습니다. 간단히 설명하면 아래와 같습니다.
- User Interface : 주소 표시줄 등 User가 입력할 수 있는 부분
- Browser Engine : User Interface와 Rendering Engine 사이 동작 제어
- Data Persistence : 쿠키 등의 정보를 캐싱 하는 저장소
- Rendering Engine : HTML과 CSS를 받아 DOM과 CSSOM(CSS Object Model)을 파싱
- Networking Server : HTTP 프로토콜을 통해 HTML과 CSS를 받아 올 수 있는 곳
- Javascript Interpreter : Javascript를 활용해 DOM을 조작하고 Render Object로 파싱
- UI Backend : Render Object를 화면에 그림
a. 기본 구조
// Variable Before ES2015
var a = 100;
var a = function(){} // a()
// Variable From ES2015
const a = 100;
let b = 100;
const a = ()=>{};
// Function
function foo(){ console.log(‘안녕하세요’);}
// Condition
if(true && a==b) {var a = 100;}
// Loop
for(let i=0; i<a.length; i++){}
- 변수 선언
- (ES2015 전) 변수의 범위가 함수 단위, function-level scope
- 특징 : 중복선언이 가능하며, 블록 외부에서 선언되어도 전역변수가 될 확률이 높다.
- var : 변수 선언 가능한 유일한 방법
- 함수 객체 : 함수도 일급 객체로써 쓰여 변수에 할당이 가능합니다.
**일급객체(First-Class Object) : 하기 조건을 만족하는 객체를 일급 객체라 합니다.
- 변수나 데이타에 할당 가능 ex) var a = 객체
- 객체의 인자로 가능 ex) function ABC(객체){}
- 객체의 리턴값으로 리턴 가능 ex) return 객체;
- (ES2015 이후) 변수의 범위가 블록 {} 단위, block-level scope
- 특징 : 중복선언이 불가하며, Hoisting이 불가합니다.
** 호이스팅(Hoisting) : undefined 로 변수를 초기화해, 선언되기 전에 메모리 공간을 할당해 두는 것 - let : 기본 변수이며, var과 다른 특징들을 가진 변수입니다.
- const : 변하지 않는 값
- 함수 객체 : 역시나 일급 객체로 쓰이지만, 일반 함수가 아닌 Arrow Function(화살표 함수) 메서드도 할당이 가능합니다.
- 특징 : 중복선언이 불가하며, Hoisting이 불가합니다.
- (ES2015 전) 변수의 범위가 함수 단위, function-level scope
- 기타 문법 : 함수 선언, 조건문, 반복문, 연산자 들은 위와 같습니다.
b. 객체 (Object)
// Object 직접 선언
const person = {
name : ‘일분이’,
introduce : function(){};
}
// Object 생성자로 선언
function Person(nickname, age){
this.nickname =nickname;
this.age = age;
this.introduce = function(){console.log(‘’);};
}
Person.prototype.introduce = function(){
console.log(‘’);
}
const person1 = new Person(‘ABC’, 35);
// Prototype 활용
function Box(num, color) {
this.num = num;
this.color = color;
this.init();
}
Box.prototype = {
constructor: Box,
init: function() {
const mainElem = document.createElement('div');
mainElem.style.color = this.color;
mainElem.innerHTML = this.num;
mainElem.classList.add('box');
document.body.appendChild(mainElem);
}
};
Box.prototype.additional = 4;
- 기본 data type 이외 모든 것은 Object
** 기본 data type(Primitive type) : 숫자, 문자열, bool, undefined, null - 직접 선언
- const person = {}; (배열 []과 다르다)
- property(속성)
- this.name : 자기 object 접근!
- (외부) person.name = ‘이름’;
- (외부) person.age = 10;
- method(속성)
- person.introduce = function(){console.log(‘’)};
- person.introduce()
- 생성자를 통한 선언
- Constructor(생성자) : 관례적으로 “Person”같이 대문자로 시작, function과 모양새는 같다
- 추가적으로 ES2015에서는 "class" 가 생겼습니다.
- Prototype(원형 객체) : 객체의 원형으로 생성자로, property중 하나이다. 그 용도가 약속되어 있는 특수한 property로, prototype에 저장된 속성들은 생성자를 통해서 객체가 만들어질 때 그 객체에 연결됩니다.
- 즉 위 예에서 this.introduce 부분은 공유가 가능한 memory에 위치해 공유할 수 있는 prototype 함수입니다.
- Constructor(생성자) : 관례적으로 “Person”같이 대문자로 시작, function과 모양새는 같다
2. Interactive Web
a. DOM을 얻는 방법
// Node 얻기
const ABC = document.querySelector('.ABC');
const ABC = document.querySelectorAll('.ABC'); // ABC[3]
let temp = document.creteElement('div');
let temp = document.getElementById('ABC');
function (e) {e.target}
function (e) {e.currentTarget}
function (e) {this}
// Node 조작
elem = e.target
const pElem = document.createElement('p')
pElem.innerHTML = '<a href=“#”>안녕</a>'
elem.nodeName == 'BODY'
elem.parentNode
elem.appendChild(pElem)
elem.removeChild(document.querySelector('.ABC')))
elem.parentNode.removeChild(elem) //본인 대체
elem.classList.contains(‘ABC’)
// Class
elem = e.target
elem.className = 'ABC'
elem.classList.add('ABC')
elem.classList.remove('ABC')
elem.classList.toggle('ABC')
// Attribute
elem = e.target
elem.getAttribute('ABC')
elem.setAttribute('ABC', 123)
- Node 을 얻는 방법
- document.querySelector() : CSS 선택자를 활용해 찾으며, 없다면 NULL 있다면 첫번째부터 찾습니다.
- document.querySelectorAll() : NodeList를 반환하며 index를 활용해 사용 가능합니다.
- document.createElement() : 새로운 DOM을 만들어낼 때 사용
- document.getElementById() : ID를 활용해 얻기
- e.target : event가 처음 발생한 그 요소
** function HANDLER(e){}로 핸들러를 만든 경우, event input를 e라고 표현했습니다. 자세한 내용은 아래에서 살펴 보도록 하겠습니다. - e.currentTarget == this : event가 bubbling & capturing 되어 찾아진 handler를 가진 요소
** capturing : event발생시 html요소부터 처음 이벤트가 발생한 요소자식까지 내려가면서 event handler가 있는지를 확인하는 것
** bubbling(기본) : event 발생시 처음 이벤트 발생한 요소부터 html요소 부모까지 올라가면서 event handler가 있는지를 확인하는 것
- Node 조작 : 위에서 DOM(Node)을 얻은 이후에 새로운 정보를 얻기 위한 방법
- .nodeName : 해당 Node의 HTML element를 의미합니다.
ex) "p", "BODY" - .parentNode : 부모 Node를 얻는 데에 사용합니다.
- .appendChild() : 해당 Node에 새로운 element를 추가할 때 사용합니다.
- .removeChild() : 해당 Node의 element를 제거할 때 사용합니다.
- .classList.contains() : 해당 Node 중 어떤 특성을 가진 것을 얻어냅니다.
- .nodeName : 해당 Node의 HTML element를 의미합니다.
- Class : Node를 얻은 이후에 class 정보를 얻기 위한 방법
- .className : 해당 Node의 Class를 의미합니다.
- .classList.add() : 해당 Node에 Class를 추가할 때 사용합니다.
- .classList.remove() : 해당 Node의 Class를 제거할 때 사용합니다.
- .classList.toggle() : 해당 Node의 Class를 Toggle할 때 사용합니다.
- Attribute : Class 이외 어떤 HTML 속성(Attribute)들이 있는지를 보여줌
- .getAttribute() : 해당 Node의 속성을 얻어냅니다.
- .setAttribute() : 해당 Node의 속성을 설정합니다.
b. Javascript 와 HTML간의 관계
// HTML 조작
const pElem = document.createElement(‘p’)
const AnotherNode = document.createElement(‘p’)
pElem.innerHTML = ''
+ '<p>'
+ '<a href = “#”>안녕></a>'
+ '</p>'
pElem.style.color = “red”
pElem.classList.add(‘newcl’)
pElem.setAttribute(‘data-id’, 123)
AnotherNode.appendChild(pElem) : 다른 곳 아래에 추가하기
// Object 속성
pElem.offsetTop
pElem.getBoundingClientRect().top
// Event Object 속성
e.target
e.currentTarget
this
e.clientX
e.clientY
e.elapsedTime
e.propertyName
// Document 속성
document.body.offsetHeight
// Window 속성
window.innerHeight
window.pageXOffset
window.pageYOffset
window.innerHeight
- HTML조작
- pElem.innerHTML = HTML : HTML element 형태를 직접 추가
- pElem.style.color = “red” : CSS style을 inline 으로 넣기
- style=“color:red”을 본인 class로 추가
ex) <div class=“card” style=“color:red;”>1</dev>
- style=“color:red”을 본인 class로 추가
- pElem.classList.add( ‘newcl’) : class를 추가
- 해당 class에 추가하고 새로운 CSS로 다루고 싶을 때
ex) <div class=“my newcl”> .newcl{CSS코드는 이미 구현되어 있음}
- 해당 class에 추가하고 새로운 CSS로 다루고 싶을 때
- pElem.setAttribute(‘data-id’, 123) : 속성(Attribute) 추가
- data-id라는 속성을 만들고 123을 넣기
- char.getAttribute(‘data-id’) : data-id의 속성 값을 얻어오기
ex) <div class=“my” data-id=123> 인 경우 123을 얻어옵니다
- 다른Node.appendChild(pElem) : 다른 곳 아래에 추가하기
- Object 속성
- Node.offsetTop : 해당 node의(주로 fig) offset을 얻기 (하지만 동적으로 제공하지 않는다)
- Node.getBoundingClientRect() : 해당 node의(주로 fig) 동적으로 offset을 얻기
- bottom, height, left, right, top …
- ie에서는 x,y지원 안합니다.
- Event Object 속성
- e.clientX, e.clientY : event function에서 e 의 속성 (해당위치 예] click인경우 click된곳)
- e.elapsedTime : event function 에서 e 의 속성(해당 이벤트 일어난 기간 = transition duration)
- e.propertyName :event function에서 e 의 속성(event발생시 발생하는 변화)
- Document Object 속성
- document.body.offsetHeight :전체 문서높이
- Window Object 속성
- window.innerHeight : 전체 창 높이
- window.pageXOffset : page X offset 얻기
- window.pageYOffset : page Y offset(scroll) 얻기
- window.innerHeight : browser의 사이즈를 얻기
c. event추가 하기
class elem = document.querySelector(‘.ABC:nth-child(3)’)
elem.addEventListener(‘click’, function(e){
console.log(e);
console.log(this);
});
window.addEventListener('scroll', function () {
clearTimeout(self.scrollState);
self.scrollState = setTimeout(function () {
self.scrollState = false;
}, 500);
});
- Event Delegate(위임) :
- .addEventListener(‘click’, ’, function(e){}, option) : 클릭에 해당하는 이벤트를 추가
- window.addEventListener(‘scroll’, handler) : 스크롤에 해당하는 이벤트를 추가
- Pagenation 등의 이벤트를 추가할 수 있습니다.
**Pagenation : 스크롤 내릴 떄 다음 데이터 가져오는 것
- Pagenation 등의 이벤트를 추가할 수 있습니다.
- window.addEventListener(‘transitionstart’) : transition으로 움직이는 element의 “시작start”에 주기
window.addEventListener(‘transitionend’) : transition으로 움직이는 element의 “끝에end”에 주기(start보다 많이 쓴다) - window.addEventListener(‘animationstart’) : animation으로 움직이는 element의 “시작start”에 주기
window.addEventListener(‘animationend’) : animation으로 움직이는 element의 “끝end”에 주기
window.addEventListener(‘animationiteration’) : animation으로 움직이는 element의 “반복될때”에 추가
**주의 animation 적용하고 나서 transform style추가해도 움직이지 않는다. - window.addEventListener(‘resize’) :창사이즈가 바뀌었을 때
- window.addEventListener(‘mousemove’) : 마우스가 움직일 때마다
e.clientX, e.clientY : 마우스의 위치 - window.addEventListener(‘keydown’) : 키보드 값 얻기
- e.keyCode : 키보드 값 ( 왼쪽 37, 오른쪽 39, 위38, 아래40…) => keycode.info
- (주의) 누르고 있는동안 계속 작동한다 ex) 어떤 값 -= 2; 하면 계속해서 줄어듭니다.
- 따라서 keyup을 활용해야 한다.
- window.addEventListener(‘keyup’) : 키보드에서 손 뗐을 때
// setTimeout
function handler1(){console.log('Timeout!!');}
timeId = setTimeout(handler1, 1000);
clearTimeout(timeId);
// setInterval
function handler1(){console.log('Timeout!!');}
timeId = setInterval(handler1);
timeId = setInterval(handler1);
clearInterval(timeId);
// requestAnimationFrame
function handler1(){
timeId = requestAnimationFrame(handler1)
}
handler1();
function handler2(){
cancelAnimationFrame(timeId )
}
button.addEventListener(‘click’, handler2);
- 타이밍 제어
- 1. setTimeout :
- setTimeout(handler1, 1000) : 1000ms후에 이 함수를 실행하세요
- timeId = setTimeout(handler1, 1000) : 몇 초 상태인지 얻기
- clearTimeout(timeId) : 취소하기
- 2. setInterval
- setInterval(handler1) :지속적으로 실행하세요
- setInterval(handler1, 1000) : 1000ms 마다 반복하세요
- clearInterval(timeId) : 취소하기
-
3. requestAnimationFrame
-
setInterval : 아무리 빠르게 반복하고 싶다고 해도, 컴퓨터가 부하가 걸리면 frame loss 및 배터리가 빨리 닳는 등 단점이 있다.
-
handler1() : 1/60초 반복으로 얻어내기 (반드시 함수로 만들어서 실행해야한다.)
-
그냥 requestAnimationFrame()하면 Reculsive하게 실행되지 않아 한번만 실행한다.
-
-
cancelAnimationFrame(timeId) : 취소
-
- 1. setTimeout :
- 추가 Tip
- 1. addEventListener 너무 많으면 memory 많이 먹어서 성능이 안좋습니다.
- 매번 event를 걸어주면 너무너무 느리므로 전체 container에 각각 속성값 별로 한번 event binding 후, 내용만 바꿔주는 방법을 택합니다.
- object마다 이벤트를 추가해야 하는 경우 object 각각의 내부의 prototype으로 미리 선언해주는 것이 좋습니다.
- 2. 부모에 addEventListener 하고 나서 handle에서 this(e.currentTarget)가 아닌 e.target을 사용하는 것이 정확히 해당 object를 활용할 수 있어 좋습니다.
- 단, exception 처리 해줘야 (e.target이 원하는 class 가지고 있을 때)
- ex) e.target.classList.contains(‘ilbuni’) -> this.removeChild(e.target)
- 3. button에 여러가지 child들이 있는 경우 (아이콘, 텍스트 …)
- (방법1) 각 아이콘마다 attribute를 제공 => HARD
- e.target.getAttribute(‘data-value’) : class 말고 어떤 속성들이 있는지를 보여줌
- e.target.dataset : “data-”로 시작하는 속성들 얻을 수 있다.
- e.target.getAttribute('data-value') 는 e.target.dataset.value와 같습니다.
- e.target.getAttribute(‘data-value’) : class 말고 어떤 속성들이 있는지를 보여줌
- (방법2) 만족할 때까지 부모 node를 확인 => 오른쪽 처럼
- elem.nodeName == ‘BODY’ 로 체크
- (방법3) css 상에서 text, 아이콘 등에 “pointer-events:none” 하면 그냥 event 안받습니다.
- 단점 : 동적으로 window.addListener로 HTML 입력될 때 혹은 child에 listener 필요할때 불편합니다.
- (방법1) 각 아이콘마다 attribute를 제공 => HARD
- 4. 어떤 해당 이벤트를 css로 구현하고 js로 주고싶을 때
- css에 “door-opened”라는 class가 생기면.. 이라고 해놓고, 원하는 event 발생시 실행시키면 됩니다.
- 5. 다른 일이 일어났을 때 원래 것들을 원상복구 하고 싶다면
- (방법1) “.해당클래스” 가진 것들을 찾아내서 해당 class를 remove! (오른쪽)
- DOM에 접근하는 것은 가장 느린 것중에 하나여서 느린 방법중에하나입니다.
- +class를 직접적으로 찾는 것은 바람직한 방법이아니다
- (방법2) function(){}내부의 지역변수를 활용하자 (오른쪽)
- 로컬 변수로 현재 활성화된 것에 대한 flag를 만들어 놓습니다.
- (방법1) “.해당클래스” 가진 것들을 찾아내서 해당 class를 remove! (오른쪽)
- 6. Scroll을 어떤 값으로 사용할 때
- (스크롤 범위 알아내기) document.body.offsetHeight – window.innerHeight
- 전체문서 높이 - 창 사이즈 = 스크롤 범위
- normalize 해서 사용해야 window사이즈가 바뀌어도 쓸 수 있습니다.
- 창 사이즈 바뀌었을 때 load 될때의 window.innerHeight와 다를 텐데?
- window.addEventListener(‘resize’) :창사이즈가 바뀌었을 때
- 위 이벤트를 활용해 바뀔 때마다 다시 maxScrollValue를 다시 구해줍니다.
- Scroll 상향 하향 판단 : global 변수로 이전 위치를 저장해두고, 이후에 비교 하는 방식으로 확인할 수 있습니다.
- (스크롤 범위 알아내기) document.body.offsetHeight – window.innerHeight
- 1. addEventListener 너무 많으면 memory 많이 먹어서 성능이 안좋습니다.
https://www.inflearn.com/course/interactive_web/unit/20059?tab=curriculum
'Developers 공간 [Basic] > Frontend' 카테고리의 다른 글
[Flutter] 프로젝트 시작하기 (0) | 2023.02.18 |
---|---|
[Web] React와 Typescript 시작하기 (0) | 2023.01.06 |
[Web] HTML/CSS 기초 문법 정리 (0) | 2022.12.21 |