[Vue.js] Kakao 지도 구현 02 - Marker 생성 click listener

이전 문서에서 작성한 지도 기능(level, center 변경)에 마커 생성 및 click listener 코드를 추가합니다.

[Vue.js] Kakao 지도 구현 02 - Marker 생성 click listener

Source Code

  • MarkerHandler.js - marker 생성 및 관리 기능용 클래스(추가)
  • App.vue - 애플리케이션 루트 컴포넌트(수정)

나머지 파일들은 수정 사항 없음

프로젝트 구조

프로젝트구조
[ROOT] +- public | +- index.html +- src +- components/map | +- KakaoMap.vue | +- marker-handler.js (+) | +- service | +- api.js | +- App.vue (E) +- main.js

src/components/map/marker-handler.js

marker 생성 및 관리를 담당하는 클래스. 현재는 마커 생성 기능만 구현하고 있지만 마커를 삭제하거나 잠시 가리는 등의 기능이 이곳에 추가됩니다.

src/components/map/marker-handler.js
const kakao = window.kakao; class MarkerHandler { constructor(vueKakaoMap, options) { this.vueMap = vueKakaoMap; this.options = options; } add(userData, fnConv) { userData.forEach((data) => { const option = fnConv(data); // this is harbor const markerInstance = new kakao.maps.Marker({ map: this.vueMap.mapInstance, position: new kakao.maps.LatLng(option.lat, option.lng), }); markerInstance.$$ = { data, }; if (this.options.markerClicked) { kakao.maps.event.addListener(markerInstance, "click", () => { this.options.markerClicked(markerInstance.$$.data); }); } }); } } export default MarkerHandler;

src/App.vue

MarkerHandler 인스턴스를 사용합니다.

src/App.vue
<template> <div> <h3>kakao map demo(center, level)</h3> <div class="controll"> <button @click="zoom(-1)"> <span class="material-icons"> zoom_in </span> </button> <button @click="zoom(1)"> <span class="material-icons"> zoom_out </span> </button> </div> <div class="map-area"> <div class="harbors"> <div class="harbor" v-for="hbr in harbors" :key="hbr.seq" @click="showOnMap(hbr)" :class="{ active: hbr === activeHarbor }" > <h4>{{ hbr.place }}</h4> </div> </div> <!-- KakaoMap 구현체 참조가 필요함 --> <KakaoMap ref="kmap" class="kmap" :options="mapOption" /> </div> </div> </template> <script> import KakaoMap from "./components/map/KakaoMap.vue"; import api from "./service/api"; import MarkerHandler from "./components/map/marker-handler"; export default { components: { KakaoMap, }, data() { return { mapOption: { center: { lat: 33.450701, lng: 126.570667, }, level: 8, }, harbors: [], markers: null, // (+) instance of MarkerHandler activeHarbor: null, // (+) 현재 선택된 harbar 참조 }; }, mounted() { const vueKakaoMap = this.$refs.kmap; this.markers = new MarkerHandler(vueKakaoMap, { markerClicked: (harbor) => { console.log("[clicked ]", harbor); // this.activeHarbor = harbor; this.showOnMap(harbor); }, }); api.harbor.all((res) => { console.log("[항구목록]", res.harbors); this.harbors = res.harbors; // create markers this.markers.add(this.harbors, (harbor) => { return { lat: harbor.lat, lng: harbor.lng }; }); }); }, methods: { zoom(delta) { // delta : 1 or -1 // console.log("[delta]", delta); const level = Math.max(3, this.mapOption.level + delta); // min level 3 this.mapOption.level = level; // console.log(this.mapOption.level); }, showOnMap(harbor) { this.activeHarbor = harbor; // console.log("[center]", harbor); this.mapOption.center = { lat: harbor.lat, lng: harbor.lng, }; }, }, }; </script> <style lang="scss"> button { border: 1px solid transparent; padding: 6px; background-color: #efefefdd; border-radius: 6px; &:hover { background-color: #ddd; border-color: #ddd; cursor: pointer; } &:active { background-color: #aaa; border-color: #aaa; } } .map-area { display: flex; .harbors { .harbor { padding: 10px; border: 1px solid transparent; &:hover { background-color: aliceblue; border-color: #6a9dff; cursor: pointer; } &:active { background-color: rgb(166, 197, 224); border-color: #4471c5; } &.active { background-color: rgb(253, 229, 150); border-color: rgb(211, 173, 3); } h4 { margin: 0; } } } .kmap { flex: 1 1 auto; } } </style>