주소 API를 사용하려고 찾아보니 다음 우편번호 API가 Key 없이도 자유롭게 사용할 수 있어서 적용해보려고 한다. 카카오로 바뀌었으니까 막 갑자기 사라지거나 하진 않을 것 같다. 계속 최신화 업데이트도 되고 있다.

공식문서: https://postcode.map.daum.net/guide

공식문서에서 스크립트 소스를 가져와 public/index.html의 <head>에 추가한다.

<script src="//t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js"></script>

공식문서에서 밑으로 좀 내려가면 사용 예시와 예시 코드가 있다. 팝업 없이 하려면 iframe으로 해야 하는 것 같다. 'iframe을 이용하여 레이어 띄우기' 예시를 Vue.js에 적용할 수 있게 수정했다.

예시에는 도로명 주소와 지번 주소 중 하나를 선택하는 것까지 포함인데 나는 도로명 주소를 기본으로 쓸 거라서 if문을 뺐다.

위치 변경하는 기능을 만들어야 해서 주소가 쓰여 있는 부분을 클릭했을 때 검색 창이 뜨게 할 것이다.

Vue3.0 기준이고 <script setup>으로 작성했다.

<script setup>
import { ref } from 'vue'

const userLocation = ref('기본 주소');
const locationWrap = ref(null);
const modalOpen = ref(false);

const showLocation = () => {
  toggleModal();
  new daum.Postcode({
      //검색 결과를 클릭했을 때 실행되는 코드
    oncomplete: (data) => {
      let addr = data.roadAddress; //도로명 주소. 지번 주소는 data.jibunAddress
      let extraAddr = ''; //세부 주소
      //법적동명 추가
      if (data.bname !== '' && /[동|로|가]$/g.test(data.bname)) {
        extraAddr += data.bname;
      }
      // 건물명, 공동주택일 경우 추가
      if (data.buildingName !== '' && data.apartment === 'Y') {
        extraAddr +=
          extraAddr !== '' ? ', ' + data.buildingName : data.buildingName;
      }
      // 참고항목 추가
      if (extraAddr !== '') {
        extraAddr = ' (' + extraAddr + ')';
      }
      userLocation.value = addr + extraAddr;
      toggleModal();
    },
  }).embed(locationWrap.value);
};

const toggleModal = () => {
  modalOpen.value = !modalOpen.value;
};
</script>

<template>
  <div>{{ userLocation }}</div>
  <div class="location-wrap" :class="{ show: modalOpen }" ref="locationWrap"></div>
</template>

<style scoped>
.location-wrap {
  display: none;
  position: absolute;
  z-index: 999;
  margin-inline: 75px;
}
.show {
  display: block;
}
</style>

보통 도로명 주소가 "○○로 123-45(○○아파트, ○○동)" 이런 식인데 괄호 안에 있는 세부정보가 필요 없다면 extraAddr 관련 코드는 제외해도 되므로 <script>의 코드가 간략해진다.

<script setup>
import { ref } from 'vue'

const userLocation = ref('기본 주소');
const locationWrap = ref(null);
const modalOpen = ref(false);

const showLocation = () => {
  toggleModal();
  new daum.Postcode({
    oncomplete: (data) => {
      let addr = data.roadAddress;
      userLocation.value = addr;
      toggleModal();
    },
  }).embed(locationWrap.value);
};

const toggleModal = () => {
  modalOpen.value = !modalOpen.value;
};
</script>


오른쪽이 같은 주소로 세부 주소를 표시했을 때

border를 넣어도 디자인이 좀 많이 어색한데 이게 한계인 것 같다. 지금 다른 부분도 할 게 많아가지고 뭔가를 더 시도하기가 힘들다.


구매 페이지에는 우편번호, 주소, 상세 주소가 모두 뜨게 했다. 이건 팝업으로 열리게 했는데 팝업으로 열리게 하려면 함수 끝부분의 embed()를 open으로 변경하면 된다.

<script setup>
import { ref } from 'vue';

const deliverLocation = ref({
  postcode: '',
  roadAddress: '',
  detailAddress: '',
});

const showLocation = () => {
  new daum.Postcode({
    //검색 결과를 클릭했을 때 실행되는 코드
    oncomplete: (data) => {
      let addr = data.roadAddress;
      let extraAddr = ''; //세부 주소
      //법적동명 추가
      if (data.bname !== '' && /[동|로|가]$/g.test(data.bname)) {
        extraAddr += data.bname;
      }
      // 건물명, 공동주택일 경우 추가
      if (data.buildingName !== '' && data.apartment === 'Y') {
        extraAddr +=
          extraAddr !== '' ? ', ' + data.buildingName : data.buildingName;
      }
      // 참고항목 추가
      if (extraAddr !== '') {
        extraAddr = ' (' + extraAddr + ')';
      }
      deliverLocation.value.postcode = data.zonecode;
      deliverLocation.value.roadAddress = addr + extraAddr;
    },
  }).open();
};
</script>

<template>
<div class="deliver-info-wrap">
  <div class="postcode-wrap">
    <input type="text" v-model="deliverLocation.postcode" placeholder="우편번호" readonly />
    <button btntype="outlineGray" @click="showLocation">주소 찾기</button>
  </div>
  <input type="text" v-model="deliverLocation.roadAddress" placeholder="도로명주소" readonly />
  <input type="text" v-model="deliverLocation.detailAddress" placeholder="상세주소" />
</div>
</template>

우편번호와 도로명주소는 '주소 찾기' 버튼을 눌러서 검색하게 하고 'readonly' 속성을 추가해서 따로 수정할 수 없게 했다. 상세주소(동, 호수)는 직접 입력해야 한다.