I. DOM
1. 이벤트
(1) 이벤트 객체 클릭했을 때 태그 찾기
1) 클릭했을 때 색 바꾸기
<ul>
<li class="current"><span>1</span></li>
<li>
<div>
<span>2</span>
</div>
</li>
<li><span>3</span></li>
<li><span>4</span></li>
</ul>
.s2 ul{
padding: 0;
list-style-type: none;
display: flex;
}
.s2 span{
display: inline-flex;
width:100px;
height: 100px;
align-items: center;
justify-content: center;
color: white;
font-weight: bold;
background-color: blue;
/* transition: .5s; */
}
.s2 li.selected .box,
.s2 li.selected span
{
/* 애니메이션 넣기 */
animation-name : selectedani;
animation-duration: 2s;
animation-direction: alternate;
}
let section = this.document.getElementsByTagName("section")[0];
let ul = section.querySelector("ul");
let current = ul.querySelector("li.current");
let lis = ul.querySelectorAll("li");
// let lis = ?;
for(let li of lis)
li.onclick = function(e){
current = e.target;
current.style.backgroundColor = "red";
}
그런데 치명적인 오류가 있어! span에 다가 적용되는게 문제야!
2) span 적용 문제
current 는 타겟이 아니라 부모의 요소로 볼 수있어.
for(let li of lis)
li.onclick = function(e){
// current = e.target;
current = e.target.parentElement;
console.log(current);
current.style.backgroundColor = "red";
}
}
li 태그가 클릭된다 그런데 클릭을 해도 색상은 바뀌지 않는다.
대상을 잘 잡아줘야해
3)span 적용문제 해결하기 -> li에 적용하기
let section = this.document.getElementsByTagName("section")[0];
let ul = section.querySelector("ul");
let current = ul.querySelector("li.current");
let lis = ul.querySelectorAll("li");
// let lis = ?;
for(let li of lis)
li.onclick = function(e){
// current = e.target;
current = e.target.parentElement;
console.log(current);
// current.style.backgroundColor = "red";
current.firstElementChild.style.backgroundColor = "red";
}
parentElement 를 선택해서 current에 넣는다
그러고 나서 firstElementChild로도 가능하다 (즉 첫번재 요소 만 잡아주기)
이렇게 하면 li가 잡히면서 가능해
4) 보다 바람직한 해결방법
ul태그 안에 span찾는 것을 해보자!
// let lis = ?;
for(let li of lis)
li.onclick = function(e){
// current = e.target;
current = e.target.parentElement;
// console.log(current);
// current.style.backgroundColor = "red";
// current.firstElementChild.style.backgroundColor = "red";
//while문으로 이용방법
let span = current.firstElementChild;
while(span.tagName !== "SPAN") //대문자로!
span = span.firstElementChild;
console.log(span);
//??????
span.style.backgroundColor = "red";
//for문 이용방법
// for(let span = current.firstElementChild;
// span.tagName !== "span";
// span = span.firstElementChild);
}
span 에서 tagName 이 SPAN일 때 까지 찾는방식이야
그리고 찾았을 때 해당 요소를 span안에 대입하는 방식이야
이 방식을 기본으로 두고 꼭하자!!
(2) 클릭 했을 때 스타일 변경 시키기
1) li 태그 찾아주기와 클래스name이 current인 것 찾기
li태그 current찾고 나서, span에다가 스타일 적용하는것이 목적이다
- current 잡아주기
<ul>
<li class="current"><span>1</span></li>
<li>
<div>
<span>2</span>
</div>
</li>
<li><span>3</span></li>
<li><span>4</span></li>
</ul>
li 태그안 div태그가 잡히는것을 방지하고 span까지 가기위해서 만들어진 코드
// 뭘하는거임??
current = e.target.parentElement;
while(current.tagName !== "LI") //대문자로!
current = current.firstElementChild;
현재 클릭한것에서 li찾기
2) 태그의 클래스명을 바꾸어서 본 스타일을 적용시키는 방식
{
let section = this.document.getElementsByTagName("section")[0];
let ul = section.querySelector("ul");
let current = ul.querySelector("li.current");
let lis = ul.querySelectorAll("li");
for(let li of lis)
li.onclick = function(e){
// 뭘하는거임??
current = e.target.parentElement;
while(current.tagName !== "LI") //대문자로!
current = current.firstElementChild;
//while문으로 이용방법
let span = current.firstElementChild;
while(span.tagName !== "SPAN") //대문자로!
span = span.firstElementChild;
console.log(span);
// 이렇게 스타일을 적용하는 것은 바람직하지 않다.
// 왜냐 나중에 생각이 바뀌어서 다양하게 하고싶은데, 스타일을 코드로 하면안된다
//js로 한다는거는 동적인것인데, 시작할 때 거는 미리 준비하게 해야한다
//이렇게 보다는 현재 선택된 녀석의 스타일의 클래스명을 바꾸자!!
span.style.backgroundColor = "red";
console.log(current);
}
}
스타일은 js로 하기보다, 미리만들어 놓을 수 있는 스타일은 만든다
그리고 태그의 클래스명을 바꾸어서 본 스타일을 적용시키는 방식으로 하자
.s2 li.current .box,
.s2 li.currnet span
{
background-color: red;
}
li 태그에, current라는 클래스를 추가해주는 것을 고민해보자
// 4. 이벤트 객체
{
let s1 = document.querySelector(".s2");
let ul = s1.querySelector("ul");
let current = ul.querySelector("li.current");
let lis = ul.querySelectorAll("li");
for(let li of lis)
li.onclick = function(e){
//* 현재 선택된 노드를 찾고
current = e.target.parentElement;
while(current.tagName !== "LI")
current = current.parentElement;
//* 선택된 노드임을 표시하는 스타일 변경
current.classList.toggle("current");
console.log(current);
}
}
current.classList.toggle 를 이용한다
토글 방식으로 current를 넣었다가 빼엇떤 방식으로 on/off 방식으로 설정이 쉽게 가능하다.
(3) 두개 클릭했을 때 서로 바꾸기
1) 콘솔로 띄어보기
두개를 클릭했을 때 두개를 맞바꾸는 것을 구현해보자!
같은 부분을 두번 클릭했을 때 콘솔에 띄우는 방법을 알아보자
두가지 방법이 있는데, 모든 요소들을 순회하는 방법보다, 그 부분만 셀렉터를 이용해서 들고 온 뒤에 log를 띄어주면 된다.
//다음처럼 for문을 사용하는 코드는 바람직하지 않다
{
let lis = ul.querySelectorAll("li");
let hasCurrent = false;
for(let li of lis){
if(li.classList.contains("current")){
hasCurrent = true;
console.log()
}
break;
}
}
//위의 방법보다 다음처럼 그냥 있는지 쉽게 확인할 수 있다
if(ul.querySelector("li.current"))
console.log("두번째 선택");
이 경우 위와같이 두가지 방법이 있다
첫번째는 for문으로 순회하면서 같은게 있는 찾는 방법
두번쨰는 css 셀렉터 방식을 이용해서 바로 찾는 방식이다 (부모로 올라가서!)
성능 등 다양한 방식을 고려 하면후자가 바람직 하다고 볼 수 있다.
2) 바꿔주기
{
let s1 = document.querySelector(".s2");
let ul = s1.querySelector("ul");
let current = null; // ul.querySelectorAll("li.current");
let lis = ul.querySelectorAll("li");
for(let li of lis)
li.onclick = function(e){
if(ul.querySelector("li.current"))
let selected = ul.querySelector("li.current");
if(current){
// *** 실습 3 ; 박스 위치 바꾸기, selected.classList.add("selected"); 이용!!
//공식
let selected = e.target.parentElement;
while(selected.tagName !== 'LI')
selected = e.parentElement;
selected.classList.add("selected");
//선택 된것 앞부분의 위치를 저장한다
let selectedBefore = selected.previousElementSibling;
//replaceWith를 이용해서 요소를 넣어준다
current.replaceWith(selected);
//저장한 위치가 있으면 거기 뒤에 current를 넣어준다.
if(selectedBefore)
selected.after(current);
else //엎으면 앞에 넣어준다.
ul.prepend(current);
//기존것은 제거해준다
current.classList.remove("current");
//이전에 클릭했던 내용을 없애준다.
current=null;
//색변화는 안되게끔해준다.
return;
}
}
1 append : dom tree에 추가
2 prepand : 특정 요소의 첫번째 자식앞에다가 매개변수의 요소를 넣어준다.
3 replaceWith :
Element.replaceWith()
Element는 부모가 있는 자식이다.
이 자식대신에 () 매개변수를 넣어주면 매개변수 값이 대신 위치하게 되는 것을 의미한다.
4 after
let container = document.createElement("div");
let p = document.createElement("p");
container.appendChild(p);
let span = document.createElement("span");
p.after(span);
console.log(container.outerHTML);
// "<div><p></p> <span></span> </div>"
after은 엘레먼트 끝나고 바로다음에 넣어주는 방식이다.
span은 p 태그 다음에 들어왔다.
4가지 방식으로 위 문제를 해결 할 수 있다
2. CSS
(1) transform 과 trasition
1) transform
.s2 li.current span
{
background-color: red;
border: 3px solid yellow;
width: 120px;
height: 120px;
/* 다른 크기 영향안받고 해주기 */
transform: scale(1.2, 1.2);
}
이렇게 하면 크기를 변형할 수있다.
2) trasition
.s2 span{
display: inline-flex;
width:100px;
height: 100px;
align-items: center;
justify-content: center;
color: white;
font-weight: bold;
background-color: blue;
transition: .5s;
}
.5s 를 하면 0.5초 동안 변화할 수있다.
(2) 애니메이션
1) 의의
mdn 의 말처럼 이는 스타일의 변화를 부드럽게 하기 위함이다.
2) @keyframes
애니메이션관련
본 내용과 같이 trasitions 와 변화를 할 때 의 중간단계에 관련해서 컨트롤할 수있는 방법이다
각 시퀀스 중간중간에 다양한 방식으로 넣어 줄 수있다.
@keyframes zoomin {
/* 처음에는 얼마였다가 */
from {
transform: translateX(1,1);
}
/* 50% 왔을 때 다른값을 할 것이다. */
/* 50%{
} */
/* 나중에는 얼마로 바뀔 것이다. */
to {
transform: translateX(1.2,1.2);
}
}
1.1 에서 2.2까지
.s2 li.current span
{
background-color: red;
border: 3px solid yellow;
width: 120px;
height: 120px;
/* 다른 크기 영향안받고 해주기 */
/* transform: scale(1.2, 1.2); */
/* 애니메이션 넣기 */
animation-name : zoomin;
animation-duration: 1s;
animation-iteration-count: infinite;
animation-direction: alternate;
}
그리고 애니메이션을 적용하고 넣기 위해서는 다음과 같이 애니메이션을 넣어주어야해
이름, 기간, 반복, 방향 이런것을 넣어주면돼
- duration은 한싸이클의 애니메이션이 얼마에 걸쳐일어날지
- interation-count 는 몇번 반복될지이다. (이 경우 infinite 이면 무한반복이다)
- direction 은 다시 시작할디지 역방향으로 할지 지정하는 것이다. (alternate 는 주기마다 방향을 바꾸는 것이다.)
그런데 애니메이션이나 트랜지션은 같이 쓰면안돼
둘 다 있으면 그 효과가 중복되기 때문이야
3) 다양한 애니메이션 설정
애니메이션 관련 조건 설정 -> 애니메이션 이벤트
애니메이션의 어떤 이벤트가 있는지 확인해야해
@keyframes zoomin {
/* 처음에는 얼마였다가 */
from {
transform: translateX(1,1);
}
/* 50% 왔을 때 다른값을 할 것이다. */
30%{
transform: rotate(360deg);
}
60%{
transform: rotate(-360deg);
}
/* 나중에는 얼마로 바뀔 것이다. */
to {
transform: translateX(1.2,1.2);
}
}
@keyframes currentani {
/* 처음에는 얼마였다가 */
from {
transform: translateX(1,1);
}
/* 나중에는 얼마로 바뀔 것이다. */
to {
transform: translateX(1.2,1.2);
}
}
@keyframes selectedani {
/* 처음에는 얼마였다가 */
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.s2 ul{
padding: 0;
list-style-type: none;
display: flex;
}
.s2 span{
display: inline-flex;
width:100px;
height: 100px;
align-items: center;
justify-content: center;
color: white;
font-weight: bold;
background-color: blue;
/* transition: .5s; */
}
.s2 li.selected .box,
.s2 li.selected span
{
/* 애니메이션 넣기 */
animation-name : selectedani;
animation-duration: 2s;
animation-direction: alternate;
}
.s2 li.current .box,
.s2 li.current span
{
background-color: red;
border: 3px solid yellow;
width: 120px;
height: 120px;
/* 다른 크기 영향안받고 해주기 */
/* transform: scale(1.2, 1.2); */
/* 애니메이션 넣기 */
animation-name : zoomin;
animation-duration: 1s;
animation-iteration-count: infinite;
animation-direction: alternate;
}
{
let s1 = document.querySelector(".s2");
let ul = s1.querySelector("ul");
let current = ul.querySelector("li.current");
let lis = ul.querySelectorAll("li");
for(let li of lis)
li.onclick = function(e){
if(current){
console.log("두번째 선택");
//공식!!!
let selected = e.target.parentElement;
while(selected.tagName !== "LI")
selected = selected.parentElement;
console.log(current);
selected.classList.add("selected");
return;
}
//* 현재 선택된 노드를 찾고
current = e.target.parentElement;
while(current.tagName !== "LI")
current = current.parentElement;
//* 선택된 노드임을 표시하는 스타일 변경
current.classList.toggle("current");
console.log(current);
}
}
결국 이런 경우에
애니메이션 이벤트발생조건으로 selected 인경우 current 인경우 각각을 넣어주면된다
1. 보충
(1)
2. 회고
1) 바람직한 방법으로 dom 조작과 css 컨트롤은 녹록치 않다
선생님이 말씀하신것처럼 이것은 긴 기간 해보면서 익혀지는것이라 하셨으니, 당장 욕심을 내기보다 추후에 하면서 한번씩 다시 보는 방식도 괜찮을 것같다.
'배움 __IL > TIL 1기' 카테고리의 다른 글
TIL : 98번째- 230426 [4-4-수] (0) | 2023.04.26 |
---|---|
TIL : 97번째- 230425 [4-4-화] (1) | 2023.04.25 |
TIL : 94번째- 230420 [4-3-목] (0) | 2023.04.20 |
TIL : 93번째- 230419 [4-3-수] (4) | 2023.04.19 |
TIL : 92번째- 230418 [4-3-화] (0) | 2023.04.18 |