終於來到 Vue2.x 介紹的尾聲了,藉由完成今天自己的旅遊小幫手範例一起收尾吧,GO~
一樣的,先將取回來的 YouBike 資訊寫成計算屬性,留下該符合該地區的資料,方便之後資料的處理
// computed
renderBikes(){
if(this.selectArea === '全景點'){
return this.youbikes;
}else{
return this.youbikes.filter(ele => ele.sarea.match(this.selectArea))
}
}
當選擇其一飯店時,顯示該地區各景點與該飯店的距離,不過因為資料只提供經緯度,所以我們必需運用經緯度來換算成公里數或其它我們比較熟悉的距離單位,提供我們參考
// methods
distance(lat1, lon1, lat2, lon2) {
if ((lat1 == lat2) && (lon1 == lon2)) {
return 0;
}
else {
let radlat1 = Math.PI * lat1/180;
let radlat2 = Math.PI * lat2/180;
let theta = lon1-lon2;
let radtheta = Math.PI * theta/180;
let dist = Math.sin(radlat1) * Math.sin(radlat2) + Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta);
if (dist > 1) {
dist = 1;
}
dist = Math.acos(dist);
dist = dist * 180/Math.PI;
dist = dist * 60 * 1.1515;
// 轉為公里
dist = dist * 1.609344;
return dist;
}
},
這部份可以搜尋一下,關於經緯度計算距離,畢竟很少會去用到~
// computed 再寫一個 景點的篩選,用來負責最終結果渲染使用
nearAttractions(){
// 飯店位置
let lon1 = this.selectHotel.經度Lng;
let lat1 = this.selectHotel.緯度Lat;
//計算景點離飯店的距離
this.renderAttractions.forEach(ele => {
let lon2 = ele.Px;
let lat2 = ele.Py;
let tmp = this.distance(lat1, lon1, lat2, lon2);
ele.betweens = Math.floor(tmp * 100) / 100;
})
return this.renderAttractions;
},
把計算完的距離加入資料中,後面顯示會使用到
<div id="app">
// ... 略
<div class="planningCard" v-if="hasPlanning">
<h3 class="markText">{{ selectHotel.旅宿名稱 }}</h3>
<span>{{ selectHotel.電話 }}</span>
<p>{{ selectHotel.地址 }}</p>
<div class="planningAttractions">
<div class="partCard" v-for="item in nearAttractions" :key="item.Id">
<span class="markText">{{ item.Name }}</span><span>[ 距離 : {{ item.betweens }} 公里]</span>
<p>{{ item.Add }}</p>
<div>
<p class="traffic">交通方式</p>
<p >{{ item.Travellinginfo }}</p>
</div>
</div>
</div>
</div>
</div>
<script>
// computed
hasPlanning(){
// 判斷是否為空物件
if(JSON.stringify(this.selectHotel) === '{}'){
return false;
}else{
return true;
}
},
</script>
顯示該飯店訊息、該地區景點、我們計算出來的景點與飯店距離、如果有提供景點的交通方式也一併顯示。
因為該顯示區塊為選擇飯店後才顯示,所以使用 v-if
搭配計算屬性( hasPlanning
)回傳的方式控制
// computed
nearAttractions(){
// 飯店位置
let lon1 = this.selectHotel.經度Lng;
let lat1 = this.selectHotel.緯度Lat;
//計算景點離飯店的距離
this.renderAttractions.forEach(ele => {
let lon2 = ele.Px;
let lat2 = ele.Py;
let tmp = this.distance(lat1, lon1, lat2, lon2);
ele.betweens = Math.floor(tmp * 100) / 100;
})
// 處理景點附近的 youbikes
this.renderAttractions.forEach(ele => {
let lon2 = ele.Px;
let lat2 = ele.Py;
ele.bikes = [];
this.renderBikes.forEach( bike => {
let lon3 = bike.lng;
let lat3 = bike.lat;
let tmp2 = this.distance(lat3, lon3, lat2, lon2);
tmp2 = Math.floor(tmp2 * 100) / 100;
if(tmp2 < 1 ) ele.bikes.push(bike);
})
})
return this.renderAttractions;
},
<div id="app">
// ... 略
<div class="planningCard" v-if="hasPlanning">
<h3 class="markText">{{ selectHotel.旅宿名稱 }}</h3>
<span>{{ selectHotel.電話 }}</span>
<p>{{ selectHotel.地址 }}</p>
<div class="planningAttractions">
<div class="partCard" v-for="item in nearAttractions" :key="item.Id">
<span class="markText">{{ item.Name }}</span><span>[ 距離 : {{ item.betweens }} 公里]</span>
<p>{{ item.Add }}</p>
<div>
<p class="traffic">交通方式</p>
<p >{{ item.Travellinginfo }}</p>
<template v-if="item.bikes.length > 0">
<p class="YouBikeTitle">[ 1 公里內 YouBike2.0 站點 ]</p>
<p v-for="bike in item.bikes" :key="bike.sno">
<i class="fas fa-biking"></i>
{{ bike.sna }} ➟ <span class="addr">{{ bike.ar }}</span>
</p>
</template>
</div>
</div>
</div>
</div>
</div>
目前到這邊,已經可以規劃完成前往各景點的方式或者是另外提供的 YouBike 選項,這麼一來,在行程上的安排,看似更容易達成了呢,畢竟我們的交通方式更加多元的選擇了
東跑跑、西跑跑,都已經玩得這麼累的一天了,只想好好的回旅館休息,如果我們沒有租車或是旅館無提供車位,這時如果旅館附近有 YouBike 站點,那麼可能會讓我們輕鬆一些,所以我們也將旅館附近 200 公尺內的 YouBike 站點也提供上去吧~
// methods
setHotel(item){
// 選擇飯店
this.selectHotel = item;
this.selectHotel.bikes = [];
// 飯店位置
let lon1 = item.經度Lng;
let lat1 = item.緯度Lat;
// 提供附近 youbike 站點
this.renderBikes.forEach( bike => {
let lon3 = bike.lng;
let lat3 = bike.lat;
let tmp2 = this.distance(lat1, lon1, lat3, lon3);
tmp2 = Math.floor(tmp2 * 100) / 100;
if(tmp2 < 0.3 ) this.selectHotel.bikes.push(bike);
})
},
在選擇旅館的時候,一併做 Youbike 的資料篩選,篩選離飯店較近的站點,最後儲存起來
<div id="app">
// ... 略
<div class="planningCard" v-if="hasPlanning">
<h3 class="markText">{{ selectHotel.旅宿名稱 }}</h3>
<span>{{ selectHotel.電話 }}</span>
<p>{{ selectHotel.地址 }}</p>
<!-- 加入旅館附近的 YouBike -->
<template v-if="selectHotel.bikes.length > 0">
<p class="YouBikeTitle">[ 200 公尺內 YouBike2.0 站點 ]</p>
<p v-for="bike in selectHotel.bikes" :key="bike.sno">
<i class="fas fa-biking"></i>
{{ bike.sna }} ➟ <span class="addr">{{ bike.ar }}</span>
</p>
</template>
<div class="planningAttractions">
<div class="partCard" v-for="item in nearAttractions" :key="item.Id">
<span class="markText">{{ item.Name }}</span><span>[ 距離 : {{ item.betweens }} 公里]</span>
<p>{{ item.Add }}</p>
<div>
<p class="traffic">交通方式</p>
<p >{{ item.Travellinginfo }}</p>
<template v-if="item.bikes.length > 0">
<p class="YouBikeTitle">[ 1 公里內 YouBike2.0 站點 ]</p>
<p v-for="bike in item.bikes" :key="bike.sno">
<i class="fas fa-biking"></i>
{{ bike.sna }} ➟ <span class="addr">{{ bike.ar }}</span>
</p>
</template>
</div>
</div>
</div>
</div>
</div>
因為我們畫面的安排,所以選擇完之後不允許使用者繼續切換地區,所以必需做一個按鈕讓使用者回到最初的選單畫面,原理很簡單,只要把我們當初做為控制的條件還原即可~
<div id="app">
// ... 略
<div class="planningCard" v-if="hasPlanning">
<!-- 加入關閉按鈕 -->
<i class="far fa-window-close" @click="reset"></i>
// ... 略
// methods
reset(){
this.selectHotel = {};
this.selectArea = '全景點';
}
最後終於完成啦~ 不過因為 API 的關係,我們只有以高雄的資料做範例,所以如果想作其他地區的,可以找找 Open Data 有沒有提供,接著自己動手改改看囉~
(如果要安排某些景點,可能就真的需要租車比較方便 )
<template>
作為 v-if
的渲染分組computed
的資料處理DeTools , 使用 javascript 計算兩個經緯度間的距離