브라우저에서는 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];
}