終於要開始實作「獲取用戶地理位置」的功能了
要獲取地理位置必須使用「Geolocation API」這個Web API。先來看一下這個API的瀏覽器支援程度:
整體來說還算不錯,有9成的browser覆蓋率XDD
了解如何使用這個API前,要先在feed.js中來存取前端頁面的「目前所在地按鈕」和「等待圖示」。並在feed.css中將等待圖示預設為隱藏:
var locationBtn = document.querySelector('#location-btn');
var locationLoader = document.querySelector('#location-loader');
var fetchedLocation; // 透過Geolocation API取得的「經緯度」放在此變數中
#create-post #location-loader {
display: none;
}
當用戶開啟發佈貼文頁面時,在openCreatePostModal() function中,新增initializeLocation()
函式。初始化函式只是先確認瀏覽器有無支援Geolocation API,沒有的話就將「目前所在地按鈕」隱藏起來:
function initializeLocation() {
if(!('geolocation' in navigator)) {
locationBtn.style.display = 'none';
}
}
而當用戶關閉發佈貼文頁面時,就在closeCreatePostModal() function中將「目前所在地按鈕」和「等待圖示」恢復預設值:
locationBtn.style.display = 'inline';
locationLoader.style.display = 'none';
接著要來開始實作用戶點擊「目前所在地按鈕」後,取得地理位置的功能:
locationBtn.addEventListener('click', function(event) {
var sawAlert = false; // 這裡是為了避免alert警告跳出兩次
locationBtn.style.display = 'none';
locationLoader.style.display = 'block';
navigator.geolocation.getCurrentPosition(function(position) {
locationBtn.style.display = 'inline';
locationLoader.style.display = 'none';
fetchedLocation = {
lat: position.coords.latitude,
lng: position.coords.longitude
};
fetch('https://api.opencagedata.com/geocode/v1/json?key=edc4d63b87574763be46eb988e85172c&q=' + fetchedLocation.lat + '%2C+' + fetchedLocation.lng + '&pretty=1&no_annotations=1').then(function(res) {
return res.json();
}).then(function(data) {
console.log(data);
locationInput.value = data.results[0].components.county;
document.querySelector('#manual-location').classList.add('is-focused');
});
}, function(err) {
console.log(err);
locationBtn.style.display = 'inline';
locationLoader.style.display = 'none';
if(!sawAlert) {
sawAlert = true;
alert('無法獲取用戶位置,請手動輸入!!');
}
fetchedLocation = {
'lng': 0,
'lat': 0
};
}, {timeout: 7000})
});
首先,在監聽到用戶點擊「目前所在地按鈕」的事件後,先將按鈕隱藏起來,並顯示等待圖示。接著使用geolocation.getCurrentPosition()
方法取得用戶目前所在的地理位置,方法中要輸入「2個callback function」和「1個option object」。第一個為成功接收到用戶position(經緯度)時的success callback function
,第二個為error callback function
,最後的參數設定等待API回復的時間
(這裡設成7秒)。
在第一個success callback function中,代表成功取得地理位置,所以再一次的按鈕顯示出來,並將等待圖示隱藏起來。接著使用position.coords
將用戶的經緯度值傳到fetchedLocation object中。
由於這裡透過API取得到的只有經緯度資訊而已,為了要將「經緯度」轉換成「一般的地理位置」,我使用OpenCage Geocoder API。fetch回來的response data內容非常多,這裡我只使用data.results[0].components.county
取得用戶所在的縣市,並把它顯示在location input欄位中。
至於第2個error callback function,也就是當無法取得location時,就將「目前所在地按鈕」和「等待圖示」恢復成預設,以及把fetchedLocation object中的經緯度設為0。
目前實作到這邊,PWA project的功能都已經完成的差不多了,不過還有兩個bug需要修復 XDD
第一個為當用戶關閉發佈貼文視窗時,攝像鏡頭還是繼續開啟的,所以必須在closeCreatePostModal() function中加入之前寫過的「停止video stream」的code:
if(videoPlayer.srcObject) {
videoPlayer.srcObject.getVideoTracks().forEach(function(track) {
track.stop();
});
}
第二個為當用戶網路離線時,會發現背景同步時會出現錯誤,因為我還有去呼叫一個外部的OpenCage Geocoder API,而這邊必須要catch住這個error,以下為完整的fetch程式碼,可以發現catch中的code是直接copy上面已經寫好的error callback function
:
fetch('https://api.opencagedata.com/geocode/v1/json?key=edc4d63b87574763be46eb988e85172c&q=' + fetchedLocation.lat + '%2C+' + fetchedLocation.lng + '&pretty=1&no_annotations=1').then(function(res) {
return res.json();
}).then(function(data) {
console.log(data);
locationInput.value = data.results[0].components.county;
document.querySelector('#manual-location').classList.add('is-focused');
}).catch(function(err) {
console.log(err);
locationBtn.style.display = 'inline';
locationLoader.style.display = 'none';
if(!sawAlert) {
sawAlert = true;
alert('無法獲取用戶位置,請手動輸入!!');
}
fetchedLocation = {
'lng': 0,
'lat': 0
};
});
呼!! 寫到這,PWA project該有的功能都已經完成的了~~~可喜可賀
Day27 結束!!