브라우저에서는 HTML코드를 DOM(Document Object Model)이라는 객체형태의 모델로 저장합니다.
그렇게 저장된 정보를 DOM Tree 라고 함. 결국 HTML element는 Tree형태로 저장됩니다.
https://velog.io/@seokzin/JavaScript-자주-사용하는-DOM-API-정리
var input2 = document.querySelector("input[name='input2']");
input2.addEventListener("focusout", e=>{ e.target.value }); -> e.target.value는 input2의 값
var message = document.querySelector(".message");
message.innerHTML = "";
// 직접 css 값을 변경하는 것보다는 classList(DOM API)를 사용해서 클래스를 변경시켜주는 방법이 좋다.
addClass, removeClass
// 노드 탐색 방법
// 요소 접근
document.getElementById()
document.querySelector()
document.querySelectorAll()
// 자식 접근
div.firstChild -> 줄바꿈이 있다면 #text로 공백 텍스트를 찾게 됨
div.firstElementChild -> 공백(#text)이 아닌 요소를 찾아줌
ul.childNodes -> 리스트 형태로 자식 요소를 보여줌
firstLi.nextSibling -> 공백 #text
firstLi.nextElementSibling -> <li>...</li>
// 노드 타입의 이해
document.body.tagName -> "body", "div", "table" 등
document.querySelector("li:nth-child(3)")
div1.nodeType -> elementNode: 1, textNode: 3
div1.textContent -> 태그 내에 있는 모든 텍스트 노드를 출력
// 노드의 생성과 추가
var div = document.createElement("div")
var str = document.createTextNode("hello world")
div.appendChild(str)
insertBefore(div, base) -> base 앞에 div를 집어 넣음, 많이 사용하는 기법
// base는 3번째 열, div는
innnerText -> 안에 있는 모든 텍스트 가져옴
innerHtml -> getter의 역할
.innerHtml() -> setter의 역할, createElement 등의 작업을 생략하고,
// "<p>...</p>"의 형태로 추가하면 훨씬 작업이 쉽고 편리하고 빠르다.

네이버 D2, 데뷰를 참조한 것이 좋다.
네이버 whale? 크롬을 기반으로 extend한 브라우저 → 발표자료나 성능, 렌더링에 대한 것을 알 수 있어 성능이 좋은 코드를 짤 수 있다.
https://tv.naver.com/v/4578425
/* first selector */
.btn{
font-size: 20px;
color: #ff23a1;
background-color: white;
}
/* second selector */
nav#nav div.pull-right .btn{
background-color: blue;
}
/* third selector */
a{
background-color: green;
}
/* forth selector */
#nav a.btn:hover{
background-color: orange;
}

인라인 태그(태그에 직접 적용) 확인 → id 확인 → 클래스 개수가 높은 거 → selector 개수가 많은 거 선택해서 적용
https://heropy.blog/2018/11/24/css-flexible-box/
https://www.youtube.com/watch?v=pgFyqS4oCIc
// container
display: flex;
flex-direction: row;
flex-flow: column wrap
// item
flex-grow: 2; // 여백의 비율을 조절함
justfy-content: flex-end
justfy-content: space-around ??
// modal
position: fixed;
top: 0;
right: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center; // 가로 정렬, 주축 정렬
align-items: center; // 세로 정렬, 교차축 정렬
z-index: 50;
document.querySelector("body").addEventListener('click', close_user_nav_menu);
const menu = document.getElementById('user_nav_menu');
const btn = document.getElementById('btn_user_nav');
if(!(menu.contains(e.target) || btn.contains(e.target))&&!menu.classList.contains('hidden')){
// document.getElementById('user_nav_menu').classList.toggle('show');
menu.classList.toggle('hidden');
}
https://endorphin0710.tistory.com/75
본인이 너비를 지정해놓았음에도 패딩과 보더값에 의해서 너비가 변경되어 불편하시다면 현재 content-box가 적용되어 있는 겁니다.
border-box로 변경하고 싶으시다면 아래와 같이 브라우저별로 적용해주시면 됩니다.
* {
box-sizing: border-box; /* 오페라(Opera) */
-moz-box-sizing: border-box; /* 파이어폭스(Firefox)*/
-webkit-box-sizing: border-box; /* 웹킷(Webkit) & 크롬(Chrome) */
}
https://velog.io/@rohkorea86/NodeJS-pug에서-mixin-사용하는-법-hejr0qd09g
함수 라고 생각하면 쉽다. 우선 (함수)이름이 있고, 인자 "()"를 받는다. 함수는 어떤 로직을 덩어리로 묶어 둔 주머니와 같다.
인자를 받지 않는 경우
우선 mixin 이라고 적고, 그 다음에 (함수)이름을 적는다.mixin을 사용할 경우 "+" 을 넣어준다.
// videoBlock.pug
mixin videoBlock(video= {})
div.videoBlock
video.videoBlock__thumbnail(src=video.videoFile,controls=true)
h4.videoBlock__title = video.title
h6.videoBlock__view=video.views
// home.pug
include mixins/videoBlock
each object in videos
+videoBlock({
title: object.title,
description: object.description
})
beforeend
사진 크기 맞추기
#main .rooms_img img{
width: 300px;
height: 200px;
object-fit: cover;
}
https://hee-kkk.tistory.com/22
parent.childNodes -> '#text' 포함한 결과
parent.children -> 'element'만 포함한 결과
parent.firstchild -> 'element'만
e.target
e.currenttarget
지금 모든 .day 요소에 반복을 하여 이벤트 리스너를 부여하고 있는데요, 나중에 다시 달력을 그릴 때 마다 계속 이벤트를 걸어줘야되고, 비슷한 이벤트를 매번 30여번 부여하는 등의 '낭비'가 발생할 수 있습니다. 이를 해결하는 방법은 이벤트 위임(Event delegation)을 통하여 최상위의 하나의 엘리먼트에 이벤트를 걸어주고, 이벤트 객체에서 발생한 엘리먼트를 특정하여 이벤트를 발생하는 패턴입니다. https://ko.javascript.info/event-delegation 등을 참고해주세요!
https://tv.naver.com/v/5012344
https://stackoverflow.com/questions/26848289/javascript-queryselector-vs-getelementbyid
querySelector is the newer feature.
getElementById is better supported than querySelector.
querySelector is better supported than getElementsByClassName.
querySelector lets you find elements with rules that can't be expressed with getElementById and getElementsByClassName
.tab_menu::before {
background-color: black;
position: absolute;
height: 2px;
bottom: 0px;
margin-left: -9px;
left: 50%;
content: "";
width: 18px;
transform: scaleX(0);
transition: 0.2s -ms-transform cubic-bezier(0, 0, 0.1, 1),0.2s -webkit-transform cubic-bezier(0, 0, 0.1, 1),0.2s transform cubic-bezier(0, 0, 0.1, 1);
}
/* 탭 기능 */
.tab_selected:before{
transform: scaleX(1);
}
mouseover
mouseout
var el = document.getElementById("outside");
el.addEventListener("click", function(evt){
console.log(evt.target);
console.log(evt.target.nodeName);
debugger // break point를 걸어줌 -> F12의 source 탭에서 확인 가능
}, false);
싱글페이지 어플리케이션
UX가 중요하다
서버 사이드 렌더링
리액트의 첫 화면이 늦게 뜨는 것에 대한 해결방법 → 여러가지
(첫 화면 뜨고, API 요청하고, 템플릿 만들고.. 등등)
리액트에서 첫 화면을 만들 때, 서버에서 렌더링을 하는 것
그냥 서버에서 렌더링해서 보내는 것을 의미하는 것과는 요즘 다르게 쓰이고 있음
document.querySelector() → _el(selector, baseNode=document ) 등으로
default parameter 사용
리액트는 돔 조작을 도와주는 라이브러리
<script type="module" src="js/module.js">
// module.js
export {}
// main.js
import {} from 'module.js'
// index.html
<script type="module" src="main.js">
e.target.closest('') → 가장 가까운 걸 찾음
el.dataset.data1
핸들러 함수로 묶어서 init 함수로 실행
모듈 구조를 참고할 것
이벤트 델리게이션으로 이벤트를 for문으로 호출하지 않아도 된다
자식 노드에 접근할 때 [1] 등으로 접근하지 않는 것이 좋다 → 대신 querySelector로 자식 선택 가능
https://im-developer.tistory.com/115 참고
https://developer.mozilla.org/ko/docs/Web/CSS/Using_CSS_custom_properties
https://ko.javascript.info/modules-intro
https://programmingsummaries.tistory.com/313
https://pro-self-studier.tistory.com/108
.modal_content{
position: relative;
border-radius: 10px;
background-color: #ffffff;
width: 30%;
height: 500px;
overflow-y: auto;
padding:15px 15px;
animation: modalShowUp 4s ease-in-out
}
@keyframes modalShowUp{
from{
opacity: 0;
transform: translateY(200px);
}
to {
opacity: 1;
transform: none;
}
}
#search{
margin: 0 auto;
width: 100%;
transition: all 0.1s ease-in;
}
#search.scroll{
margin: 0 auto;
width: 0;
height: 0;
transform: translateY(-100px);
opacity: 0;
}
// 스크롤 이벤트
window.addEventListener('scroll', scrollHandler);
function scrollHandler(){
if(window.scrollY >= 10 && !$('#header').classList.contains('scroll'))
$('#header').classList.add('scroll');
else if(window.scrollY < 10 && $('#header').classList.contains('scroll'))
$('#header').classList.remove('scroll');
}
function computePageButton(totalLength, curPage, pageLength, url, query){
const page = []; // 페이징 정보를 담은 배열
const numOfButton = 5; // 페이지 버튼 개수
const maxPageNum = Math.ceil(totalLength/pageLength); // 최대 페이지
let rurl = `${url.split('?')[0]}?location=${query.location}&checkin=${query.checkin}&checkout=${query.checkout}&guests=${query.guests}&page=`;
curPage = parseInt(curPage);
let startIndex; // 시작 페이지
if( curPage < Math.ceil(numOfButton/2)){
startIndex = 1;
} else if(curPage > maxPageNum - Math.ceil(numOfButton/2)){
startIndex = maxPageNum - numOfButton + 1;
} else{
startIndex = curPage-2;
}
const endIndex = (startIndex+numOfButton) > maxPageNum ? maxPageNum : (startIndex+numOfButton);
if(curPage > 1) page.push({name:'<', href:rurl+(curPage-1)});
for(let i=startIndex-1; i<endIndex; i++){
if(i === curPage-1) page.push({name:i+1, href:rurl+(i+1), curPage:true});
else page.push({name:i+1, href:rurl+(i+1)});
}
if(curPage < maxPageNum) page.push({name:'>', href:rurl+(curPage+1)});
return [...page];
}