[FE] 헤더에 hover할 때 메뉴 나오도록 하기 (getBoundingClientRect())

이거 하나 만드는데 너무 오래걸렸다 흑흑... 너무 멍청한 실수를 했기때문인데, 실수1) hover 처리를 자바스크립트에서 하려고 한 점, header 아래에 나올 이 밀리면 안되고 메뉴에 덮여야 한다는

ala-nueva.tistory.com

 
 
어제 다 해놓고 서버에 적용할때 안떠서 당황했는데, 나중에 뒤지면서 보니 내가 어제 d:none 이나 opacity설정을 넣었다뺐다 하면서 테스트하다가 메뉴 내부 css에 opacity:0으로 되어있어서 그런거였다................... 이게 개발자도구에선 메뉴가 계속 투명으로 보임 + 계속 전체를 감싼 부모박스만 체크하느라 내부 속성이 보이질 않음의 총체적 난국이라 발견이 늦었음.
 
뭐가 잘못된줄 알고 작은 박스를 새로 만들어서 한참을 예행연습하고도 또 적용이 안되길래 그제서야 css를 깊숙히 뒤져본 나란 인간.. ㅠ ㅠ
그래도 덕분(?)에 더 나은 방향으로 일단 하긴 했으니 다행이라 해야할지 😂 다음엔 생각지 못한 부분도 꼭 찾아보자...
 
 
 

개선사항1) css 속성에 opacity와 top을 사용해서 위에서 아래로 내려오도록 구현함.

: 원래대로 d:none을 사용했으면 엄청 어색했을텐데 absolute로 left는 조정했으면서 top으로 위에 숨겨놓고 내려오게 한단 생각을 왜 못했는지 모르겠다.d:none에 너무 꽂혀있었음.
 

.octaheader {
	background-color: white; // 기본으로 투명이라 숨어있는 메뉴를 가리기위해 흰색으로 지정해줌
	position:relative;
}

.octaheader .parent:hover .menubox { // 헤더+메뉴가 같이감싸진 부모에 hover를 줘야 메뉴에 마우스가있어도 안사라짐
	position: absolute; //위치지정을 위한 absolute
	left: 460px; // js에 의해 left값은 계속 바뀐다
	transition: top 0.2s ease-out, opacity 1s ease-in; // 적당한 눈속임을 위한 transition
	top: 57px; // 헤더 선을 살짝 가리도록 1px 줄임
	opacity:1; // 나타나면서 불투명이 됨
	z-index:999; // 다른 부분과 겹칠때 묻힐때가 있어서 가장 앞으로 꺼내줌
}

.menubox{
	position: absolute;
	top: -72px; //숨어있음
	opacity:0; //투명
}

 
 

개선사항2) hover속성은 css로만 끝내고 js는 left만 계산함. 이때 load보다 더 빠르게 구동되게함. (튕김방지)

window.addEventListener("DOMContentLoaded", function() {
	let header = this.document.querySelector(".octaheader");
	let menubox = header.querySelector(".menubox");
	let logo = header.querySelector(".logo-mini");
	
	setLeftPosition();

	function setLeftPosition() {
		let x = logo.getBoundingClientRect().left;
		let leftValue = x - 22;

		// left 속성 설정
		menubox.style.left = leftValue + "px";
		console.log(leftValue);
	}

	// 초기화 및 리사이즈 이벤트에 대한 처리
	window.addEventListener("resize", setLeftPosition);

});

 

Window: DOMContentLoaded 이벤트 - Web API | MDN

DOMContentLoaded 이벤트는 HTML 문서가 완전히 구문 분석되고 모든 지연된 스크립트(<script defer src="…">와 <script type="module">)가 다운로드되고 실행될 때 발생합니다. 이미지, 서브프레임, 비동기 스크

developer.mozilla.org

 
문서에 이미지가 다 생기고 나서 js가 작동하다보니 자꾸 오른쪽에서 왼쪽으로 튕기듯 메뉴가 나오는게 적나라하게 보였다. 그래서 dom이 분석되자마자 비동기적으로 적용될 수 있도록 DOMContentLoaded 이벤트로 읽어들여줌.
 
mdn에서 보니 원래 대상은 로드된 문서라는데, 그래도 다른로드보다 빨리 되다보니 딜레이 현상이 줄었다. 좀더 매끄럽게 하려면 어떻게 할지 고민해볼것...
 
 

 
 

좌표까지 캡쳐를 뜬데엔 이유가있음 !

 

이거 하나 만드는데 너무 오래걸렸다 흑흑... 너무 멍청한 실수를 했기때문인데,

 

 

실수1) hover 처리를 자바스크립트에서 하려고 한 점, header 아래에 나올 <main>이 밀리면 안되고 메뉴에 덮여야 한다는 점.

  • 자바스크립트에서 mouseover 이벤트로 menu가 활성화되는 클래스를 추가하려고 함
  • d:none속성을 넣었다 뺐다 하고, 메뉴위에 마우스가 있을때 떠있게하고, 나갈때 사라지도록 설정함

여기서 부드러운 액션에 opacity속성을 쓰지않은 이유

: opacity를 쓰면 마우스가 헤더에 가지않고 메뉴가 뜨는 곳에 가기만 해도 갑자기 메뉴가 생긴다. 저 공간 자체에 투명으로 숨어있게 되기 때문에 아예 사라져야하는 상황은 opacity를 쓸 수 없었음. (그래서 setTimeout으로 시간차로 생기게 해서 뭔가 부드러운 느낌을 주려고 오만 난리를 침)

 

👉 설정했더니 메인에 있는 글씨 (글자가 있습니다) 가 밀려서 실패.

 

일반적인 접었다 펴기 공식처럼 height:0으로 두고 hover조건에서 펼치지 못한 이유

자손에 높이를 가진 박스가 하나뿐이면 없앴다가 줄 수 있는데, 나같은 경우는 자손의 자손들에 개별 높이를 가지고있는것들이 많았다. 그레서 메뉴박스 자체의 높이를 0으로 설정해봤자 안에서 글씨를 감싸는 박스들의 개별높이가 살아있기때문에 글씨만 동동 떠있게 됨. 그렇다고 그 모든 높이를 0으로 바꾸고 hover때 부여해주기엔 .... 이건 좀 아닌것 같았다.

 

✔️ 이 부분 결국 코드수정하면서 top과 opacity속성을 써서 구현했다.! 다음 포스팅에 정리해둠!

 

 

 

 

실수2) position 속성만으로만 해결할 수 있다고 생각한 점

.octaheader>div {
    position: relative;
}

.octaheader>div:hover .header-m {
    display: flex;
}

.header-m {
    position: absolute;
    display: none;
    left: 460px;
}

 

 

[css 응용] 스크립트 없이 드롭다운 메뉴 만들기 (drop down menu)

마우스를 오버해서 나타나는 드롭다운 메뉴를 만드는데에 html 구조와 css만을 이용해서 작업할 수 있다. 1. html 구조 만들기 단순히 css만 이용한다고해서 드롭다운 메뉴를 만들 수 있는 것은 아니

abcdqbbq.tistory.com

위 포스팅을 참고해서 부모속성(헤더와 메뉴를 모두 감싸고 있다)에 relative를 주고, 튀어나올 메뉴에다가 absolute를 줬다. 이때 hover는 각 li가 아니라 li들을 감싸고 있는 div에다가 줘야 (쉽게말하면 부모속성) li안의 a링크로 마우스가 옮겨갔을때 배경이 사라지지않는다.

 

이제 main이 밀리지않고 덮이니까 잘됐다고 생각하고 있었는데 아맞다... 이거 화면 반응형이다 ㅠ ㅠ

(저기있는 460은 내가 보고있던 화면에서의 위치로 그냥 숫자를 박아둔것)

 

 

 


 

 

🔥 해결책) 좌표구해서 대입하기

그럼 가변하는 left의 위치를 어떻게 구해야 할지 고심을 많이 했다.

전체 넓이의 1/5 이런식으로 left를 잡기엔 화면이 바뀔때마다 조금씩 틀어져서 이건 좀 아닌것 같았고.

// 찾아보며 알게된 뷰포트 폭 가져오는법 ==============
// 화면 너비와 부모 요소의 너비 가져오기
const viewportWidth = window.innerWidth;
const parentWidth = parent.clientWidth; // 부모 요소의 너비

// left 값을 동적으로 계산 (예: 부모 요소 너비의 중앙으로 정렬)
// const leftValue = (parentWidth - menu.clientWidth) / 2;

 

그러던 중, 그나마 눈에 보이는 OctaP로고의 좌표를 따올 수 있지 않을까? 라는 생각이 들었다! 다행히 가능한 방법이 있었다. 감사합니다 자바스크립트...................

 

#️⃣ getBoundingClientRect()

getBoundingClientRect() 메서드는 DOM 요소의 위치와 크기 정보를 제공하는 메서드. 이 메서드를 호출하면 요소의 위치, 폭, 높이 등에 관한 정보를 담고 있는 DOMRect 객체를 반환한다.

속성들!
x: 요소의 왼쪽 가장자리의 X 좌표 (page X 좌표)
y: 요소의 위쪽 가장자리의 Y 좌표 (page Y 좌표)
width: 요소의 폭
height: 요소의 높이
top: 요소의 상단 가장자리의 Y 좌표
right: 요소의 오른쪽 가장자리의 X 좌표
bottom: 요소의 하단 가장자리의 Y 좌표
left: 요소의 왼쪽 가장자리의 X 좌표

 

 

Element.getBoundingClientRect() - Web API | MDN

Element.getBoundingClientRect() 메서드는 엘리먼트의 크기와 뷰포트에 상대적인 위치 정보를 제공하는 DOMRect 객체를 반환합니다.

developer.mozilla.org

 

window.addEventListener("load", function () {
    let octaheader = this.document.querySelector(".octaheader");
    let menu = this.document.querySelector(".header-m");
    let logo = octaheader.querySelector(".logo-mini");

    function setLeftPosition() {
        let x = logo.getBoundingClientRect().left;
        console.log(typeof (x)); //number 반환
        let leftValue = x - 22; //추가로 폭 조절해줌

        // left 속성 설정
        menu.style.left = leftValue + "px";
        console.log(leftValue); //캡쳐에 있던 최종 좌표
    }
    
    // 초기화 및 리사이즈 이벤트에 대한 처리
    setLeftPosition(); //초기화하여 현재 화면에서의 x값 넣기
    window.addEventListener("resize", setLeftPosition); //화면이 변했을때 이벤트로 함수 전달
});

여기서 나오는 left(x좌표) 는 화면의 좌상단 꼭지점을 0으로 해서, 실제 컨텐츠 크기까지를 구해준다. 그리고 메뉴박스가 아이콘보다 더 옆으로 가야해서, 구해진 크기보다 왼쪽으로 좀더 옮겨줘야 메뉴박스만의 x좌표가 구해지기에 추가로 조절을 해줬다!

 

그리고 잊지말고 마지막에 함수 실행을 해줘야 현재 화면에서(onload 이벤트) 맞는 좌표가 들어가고,

화면이 변했을때 이벤트리스너에있는 함수가 작동해서 (resize이벤트) 다시 left값을 전달해준다.

 

지난주에 콜백함수 다시 보고 와 모르겠다 모르겠다 했는데 어쩌다보니 여기서 콜백함수를 쓰게됐다. 쓰려고 쓴건 아니고 어떻게저떻게 하다보니 형태가 어 ..? 콜백이었네 콜백을 이렇게 쓰는거네 배워가는 중. (신기함)

 

그리고 relave와 absolute속성은 단순히 내가 원하는 자리에 지정해서 놓으려고 쓴다. 까지만 인지하고 있었는데 이런식으로 이벤트가 일어날때마다 동적으로 바꿀수 있다니까 활용법을 새로 배운 기분이다. 

 

 

 

🔽 추가로 구현할 점

다행히 원하는 바는 다 만들었지만 그래도 너무 메뉴가 뿅 튀어나오는건 별로라 어떻게든 부드럽게 뜨게 만들 방법을 찾아봐야겠다. height도 못쓰고 opacity도 못쓰면 대체 뭘 해야 될까 🤔

 

 

+++ 악 라이브서버에선 잘나왔는데 프로젝트에 올리니까 씹힌다 ㅠ ㅠ 대체 뭐가문제지..............

 

 

첫 api 구현 성공! 그리고 자바스크립트 날짜 형식 지정하기

#️⃣ 첫 rest api 구현 원래 단체/개인 메뉴바를 파라미터로 해서 넘어다녔는데, 이제 자바스크립트를 작동시켜야 하니 메뉴 아래 화면은 CSR방식으로 출력할 수 밖에 없게 되었다. 그래서, 각 단

ala-nueva.tistory.com

 

위 포스팅에서 처음 만들었던 자스...bind관해서 배우기 전이라 너무 하드코딩 한것 같다. 그때는 사소한게 죽어도 생각 안나더니 며칠 지나 다시 보니깐 정리할 수 있는 부분들이 많이 보였다.

 

 

✅ 최초 접속 화면에서 메뉴바 온클릭 이벤트 & 상세화면에서 돌아왔을때 온클릭 이벤트 동일하게 맞추기

메뉴바가 움직이는 조건은 두가지인데,

① 처음 feed/list에 들어와서 클릭할때랑 (한번 클릭하면 그다음부터는 api로 구현된다)

② 상세화면갔다가 메뉴바 눌러서 다시 feed/list 화면으로 돌아왔을때, 클릭한 값 그대로 (개인이라면 개인 그대로) 떠있어야 한다.

 

① 이 이전 포스팅에서 구현했던 부분이라면 오늘의 고민은 ② 였다. 상세화면에서 api로 그냥 list를 끌어와서 붙일까 하다가, 아무리 생각해도 /list와 /log는 경로도 다르고 페이지도 다르다고 생각해서 메뉴바의 css만 맞춰주기로 했다. (나중에 수업듣고나면 마음이 또 어떻게 바뀔지 모른다)

 

SSR로 돌아올땐 기본적으로 파라미터가 있으므로! 적극활용했다.

//파라미터로 메뉴 움직임 설정 ============================
let urlParams = new URL(location.href).searchParams;
let param_ = urlParams.get('s'); //type of로 확인해보면 string이므로 변환해야한다
let param = Number(param_); 

// css설정
boldReset(); 
aList[param].style.fontWeight = "bold";
line.style.left = `calc((375px / 3) * ${param} )`
    

// 두군데서 쓰다보니 따로 정의해놓은 boldReset().
function boldReset() {
for (let i = 0; i < aList.length; i++) {
    aList[i].style.fontWeight = "";
}

 

저번엔 온클릭 이벤트별로 하나씩 다 설정했는데, 지금은 깔끔하게 한줄로 정리완. 이말인즉슨 저번에 줄줄 적은 ① 도 바뀌었다는 뜻. 개별이벤트를 모두 부모이벤트에 올려주고 a링크만 클릭되도록 설정해주었다!

 

✅ 개별이벤트를 부모이벤트에 모아서 정리하기

//메뉴바 필터링 부모이벤트 ===================
menuList.onclick = function(e) {
    e.preventDefault(); //엘리먼트노드가 가진 기본 행위를 막는다

    // a태그일때만 작동하도록 하기
    let t = e.target;
    if (t.tagName != "A")
        return;

	//html에 있는 th:dataset-solo의 값을 활용해서 css 적용하기
    let isSolo_ = t.dataset.solo;
    isSolo = Number(isSolo_);

    boldReset();

    t.style.fontWeight = "bold";
    line.style.left = `calc((375px / 3) * ${isSolo} )`

    //데이터 요청 ---------------
    let request = new window.XMLHttpRequest();

    if (isSolo == 0 || isSolo == 1)
        request.open("GET", `/api/feeds?s=${isSolo}`, true);
    else
        return;

    request.onload = function() {
        let list = request.responseText;
        bind(list);
    }; //request.onload

 

 

✅ 이벤트마다 화면반환 코드를 넣을 수 없으므로 bind함수에 정의해주기

 최종 화면은 function bind(text)에  정의해주었다.

데이터를 받고 parse를 한 뒤에 적용해야 할 조건도 많아서 코드가 생각외로 길어졌다.

 

//최종 화면반환 ============================

function bind(text) {

    //리스트 parse처리
    let list = JSON.parse(text);
    console.log(list);

    //초기화
    feedList.innerHTML = "";

    for (let f of list) {
        /*단체개인 출력*/
        let solo = (isSolo == false) ? "단체" : "개인";

        /*프로필사진*/
        let profile = (f.writerPic == null) ? "default.png" : `${f.writerPic}`;
        console.log(profile);

        /*로그 날짜 연산*/
        let logDate_ = new Date(f.regDate);
        let month = logDate_.getMonth() + 1;
        let date = logDate_.getDate();
        let logDate = month + "월 " + date + "일";

        let liked = (f.isLike == false ? "icon-like" : "icon-like-fill");
        let bookmarked = (f.isBookmark == false ? "icon-bookmark" : "icon-bookmark-fill");

        let template = `html 복사해서 변수로 넣어주기`;

        feedList.insertAdjacentHTML("beforeend", template);
    };
}

 

 

✅ 자바스크립트로 말줄임표 (ellipsis) 만들어 출력하기

css 기능을 두고 굳이 자바스크립트로 왜 했냐...면 잘 안먹혀서임. 기본적으로 block이나 inline-block이어야 하고, 폭이 정해져있어야 인식해서 말줄임표 처리를 해준다는데, 나는 가변이라 그런지 혹은 설정을 제대로 못한건지, 원하는 모양대로 나오질 않았다. 그래서 그냥 만들어주기로 함!

 

  /*글씨 길이 길때 ellipsis*/
let m = matchMedia("(min-width:800px)"); // 나는 웹화면에서만 적용하고 싶었으므로 미디어쿼리 조건도 가져왔다
let maxLength = 255; //글자수 제한
let contents = (f.logContents = null ? "" : f.logContents);
let textLength;
if (contents != null) {
        textLength = contents.length;

        if ((textLength > maxLength) && (m.matches == true)) {
            contents = contents.substring(0, maxLength - 3) + '...';
        }
    }

👉 이 부분은 나중에 다시 연구해보고 싶은게, 아무래도 화면이 읽어들여질때 자바스크립트가 읽다보니, 한번 읽은 화면에서 반응형으로 움직이면 (화면을 움직이면) 적용이 되질 않고 다시 새로고침을 해줘야 적용된다.

물론 사용자가 쓰면서 화면을 굳이 (개발자도구를 열어서) 좌우로 움직일 일은 없겠지만 그래도 뭔가 매끄러웠음 좋겠어서 더 고민해볼 예정!

 

 SELECT 
        -- 아래 속성 그대로 가져오므로 생략
        COUNT(`lc`.`mission_log_id`) AS `comment_cnt`,
        SUM(IF(`bm`.`member_id` = 2, 1, 0)) AS `is_bookmark`
    FROM
        (((SELECT 
            `ml`.`id` AS `mission_log_id`,
                `ml`.`member_id` AS `member_id`,
                `ml`.`mission_id` AS `mission_id`,
                `m`.`nickname` AS `nickname`,
                `m`.`img` AS `writer_pic`,
                `ml`.`reg_date` AS `reg_date`,
                `mv`.`is_solo` AS `is_solo`,
                `mv`.`personality_id` AS `personality_id`,
                `mv`.`personality` AS `personality`,
                `mv`.`activity_id` AS `activity_id`,
                `mv`.`activity` AS `activity`,
                `mv`.`title` AS `title`,
                `mv`.`score` AS `score`,
                `ml`.`contents` AS `contents`,
                `ml`.`img` AS `img`,
                COUNT(`ll`.`mission_log_id`) AS `like_cnt`,
                SUM(IF(`ll`.`member_id` = 2, 1, 0)) AS `is_like`
        FROM
            (((`mission_log` `ml`
        JOIN `mission_view` `mv` ON (`ml`.`mission_id` = `mv`.`id`))
        JOIN `member` `m` ON (`ml`.`member_id` = `m`.`id`))
        LEFT JOIN `log_like` `ll` ON (`ml`.`id` = `ll`.`mission_log_id`))
        GROUP BY `ml`.`id`) `f`
        LEFT JOIN `log_comment` `lc` ON (`f`.`mission_log_id` = `lc`.`mission_log_id`))
        LEFT JOIN `bookmark` `bm` ON (`f`.`mission_id` = `bm`.`mission_id`))
    GROUP BY `f`.`mission_log_id`

 

좋아요, 댓글은 카운트가 필요하다면, 좋아요, 북마크는 로그인 아이디에 해당하는 색깔표기가 되어야 한다.

원래 배웠던 부분은 ifnull로 널값 여부에 따라 1,0 을 반환하게 해서 true를 체크하는거였음!

 

위와같이 log_like를 left join 해놓은 경우, 속성을 뽑을때 ifnull(ll.member_id=2,0) 으로 하면, 참일때 1이 나오고, 아니면 0이 나온다. 

 

문제는 이렇게 뽑게 되면 group by로 뭉쳐지면서 해당 로그에 첫번째로 등록한 멤버아이디만 true로 반환하고, 같은 로그를 체크한 다른 멤버아이디는 false로 출력된다는걸... 프론트 작업을 하면서 알게 되었다. 아니 뒷번호 조회해볼 생각을 못했지..!

 

그래서 머리싸매다가 sum을 활용하는 팁을 알게돼서 기록함.

 

위와 같이 sum(if(ll.member_id=2,1,0))으로 하게되면, 조건이 참일때 1을 반환한다는 점에서 ifnull과 결과물은 같다.

다른점이 있다면, sum은 조건에 해당하는 행을 체크해서 반환하므로 로그를 체크한 여러 멤버 아이디들 중에 하나라도 걸리면 1을 반환시킬 수 있다는것.

 

문제는 group by때문에 좋아요와 북마크를 한번에 left join할 경우, 그룹핑이 섞이면서 요상하게 합산된 결과가 출력됐다.

개별 속성을 뽑고 싶다면 조금 힘들어도 나눠서 조인을 진행해야 한다.

 

위에서 뽑은 isLike와 isBookmark는 아래와 같이 프론트에서 처리된다!

 

 

 

🔥html에서 타임리프로 처리할때 (classappend로 클래스 추가해주기)

<section class="feed-footer">
    <h1 class="d:none">좋아요, 댓글, 북마크</h1>
    <div class="f-list">
        <div>
            <div class="likebox">
                <a class="icon icon-size-24"
                    th:classappend="*{isLike==false}? 'icon-like':'icon-like-fill'">좋아요</a>
                <div class="like"><a>좋아요 <span th:text="*{likeCnt}">3</span>개</a></div>
            </div>
        <div class="bookmark">
            <a class="icon icon-size-28" th:classappend="*{isBookmark==false}? 'icon-bookmark':'icon-bookmark-fill'">북마크</a>
        </div>
    </div>
</section>

 

 

🔥 js에서 api로 받아온 값을 출력할때 (조건처리를 통해 변수에 담아서 전달하기)

//삼항연산자로 클래스에 들어갈 클래스명을 정해준다
let liked = (f.isLike == false ? "icon-like" : "icon-like-fill");
let bookmarked = (f.isBookmark == false ? "icon-bookmark" : "icon-bookmark-fill");

<section class="feed-footer">
    <h1 class="d:none">좋아요, 댓글, 북마크</h1>
    <div class="f-list">
        <div>
            <div class="likebox">
                <button class="icon ${liked} icon-size-24"></button>
                <div class="like"><a>좋아요 <span>${f.likeCnt}</span>개</a></div>
            </div>
        <div class="bookmark">
            <button class="icon ${bookmarked} icon-size-28">북마크</button>
        </div>
    </div>
</section>

 

 

좋아요, 북마크가 각각 적용된 화면

👉 화면이 잔잔바리로 변해서 별거 안한것 같긴 한데, 좋아요랑 북마크 세팅하고 상세화면도 똑같이 적용해주고! 프로필 사진도 경로 맞춰서 디폴트사진도 넣어주고 검색도 된다!

 

#️⃣ 첫 rest api 구현

피드 가로카드는 아래로 쭉쭉 출력됨!

 

원래 단체/개인 메뉴바를 파라미터로 해서 넘어다녔는데, 이제 자바스크립트를 작동시켜야 하니 메뉴 아래 화면은 CSR방식으로 출력할 수 밖에 없게 되었다.

 

그래서, 각 단체미션/ 개인미션 a태그에 대한 onclick은 구현되어있는데, 그 onclick마다 request.open()으로 값을 받아오고 일일히 innerHTML을 갈아끼는 식을 넣을수는 없으니 (한 파일에서 전체코드를 두번 반복해야함) 어떻게 해야 클릭한번으로 움직이는 애니메이션과 값처리를 할 수 있을까 고민하게 됐고, 얼마전 수업에서 들었던 버블링을 이용할 수 있을까 생각해보게됨.

 

window.addEventListener("load", function() {

	//querySelector 생략

	/*api교체영역*/
	let feedList = this.document.querySelector(".feed-list");

	//개별이벤트
	team.onclick = function(e) {
		isSolo = 0;

		console.log("팀");
		line.style.left = "0px";
		team.style.fontWeight = "bold";
		personal.style.fontWeight = "";
		gathering.style.fontWeight = "";
	}

	personal.onclick = function(e) {
		isSolo = 1;

		console.log("개인");
		line.style.left = "calc((375px / 3))";
		personal.style.fontWeight = "bold";
		team.style.fontWeight = "";
		gathering.style.fontWeight = "";
	}

	gathering.onclick = function(e) {
		console.log("카테고리");
		line.style.left = "calc((375px / 3) * 2 )";
		gathering.style.fontWeight = "bold";
		personal.style.fontWeight = "";
		team.style.fontWeight = ""
	}

	//부모이벤트
	feedMenu.onclick = function(e) {
		console.log(isSolo);
		e.preventDefault(); //엘리먼트노드가 가진 기본 행위를 막는다
		let request = new window.XMLHttpRequest();
		request.open("GET", `/api/feeds?isSolo=${isSolo}`, true);

		request.send();

		request.onload = function() {

			//리스트 parse처리
			let list = JSON.parse(request.responseText);

			//초기화
			feedList.innerHTML = "";

			for (let f of list) {
				/*단체개인 출력*/
				let solo = (isSolo == 0) ? "단체" : "개인";
				/*로그 날짜 연산*/
				let logDate_ = new Date(f.missionLogDate);
				let month = logDate_.getMonth() + 1;
				let date = logDate_.getDate();
				let logDate = month + "월 " + date + "일";

				let template = `
				// html 가져오기
				`;
				feedList.insertAdjacentHTML("beforeend", template);
			};
		}; //request.onload ends
	}
});

 

수업에선 e.stopPropagation(); 으로 부모객체의 버블링을 막아서 개별 이벤트가 부모이벤트를 이용하지 못하게했지만,

지금은 각 클릭값 (개별이벤트) + 공통 이벤트 (부모이벤트) 를 모두 적용해야하므로 해당 액션을 지웠다.

그리고 기존에 파라미터로 받던 부분을 클릭할 시 변수로 세팅해서 request할때 넘겼음!

 

이게 될까될까 하면서 반신반의로 설계하고 해본건데 잘돼서 진짜 기뻤다!!!!!!!

let request = new window.XMLHttpRequest();
request.open("GET", `/api/feeds?isSolo=${isSolo}`, true); // api 절대경로로 쓰기

 

 

 

#️⃣ 자바스크립트로 날짜구현하기

 

Json형식으로 데이터를 뽑아왔는데, 해당 객체의 변수(f.logDate) 를 출력하면 일단 String으로 나와서 내가 원하는대로 형태변환이 불가했다. 찾아보니 자바스크립트 new Date()가 자꾸 나오길래 얘는 새 객체 아닌가 했더니만, 다시 여기로 넣어서 치환해서 쓰는게 가능했다!

/*로그 날짜 연산*/
let logDate_ = new Date(f.missionLogDate);
let month = logDate_.getMonth() + 1; // 9월이면 숫자 8을 반환하므로 +1 해주기
let date = logDate_.getDate();
let logDate = month + "월 " + date + "일";

String을 다시 Date에 넣어서 타입을 바꿔주고 (console.log로 typeof 뽑으면 Object로 나온다)

month와 date를 뽑아서 내가 원하는 형태로 바꿔줬다(string)

자바스크립트에 쓸수있는 변환메서드는 월,일이 나오는 세팅이 없었음.

 

 

 

 

 

 

 

 

 

 

 

 

 

+ Recent posts