장소(전시장)를 기록하는 앱을 만들어 보자(1)😎

Kim Seoung Hun·2022년 8월 14일
0

전시장앱만들기

목록 보기
1/2
post-thumbnail

미대출신인 나는, 어찌 하다보니 퍼블리셔로 일하면서 프론트엔드를 공부중인데,
최근에 뷰를 배웠고, 이를 통해 개인 프로젝트를 하나 만들어보고자 했다
(강의에서 만들었던 프로젝트가 아닌!)

그래서 전시장을 맵에 표기해서 소개하는 웹을 만들었다.🥳

블로그 쓰는 시점에서 그냥 전시장을 보여주는 앱이 아니라, 인상 깊었던 공간을 기록하는 앱을 만들어보자로 해보면 어떨까 생각이 들었고, 뜯어 고치기전 내 결과물과 앞으로 개발을 쭉 진행하는 과저을 기록하고자 글을 쓴다.

지도에 전시장들을 표시해보자!

1.프로젝트 생성하기
먼저 이 프로젝트는 vue-cli vue3를 이용해서 진행했다.

vue create projectname

2.파일 분류
이번에 작업을 진행할때 모듈화에 신경을 쓰면서 작업을 하기 위해,
먼저 폴더들을 생성을 선행하고 진행했다.
나중에 모듈화하는게 귀찮았다.

각 기능에 따라 api/assets/components/css/scss/router/store/views 로 폴더를 정리했다.
(생성시 만들어지는 폴더는 components / assets )

api는 axios로 비동기 통신을 하기위해 사용되는 코드를
router는 라우팅에 사용되는 코드를,
store는 vuex에 사용되는 코드를,
views는 views에 위치한 상위컴포넌트를 생성해 여기에서는 보여주는 역활만 진행하고 컴포넌트 파일에 하위컴포넌트를 생성해 코드들을 담아내서 관리 하고자 했다.


3.codes
app.vue

<template>
  <router-view />
</template>
<script></script>

<style>
* {
  margin: 0;
  padding: 0;
}
li {
  list-style: none;
}
a {
  text-decoration: none;
  color: #333;
}
</style>

app.vue
app.vue내에 있던 HelloWorld.vue 컴포넌트 정보와 해당 파일을 삭제하고 시작했다.

app.vue에서는 최대한의 정보를 담지 않을려고 했고 공통적으로 적용하기 위해 css만 넣어서
라우팅된 페이지만 보여주기 위해 <router-view></router-view> 코드만 넣어주었다.

이제 맵을 구현해야하는데! 우리에겐 카카오맵이 있다.
카카오맵을 뷰로 불어올려면 먼저 카카오맵API APP KEY를 발급받아야 한다.

카카오맵 API DOCS
위 링크에 들어가서 카카오톡 로그인을 하고나면 아래 페이지로 이동한다.

이미 생성한 애플리케이션이 있다.
새로 시작할려면 애플리케이션 추가하기를 눌러, 기본 정보를 입력해준다.

입력을 해주고 들어가게 되면 이제 필요한 appkey를 알 수가 있다!

appkey 와 플랫폼을 등록해준다.

사실 이 모든거에 대한 안내는 카카오맵 api docs에 아주 잘 설명되어있다.

그 다음 프로젝트 src 폴더내 component 파일속 ShowMap.vue 파일을 생성해 맵을 표시 할려고 한다.

빠른 결과를 원하는 한국인을 위해 코드 먼저 띄운다.

ShowMap.vue 전체코드

<template>
<div id="container">
  <div>
    <div>
      <form @submit.prevent="inputKeyword()">
        <input
          type="text"
          v-model="this.keywordSearch"
          @click="serchBarEventHandler"
          id="searchArea"
          autocomplete="off"
        />
      </form>
      <div id="nav" v-show="!this.$store.state.searchBar">
        <ion-icon name="menu" @click="menuToggle"></ion-icon>
      </div>
    </div>
    <div v-show="this.$store.state.searchBar">
      <ul>
        <li
          v-for="(list, i) in this.$store.state.positions"
          :key="i"
          @click="
            (this.$store.state.searchBar = !this.$store.state.searchBar),
              initText()
          "
        >
          <div
            v-show="list.place_name.includes(this.keywordSearch)"
            class="ae"
          >
            {{ list.place_name }}
          </div>
        </li>
      </ul>
    </div>
  </div>
  <div class="map_wrap">
    <div id="map"></div>
    <div id="myCenter" v-show="!this.$store.state.searchBar">
      <div v-show="this.$store.state.localIconShow == true">
        <ion-icon name="location" id="getCenter"></ion-icon>
      </div>
      <div v-show="this.$store.state.localIconShow == false">
        <ion-icon name="location-outline" id="hideMyCenter"></ion-icon>
      </div>
    </div>
  </div>
</div>
</template>

<script>
import store from "@/store/store";
export default {
name: "KakaoMap",
data() {
  return {
    modalOpen: false,
    keywordSearch: "",
    closeBtn: false,
  };
},
mounted() {
  // ! 카카오맵 초기 설청 -------------------------------------------------
  if (window.kakao && window.kakao.maps) {
    this.initMap();
  } else {
    const script = document.createElement("script");
    /* global kakao */
    script.onload = () => kakao.maps.load(this.initMap);
    script.src =
      "//dapi.kakao.com/v2/maps/sdk.js?autoload=false&appkey={api key}&libraries=services,clusterer,drawing";
    document.head.appendChild(script);
  }
},
methods: {
  inputKeyword() {
    this.$store.state.keyword = this.keywordSearch;
    this.initMap();
  },
  // !맵 초기 셋팅 ---------------------------------------------------------------------
  initMap() {
    const container = document.getElementById("map");
    const options = {
      center: new kakao.maps.LatLng(
        this.$store.state.mainLocation.lat,
        this.$store.state.mainLocation.lng
      ),
      level: this.$store.state.viewLevel,
    };
    const map = new kakao.maps.Map(container, options);
    this.map = map;
    // !--------------------------------------------------------------------------------
    // !내 위치 마커
    // !--------------------------------------------------------------------------------
    document
      .querySelector("#getCenter")
      .addEventListener("click", function () {
        store.state.localIconShow = false;
        // * 위치 얻어오기
        if (navigator.geolocation) {
          navigator.geolocation.getCurrentPosition(function (position) {
            var Mylat = position.coords.latitude,
              Mylon = position.coords.longitude;

            var locPosition = new kakao.maps.LatLng(Mylat, Mylon);
            displayMarker2(locPosition); //* 위치 마커 생성하는 함수
          });
        } else {
          var locPosition = new kakao.maps.LatLng(33.450701, 126.570667);

          displayMarker2(locPosition); // * 실행이 실패하면 설정한 좌표값에 표시
        }
        var imageSrc =
          "https://www.citypng.com/public/uploads/small/11641513638sanpg6vtthzma5pmyxbnbe0sfhpnqdawfg2pjpzl11hkj9qhwbj7g0ektsxgghfjeml4jehzbjkaujbydzfrhf4nb9agagomf0yz.png";
        var imageSize = new kakao.maps.Size(20, 20);
        var markerImage = new kakao.maps.MarkerImage(imageSrc, imageSize);
        function displayMarker2(locPosition) {
          // 마커를 생성합니다
          var marker = new kakao.maps.Marker({
            map: map,
            position: locPosition,
            image: markerImage,
          });
          map.setCenter(locPosition);

          map.setLevel(3);

          kakao.maps.event.addListener(marker, "click", function () {
            marker.setMap(null);
            store.state.localIconShow = true;
          });

          document
            .querySelector("#hideMyCenter")
            .addEventListener("click", function () {
              map.panTo(locPosition);
              if (store.state.localIconShow == true) {
                marker.setMap(map);
              }
            });
        }
      });
    // ! 전시장소 마커 셋팅  ---------------------------------------------------------------------
    var imageSrc =
      "https://cdn.iconscout.com/icon/free/png-256/pin-locate-marker-location-navigation-7-16347.png";
    for (var i = 0; i < this.$store.state.positions.length; i++) {
      var imageSize = new kakao.maps.Size(40, 40); // * 마커 이미지의 이미지 크기

      var markerImage = new kakao.maps.MarkerImage(imageSrc, imageSize); // * 마커 이미지를 생성

      displayMarker(this.$store.state.positions[i]); // * 해당 위치들에 마커 표시
    }
    function displayMarker(place) {
      //* place = 위에서 받아온 위치정보 인자
      var marker = new kakao.maps.Marker({
        map: map,
        position: new kakao.maps.LatLng(place.lat, place.lng),
        image: markerImage,
      });
      // ! 커스텀 오버레이 셋팅  ---------------------------------------------------------------------
      let content = document.createElement("div");

      let header = document.createElement("div");
      header.className = "header";

      let info = document.createElement("div");

      let close = document.createElement("ion-icon");
      close.onclick = () => {
        overlay.setMap(null);
      };

      let title = document.createElement("div");

      let link = document.createElement("a");
      link.href = store.state.positions[i].url;
      link.target = "_blank";
      link.appendChild(
        document.createTextNode(`${store.state.positions[i].place_name}`)
      );

      let adress = document.createElement("div");

      let adressP = document.createElement("p");
      adressP.appendChild(
        document.createTextNode(`${store.state.positions[i].adress}`)
      );
      let subBtnArea = document.createElement("div");
      subBtnArea.className = "sub-btn-area";

      let moreInfo = document.createElement("a");
      moreInfo.href = "/space/" + store.state.positions[i].id;
      moreInfo.appendChild(document.createTextNode("더보기"));

      let contect = document.createElement("div");

      let contentRoute = document.createElement("a");
      contentRoute.href =
        "https://map.kakao.com/link/to/" +
        store.state.positions[i].place_name +
        "," +
        store.state.positions[i].lat +
        "," +
        store.state.positions[i].lng;
      contentRoute.target = "_blank";
      contentRoute.appendChild(document.createTextNode("길찾기"));

      let label = document.createElement("div");
      label.appendChild(
        document.createTextNode(store.state.positions[i].label)
      );

      content.appendChild(info);
      info.appendChild(header);
      info.appendChild(label);
      info.appendChild(adress);
      adress.appendChild(adressP);
      info.appendChild(subBtnArea);
      header.appendChild(title);
      header.appendChild(close);
      subBtnArea.appendChild(contect);
      subBtnArea.appendChild(moreInfo);
      contect.appendChild(contentRoute);
      title.appendChild(link);

      title.className = "title";
      content.className = "wrap";
      adress.className = "adress";
      info.className = "info";
      close.name = "close-outline";
      close.className = "close-btn";
      // !오버레이 생성-----------------------------------------------------
      var overlay = new kakao.maps.CustomOverlay({
        content: content,
        map: map,
        // * 마커들의 위치를 가져온다.
        position: marker.getPosition(),
      });
      overlay.setMap(null);
      // ! 초기 오버레이 닫은 상태로 시작하기 위해 추가.
      kakao.maps.event.addListener(marker, "click", function () {
        overlay.setMap(map);
        map.panTo(this.getPosition());
        store.state.closeBtn = true;
      });
      // ! 장소 검색하고 리시트 클릭시 해당 마커로 이동
      // TODO 클래스 이름 변경하기
      const goToPlace = document.querySelectorAll(".ae");
      // * li tag 클릭시 이벤트 추가
      goToPlace.forEach(function (event, index) {
        var moveLatLng = new kakao.maps.LatLng(
          store.state.positions[index].lat,
          store.state.positions[index].lng
        );
        event.addEventListener("click", function () {
          map.panTo(moveLatLng);
        });
      });
    }
  },
  //* 메뉴 바 토글
  menuToggle() {
    this.$store.state.menuActive = !this.$store.state.menuActive;
  },
  // * 검색한 결과 클릭시 인풋 값 초기화 하는 함수
  initText() {
    this.keywordSearch = "";
  },
  // * 검색창 로직
  serchBarEventHandler() {
    if (this.$store.state.searchBar == false && this.keywordSearch == "") {
      this.$store.state.searchBar = true;
    } else if (
      this.$store.state.searchBar == true &&
      this.keywordSearch != ""
    ) {
      this.$store.state.searchBar = true;
    } else {
      this.$store.state.searchBar = false;
      document.querySelector("#searchArea").blur();
      this.keywordSearch = "";
    }
  },
},
};
</script>

<style scoped lang="scss">
@import url("../css/common.css");
@import url("../css/map.css");
</style>

더럽게 길다. 🤮

코드 정리와 모듈화를 완전히 진행시키지 못한 못난 코드지만, 한번에 보기에 좋은거 같다.

다음글부터 해당 코드를 쓰고 마추친 시련에 대해 차근차근 이야기 할려고 한다.😊

profile
낮 코딩 밤에는 그림 종종 시

0개의 댓글