눈물의 카카오맵 구현 일지 1탄. 다중 커스텀 오버레이 이벤트가 이상하다

Breeze·2021년 11월 17일
1

Frontend 개발 일지

목록 보기
8/8

안녕하세요 행복이님들 혀누킴입니다. 카카오맵 api를 이용해 가게 위시리스트 담기 페이지를 구현하면서 흘린 눈물 시리즈 1탄을 들고 왔습니다. 여러분은 부디 저와 같은 실수를 하지 않으시길 바랍니다 🥲

다중 커스텀 오버레이 이벤트 등록이 이상하다

카카오맵 api 공식 문서 중 커스텀 오버레이 생성하기2 를 참고하여 가게의 상세 정보를 담을 커스텀 오버레이를 구현하였습니다..(안돼..stay...) 가게 마커를 클릭할 때, 해당 가게 정보 오버레이가 나타나도록하고 마커 외부 영역을 클릭할 경우, 오버레이가 닫히도록 개발하여야 하는 상황인데.. 한개의 마커 오버레이를 닫았더니 반복문의 마지막 마커 오버레이가만 닫히는 현상이 발생했습니다😭 잠시 눈물을 닦는 시간을 가진 후. 구글링을 통해 문제 해결 방법을 찾아냈습니다.

const score = this.placeList[i].score * 20 + 1.5;

var content = `<div class="wrap">`;
content +=  `<div class="head">`;
content +=    `<div class="name">${this.placeList[i].name}</div>`;
content +=    `<img class="add" src="${require('@/assets/map/add.png')}" alt="">`;
content +=  `</div>`;
content +=  `<div class="body">`
content +=    `<div class="star-ratings">`
content +=      `<div class="star-ratings-fill" style="width: ${score}%"><span>★</span><span>★</span><span>★</span><span>★</span><span>★</span></div>`;
content +=      `<div class="star-ratings-base"><span>★</span><span>★</span><span>★</span><span>★</span><span>★</span></div>`;
content +=    `</div>`;
content +=    `<div class="star-ratings-text">(${this.placeList[i].score}) | 리뷰 ${this.placeList[i].review}개<div>`;
content +=    `<div>${this.placeList[i].address}</div>`;
content +=    `<div class="desc">${this.placeList[i].phone}</div>`;
content +=    `<a class="desc" href="${this.placeList[i].kakao_url}">상세보기</a>`;
content +=  `</div>`;
content += `</div>`;

var customOverlay = new kakao.maps.CustomOverlay({
  map: map,
  position: placeMarkerPosition,
  content: content,
  xAnchor: 0.5,
  yAnchor: 1.1,
  clickable: true,
});

kakao.maps.event.addListener(placeMarker, "click", function () {
  customOverlay.setMap(map);
});

무엇이 문제였나?

다음 Dev Talk들을 확인하여 문제를 해결할 수 있었습니다.

안녕하세요 다중마커로 닫기가 가능한 커스텀 오버레이를 구현하려고 하는데 가이드 부탁드립니다

Ajax로 다중 마커와 함께 커스텀 오버레이를 생성 시 문제가 생겨서 문의드립니다

두 글을 보며, 제가 참고했던 커스텀 오버레이 생성하기2 공식 문서 페이지 코드는 단 하나의 마커에 오버레이를 올릴 때 적합한 코드였던 것입니다. 아 물론, 마커에 click 등의 이벤트를 달지 않는 경우에도 사용 가능합니다. 하지만, 저의 경우처럼 오버레이 안에 여러 이벤트(담기 버튼 구현, 마커 오버레이 열고 닫기)를 구현할 생각이시라면 해당 코드는 적합하지 않습니다!(행복이님들은 이 글을 통해 시간을 아끼고 정신적 고통을 줄이시길 바랍니다ㅜㅜ)

그래서 어떻게 해결하나?

위의 Dev Talk과 커스텀오버레이를 드래그 하기 공식문서 페이지를 참고하여 다음과 같이 코드를 구현했습니다. 즉, document.createElement로 HTMLElement를 구성하고 해당 요소에 함수를 네이티브 DOM이벤트를 통해 거는 방식으로 코드를 작성했습니다. 코드를 전면 수정하는 고통을 겪으며 공식문서를 더 꼼꼼히 볼 것을 다짐했습니다 🥲

addPlaceMarker(map, place) {
			... 중략 ...
      var placeOverlay = new kakao.maps.CustomOverlay({
        position: placeMarker.getPosition(),
        clickable: true,
      })

      var placeContent = document.createElement("div")
      placeContent.className = "place-content"

      var placeHead = document.createElement("div")
      placeHead.className = "place-head"

      var placeBody = document.createElement("div")
      placeBody.className = "place-body"

      var placeName = document.createElement("div")
      placeName.innerHTML = place.name

      var placeAddImg = document.createElement("img")
      placeAddImg.setAttribute("src", require("@/assets/map/add.png"))
      placeAddImg.addEventListener("click", () => {
        const wishPlace = {
          placeName: place.name,
          placeCategory: place.category_num,
          placeUrl: place.kakao_url,
        }
        this.addWishPlace(wishPlace)
      })

      var starRatings = document.createElement("div")
      starRatings.className = "star-ratings"

      var starRatingsText = document.createElement("div")
      starRatingsText.className = "star-ratings-text"
      starRatingsText.innerHTML =
        "(" + place.rate + ")| 리뷰 " + place.review + "개"

      const rate = place.rate * 20 + 1.5
      var starRatingsFill = document.createElement("div")
      starRatingsFill.className = "star-ratings-fill"
      starRatingsFill.style.width = rate + "%"

      var starRatingsBase = document.createElement("div")
      starRatingsBase.className = "star-ratings-base"

      var star1 = document.createElement("span")
      star1.innerHTML = "★★★★★"

      var star2 = document.createElement("span")
      star2.innerHTML = "★★★★★"

      var placeAddress = document.createElement("div")
      placeAddress.innerHTML = place.address

      var placePhone = document.createElement("a")
      placePhone.className = "place-desc"
      placePhone.innerHTML = place.phone
      placePhone.href = "tel: " + place.phone

      var placeUrl = document.createElement("a")
      placeUrl.innerHTML = "상세보기"
      placeUrl.className = "place-desc"
      placeUrl.href = place.kakao_url

      placeContent.append(placeHead, placeBody)
      placeHead.append(placeName, placeAddImg)
      placeBody.append(
        starRatings,
        starRatingsText,
        placeAddress,
        placePhone,
        placeUrl
      )
      starRatings.append(starRatingsFill, starRatingsBase)
      starRatingsFill.append(star1)
      starRatingsBase.append(star2)
      placeOverlay.setContent(placeContent)
      kakao.maps.event.addListener(placeMarker, "click", () => {
        if (this.clickedOveray) {
          this.clickedOveray.setMap(null)
        }
        placeOverlay.setMap(map)
        this.clickedOveray = placeOverlay
      })
      kakao.maps.event.addListener(map, "click", function () {
        placeOverlay.setMap(null)
      })
    },
  },
profile
약속 관리 서비스 breeze의 개발 일지입니다.

2개의 댓글

comment-user-thumbnail
2022년 3월 16일

눈물일지 예비개발자에게 매우도움이되었습니당..

답글 달기
comment-user-thumbnail
2022년 9월 6일

안녕하세요!! 웹 개발 프로젝트 하고 있는데 혹시 addPlaceMarker(map,place) 구문의 중략부분 코드에는 어느 내용이 들어가있나요..?
addPlaceMarker(map, place) {
... 중략 ...
var placeOverlay = new kakao.maps.CustomOverlay({
position: placeMarker.getPosition(),
clickable: true,
})

답글 달기