> ## Content Index
> Fetch the complete content index at: https://blog.anthea.day/llms.txt
> Use this file to discover other available public pages before exploring further.

# 歡迎來到 GIS 的世界－ Day 27：旅遊規劃小專案的查詢介面
- URL: https://blog.anthea.day/series-2022-ithome-27/
- Published: 2022-10-10T16:00:59.000Z
- Updated: 2026-11-06T19:48:25.000Z
- Author: Anthea / 芫荽
- Tags: #Migrated-1792241843742, #Import 2026-10-17 12:57, Coding, 2022 iThome 鐵人賽：歡迎來到 GIS 的世界

接續前一天的縣市找景點功能，複習一下我們會有的功能說明：

> \- 身為一個使用者，我可以點擊地圖上的查詢按鈕，選擇縣市之後找到該縣市的景點。  
> \- 身為一個使用者，查詢縣市景點之後，地圖上只會呈現該縣市的景點。

昨天已經建立好 API，今天要做的就是顯示查詢的頁面，以及第二點重新渲染的部分。

### 1\. 查詢縣市的頁面顯示

這邊會使用到的套件有：[Bootstrap 5](https://getbootstrap.com/?ref=blog.anthea.day) 和 [Sweet Alert 2](https://sweetalert2.github.io/?ref=blog.anthea.day)，都是我在工作上沒有特別要求前端葉面的時候會使用到的工具，可以輕鬆地就完成一個簡單乾淨的頁面。

```
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>旅遊規劃</title>
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.8.0/dist/leaflet.css"
          integrity="sha512-hoalWLoI8r4UszCkZ5kL8vayOGVae1oxXe/2A4AO6J9+580uKHDO3JdHb7NzwwzK5xr/Fs0W40kiNHxM9vyTtQ=="
          crossorigin=""/>
    <link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.4.1/dist/MarkerCluster.Default.css">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
    
    <style>
        body{
            height: 100vh;
        }
        
        #app, .row, #map{
            height: 100%;
        }
        
        #search-by-county{
            z-index: 1001;
            top: 1%;
            right: 0;
        }
    </style>
</head>
<body>
<div id="app" class="container-fluid">
    <div class="row align-items-center position-relative">
        <div id="map"></div>
        <div id="search-by-county" class="position-absolute col-auto">
            <button type="button" class="btn btn-lg btn-primary">
                查詢
            </button>
        </div>
    </div>
</div>
</body>
</html>
```

我想做到的效果是地圖上會有一個固定的查詢按鈕，但因為 Leaflet 預設地圖的 z-index 是 1000，所以必須把按鈕的數值再調大一點。成品如下：

![](https://cdn-images-1.medium.com/max/800/0*HA8T0H9d0Y7Sa6of.jpg)

有了按鈕之後，我們還需要先透過 Vue 來建立一個查詢的流程，包含：

1. 點擊後打開一個視窗
2. 選擇要查詢的縣市

這個部分我選擇直接用 Sweet Alert 的方式製作。首先要先加入點擊按鈕之後會出發的 alert，我是參考[官方網站的範例](https://sweetalert2.github.io/?ref=blog.anthea.day#input-types)進行修改的：

```HTML
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>旅遊規劃</title>
    <!-- 略 -->
</head>
<body>
<div id="app" class="container-fluid">
    <div class="row align-items-center position-relative">
        <div id="map"></div>
        <div id="search-by-county" class="position-absolute col-auto">
            <button type="button" class="btn btn-lg btn-primary"
                    @click.prevent="searchScenicByCounty">
                <!-- ^^^ 新增點擊事件，綁定 function 名稱 -->
                查詢
            </button>
        </div>
    </div>
</div>
<script>
    const app = Vue.createApp({
        data(){},
        methods:{
            initMap(){
                // ...
            },
            getScenicSpots(){
                // ...
            },
            searchScenicByCounty(){
                Swal.fire({
                    title: '利用縣市搜尋景點',
                    
                    // 輸入的類型，select = 下拉式選單
                    input: 'select',
                    
                    // 選單的內容，物件名稱為 <option> 中的 value
                    inputOptions: {
                        A: '臺北市',
                        B: '臺中市',
                        C: '基隆市',
                        D: '臺南市',
                        E: '高雄市',
                        F: '新北市',
                        G: '宜蘭縣',
                        H: '桃園市',
                        I: '嘉義市',
                        J: '新竹縣',
                        K: '苗栗縣',
                        M: '南投縣',
                        N: '彰化縣',
                        O: '新竹市',
                        P: '雲林縣',
                        Q: '嘉義縣',
                        T: '屏東縣',
                        U: '花蓮縣',
                        V: '臺東縣',
                        W: '金門縣',
                        X: '澎湖縣',
                        Z: '連江縣',
                    },
                    
                    // 顯示取消的按鈕和文字設定
                    showCancelButton: true,
                    cancelButtonText: '取消',
                    
                    // 顯示確認的按鈕文字設定
                    confirmButtonText: '查詢'
                }).then((result) => {
                    if (result.isConfirmed) {
                        // 按下的按鈕是確認(查詢)的按鈕：打 API
                        axios({
                            method: 'get',
                            url: `./api/ScenicSpot/${result.value}`
                        }).then(res => {
                            console.log(res.data);
                        }).catch(err => {
                            console.log(err);
                        })
                    }
                })
            },
        },
        mounted(){
            this.getScenicSpots();
        }
    });
    app.mount('#app');
</script>
</body>
</html>
```

重新整理網頁後應該就會看到 console 印出了下列的訊息：

![](https://cdn-images-1.medium.com/max/800/0*MG-VDgiowv1lQDAV.png)

好耶！那我們是不是可以直接套用前幾天的 `initMap()`，渲染到地圖上了呢?

### 2\. 重新渲染景點

前幾天所使用到的地圖初始化功能在這裡：

```JS
initMap(data){
    // 設定地圖
    let map = L.map('map').setView([24.175339, 120.648586], 19);
    
    // 新增圖磚
    L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
    
    // 建立點位
    let layer = data.map(ele => { L.marker([ele.y, ele.x]).addTo(map) });
    
    // 新增點位到圖磚上
    map.addLayer(layer);
}
```

那我們是不是只要直接套用就可以了呢?

```JS
const app = Vue.createApp({
    data(){},
    methods:{
        initMap(data){
            // ...
        },
        getScenicSpots(){
            // ...
        },
        searchScenicByCounty(){
            Swal.fire({
               // ...
            }).then((result) => {
                if (result.isConfirmed) {
                    axios({
                        method: 'get',
                        url: `./api/ScenicSpot/${result.value}`
                    }).then(res => {
                        // 初始化地圖
                        this.initMap(res.data);
                    }).catch(err => {
                        console.log(err);
                    })
                }
            })
        },
    },
    mounted(){
        this.getScenicSpots();
    }
});
app.mount('#app');
```

如果你很開心的這樣做，然後重新整理頁面，按下查詢之後，你應該會發現的你的 console 出現了一個 error：

```
Error: Map container is already initialized.
```

由於我們在 Vue 掛載時就有用 `L.map('map')` 先初始化過地圖了，所以重複呼叫的時候就會出現這個錯誤。

#### Reference

- [TDX運輸資料流通服務 — 主資料代碼表查詢](https://tdx.transportdata.tw/api-service/codeQuery?ref=blog.anthea.day)