[ 홈페이지 리뉴얼 ] 밑줄이 따라다니는 nav-bar 구현(수정)

김민석·2021년 8월 21일
0
post-thumbnail

사이드 프로젝트를 시작했다.
아는 사람의 홈페이지를 리뉴얼 해보기로 했다.
(잘하면 팔 수 있을수도??)

사이드 프로젝트인만큼 시간에 구애받지 않기 때문에, 최대한 라이브러리를 사용하지 않고 구현해보고자 한다.
(vue.js는 일할 때 사용해야하니까 연습삼아 사용!)

첫번째 과제는 nav-bar 구현.

버튼 사이에서 마우스를 움직였을 때, 아래 언더바가 따라다니는 형태로 구현하고 싶었다.

참고:
코드는 vue.js로 작성되었음.

data() {
    return {
      underbarStyle: {
        left: `0px`,
        width: "0px",
        display: "none",
      },
    };
  },

  methods: {
    openDropDownAndShowNavBar(e) {
      if (e.target.tagName === "A") {
        e.target.classList.add("mouseover");
        this.underbarStyle.left = e.target.offsetLeft + 16 + "px";
        this.underbarStyle.width = e.target.offsetWidth - 30 + "px";
        this.underbarStyle.display = "block";
      }
    },
    closeDropDown() {
      const target = document.querySelectorAll(".mouseover");
      target?.forEach((el) => el.classList.remove("mouseover"));
    },
    hideNavBar() {
      this.underbarStyle.display = "none";
    },
  },

로직은 다음과 같다.

  1. 버튼들 아래 position: absolute인 div를 갖다 놓는다.
    (그래야 마음껏 휙휙 움직이게 할 수 있으니까.)

  2. 버튼에 마우스가 올라가면 underbar를 보이도록 만든다. (display=block)

  3. 마우스가 옮겨갈 때마다 기존의 ".mouseover" class를 없애고, 새로운 버튼에 ".mouseover"를 class를 준다.

  4. 마우스가 navBar에서 완전히 벗어나면 navBar의 display=none 으로 바꾼다.

로직은 간단해보였는데 생각보다 문제가 많았다.

1) Vue에서 :hover같은 의사 클래스를 지원하지 않아서

  • mouseover
  • mouseout
  • mouseleave
    와 같은 css를 사용해야 했다.
    심지어 mouseout이 내가 생각하는 방식으로 존재하지 않아 애를 먹었다. (자식에게 조차 작동한다. 즉, 내부의 모든 요소들 각각에서 벗어날 때마다 동작한다...) 알고보니 내가 원하는 기능은 mouseleave였다.
    그렇다고 mouseout을 사용하지 않은 것은 아니다.
    버튼 사이에서 마우스가 오갈때마다 기존의 ".mouseover"가 붙어있는 것을 제거해주는 동작이 필요했기 때문!

2) 여전히 어려운 CSS....

css는 항상 어렵다. 누군가 나 대신 해줬으면 좋겠다. ㅎ


8월 24일 (수정)
생각해보니 위에서 구현한 것은 vue.js를 사용하는 의미가 없지 않을까? 하는 생각이 들었다.
직접 돔을 조작하는 것은 vue.js가 제공하는 virtual dom을 이용해 연산을 줄이는 기능을 전혀 사용하지 못하는 행위다. 따라서 다시 고민해봐야겠다. ref를 사용하는 방법이 있을듯???
주말에 다시 시도해보기로!


1. vp를 늘이고 줄였을 때 바의 위치가 고정되던 문제 해결.

underbar의 속성을 absolute를 주고 parent의 position에 relative를 주지 않아서 바가 원래 위치에 고정되어 있지 않던 버그를 발견하였다.

부모 엘리먼트 내부에 속박되지 않고, 독립된 배치 문맥(positioning context)을 가지게 됩니다. 마치 포토샵 같은 그래픽 툴에서 새로운 레이어를 추가하는 효과에 비슷하다고 생각하시면 됩니다.
따라서, 엘리먼트를 기본적으로 브라우저 화면(viewport) 상에서 어디든지 원하는 위치에 자유롭게 배치시킬 수 있으며, 심지어 부모 엘리먼트 위에 겹쳐서 배치할 수도 있습니다.
단, 상위 엘리먼트 중에 position 속성이 relative인 엘리먼트가 있다면, 그 중 가장 가까운 엘리먼트의 내부에서만 엘리먼트를 자유롭게 배치할 수 있습니다. 즉, 전체 화면이 아닌 해당 상위 엘리먼트를 기준으로 offset 속성(top, left, bottom, right)이 적용됩니다.

2. dom 조작을 직접하던 문제 (좀 더 생각해볼 문제)

https://forum.vuejs.org/t/when-is-it-ok-to-directly-manipulate-the-dom/45818

내가 만들고자 하는 기능은 아무리 생각해봐도 방법이 없어 보였다. 따라서 검색을 좀 해보니

Frameworks like Vue, Angluar, React, etc. are data driven, meaning the reactivity that makes them so powerful is based on the data in the components of your app. Your goal should always be a data first approach. You should never manipulate the DOM or you’ll find yourself running into all sorts of bugs & unexpected behaviours. The only time when its ok to touch the DOM is when you aren’t relying on the framework to manage the state of that element. E.g. animating something trivial such as a bouncing arrow.

이런 답변이 있었다.

data의 변경으로 인한 조작이 아닌 것들은 역시 지금의 방법이 맞는 것 같다.

0개의 댓글