【實作紀錄】台灣景點旅遊導覽 × Angular

Ray
7 min readNov 14, 2021

--

參加F2E前端個人組Week1的作品,作品連結:台灣景點旅遊導覽

主要功能

  • 景點旅遊整合應用
    取得景點、餐飲、旅宿、活動資料
  • 串接第三方API
    PTX MOTC Transport API
    Google Map
  • 搜尋功能
    支援單一關鍵字不含其他操作搜尋
    支援詳細搜尋(依種類,動態提供過濾方式:地點、活動日期、活動標籤)
    資料頁碼邏輯(參考巴哈姆特分頁邏輯)
  • UX優化
    增加按鍵回饋,提高使用者體驗
    圖文列表模式瀏覽

本文目的

主要介紹以下功能。實作邏輯、踩到的坑及可以注意的事項

  • PTX API
  • Google Map
  • Pagination

PTX API

公共運輸整合資訊-流通服務平台

主要流程

申請會員(取得使用金鑰) → 將取得金鑰加密後的資料做為要Query時用的header →
透過header發出Query請求 → 取得資料

1. 申請會員

六角學院API全攻略,照著做就可以申請通過了。申請成功後會寄Gmail給你APP ID以及APP Key,待會會用到。

2. 透過APP ID以及APP Key,建立header

在這之前記得要先安裝jssha,它能幫你把AppKey加密,畢竟一般像是Key這種比較機密的資料,在請求的時候不可能透過明碼來傳

npm i jssha

3. 對PTX發出請求

透過剛剛建立的Header,加在Query中就能取得Activity這支API的所有資料

4. 加入Filter條件

PTX API支援OData查詢語法,如果需要增加條件(例如:種類、地區、時段)可以參考這裡

舉例:我需要查找的種類是"活動",地點是"台中",活動開始的時間段是"2021/10/01"~"2021/12/31",而且種類是"產業文化活動"

先根據種類以及是否有地點,決定要打的API。

/v2/Tourism/Activity

/v2/Tourism/Activity/{City}

決定好API後,加入Filter條件(日期以及種類)。

日期(格式是YYYY-MM-DD)

StartTime:2021–10–01EndTime:2021–12–31let queryStringDate = "(StartTime gt ' + this.startTime + ' and EndTime lt ' + this.endTime + ')"

種類(給中文就可以了)

let queryStringType = "(Class1 eq '產業文化活動' or Class2 eq '產業文化活動')"

把它們加起來

let queryString = queryStringDate + 'and' + queryStringType

*還有一個要注意的是

送出Query前要先將queryString進行URL編碼(encodeURI)

encodeURI(queryString);

最後就可以發出Query了

getActivitityWithFilter('Taichung',encodeURI(queryString))

Google Map

Google Map Embed API

主要流程

申請API Key → 嵌入

1. 申請API Key

Google Developers點Get Started建立一個新的Google Map Embed專案,取得API Key,詳細參考如何申請Google Map API

2. 嵌入

Google Map有提供許多地圖模式,像是輸出兩地的路徑;放大縮小...等,我這邊選擇的是place mode(文檔)。

要完成place mode的嵌入只需要給API Url、名稱(城市)、或地址,以及定位座標(經緯度)就可以了,根據下面這一頁的資料來作範例。

API baseUrl

https://www.google.com/maps/embed/v1/place

Key

?key={你的App Key}

q

&q = "哈密街61號","台北市"

center(data就是PTX撈下來的資料,在Position中這兩個值就是經緯度)

&center=${data.Position.PositionLat},${data.Position.PositionLon}

組起來就是

https://www.google.com/maps/embed/v1/place?key={你的App Key}&q=${addressRef},${this.data.City}&center=${data.Position.PositionLat},${data.Position.PositionLon}`

最後把這串資料綁到HTML上的ifram就完成了

<iframe   frameborder=”0"  [src]=”googleMapQueryString”   allowfullscreen
>
</iframe>

3.補充

照著上面做,但是報錯了,錯誤資訊如下:

這是Angular內建的安全機制,為了避免XSS之類的攻擊,其中一個解決這個Error的方式就是將綁到iframe的src認定為被信任的網址,透過使用Angular內建的DomSanitizer

程式碼

import { DomSanitizer } from ‘@angular/platform-browser’;...constructor(private sanitizer: DomSanitizer,) { }...let q = this.sanitizer.bypassSecurityTrustResourceUrl(剛剛那串Url);

補充

取得本地位置

getPosition(): Promise<any>{ return new Promise((resolve, reject) => {  navigator.geolocation.getCurrentPosition(resp => {  resolve({lng: resp.coords.longitude, lat: resp.coords.latitude}); }, err => {    reject(err); }); });}

Pagination

分頁頁碼

不太確定是不是有些Pagination有包含這個功能,但這邊是直接自己實作,先看看每個情況下的顯示頁碼

在第一頁
在最後一頁
在中間頁(1)
在中間頁(2)

這邊的條件跟對應輸出是

  1. 如果在頁碼的位置在首頁或末頁,就只顯示三頁(含當頁)及起始或末頁
  2. 如果頁碼在中間頁,就顯示當前頁以及前後兩頁與起始及末頁
  3. 如果頁碼在中間頁,且前後兩頁包含起始頁,則顯示當前附近頁與起始或末頁

總結

假設總頁數 n = 30頁 ; 當前頁數為 x 
HTML迴圈用1~30去跑 迴圈索引 為 i
If (Math.abs(x-i) <= 2 ) { 顯示此頁頁碼 }
If (Math.abs(x-i) == 2 ) { 將此頁頁碼設為"..." }
Else { 跳過不顯示 }

--

--

No responses yet