---
tags: Example,
disqus: hackmd
---
# 台灣高鐵 API練習
[台灣高鐵...](https://www.thsrc.com.tw/index.html)
[API位置](https://ptx.transportdata.tw/MOTC?t=Rail&v=2#/)
### 本次練習目標
1.製作能看到各車站的基本資料。
2.製作票價表:所有票價、選擇的起訖站票價、各車廂票價。
3.製作時刻表:單一條件搜尋或交叉搜尋日期、起訖站、車次代碼,並顯示票價。
### 製作想法
預計製作三個頁面分別是基本資料、票價表、時刻表,因此我打算使用三個閉包來放置個頁面的code,方便以後維護或新增,然後匯聚至一個閉包做統整與執行。
### 製作上遇到的問題
1.條件篩選
以往都是將API資料取回再直接做顯示,這是第一次製作多條件的顯示,把資料拿回來後要再根據條件做篩選。
2.該使用哪隻API
面對眾多的API我該如何選擇,以及在考慮到我的多條件,我應該要使用哪些資料。
### 心得
本次的製作,儘管已經在開始前有先構思過一番設計結構,但在製作中還是有遇到API要在統整處再帶入,還是放在各頁閉包的掙扎。
以及本次的條件搜尋,並非完全像台灣高鐵官網的需選擇起訖站、日期、時間才能搜尋。
而是把日期設為必填,有日期+起訖站、日期+車次、日期+起訖站+車次的搜尋選擇。
```htmlmixed=
<html>
<head>
<title>台灣高鐵 - ajax作業</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="jquery-3.5.1.min.js"></script>
<link rel="stylesheet" href="index.css">
</head>
<body>
<div class="page-body">
<h2 class="body-title">台灣高鐵</h2>
<div class="nav-wrap">
<div id="nav-station" class="nav-item active" data-index="0">車站資訊</div>
<div id="nav-price" class="nav-item" data-index="1">票價表</div>
<div id="nav-time" class="nav-item" data-index="2">時刻表</div>
</div>
<div id="station-board" class="content-wrap active">
<h3 class="station-title">車站資訊</h3>
<div id="station-nav" class="clearfix"></div>
<div class="station-content clearfix">
<div class="station-content-wrap">
<p id="station-cname" class="station-cname"></p>
<p id="station-ename" class="station-ename"></p>
<p id="station-address" class="station-address"></p>
</div>
<img id="station-image" class="station-image" src="" alt="">
</div>
</div>
<div id="price-board" class="content-wrap">
<div class="type-wrap">
<p class="type-button active" data-type="4">所有票價</p>
<p class="type-button" data-type="5">起訖站票價</p>
<p class="type-button" data-type="0">商務票價</p>
<p class="type-button" data-type="1">標準票價</p>
<p class="type-button" data-type="2">自由票價</p>
</div>
<div id="all-table" class="price-wrap active">
<div class="all-table-content">
<h3 class="price-title">商務票價</h3>
</div>
<div class="all-table-content">
<h3 class="price-title">標準票價</h3>
</div>
<div class="all-table-content">
<h3 class="price-title">自由票價</h3>
</div>
</div>
<div id="level-table" class="price-wrap"></div>
<div id="select-table" class="price-wrap">
<div class="spot-wrap">
<div class="spot-content">
<p>起點站</p>
<select id="select-start"></select>
</div>
<div class="spot-content">
<p>終點站</p>
<select id="select-end"></select>
</div>
</div>
<div id="select-journey" class="select-journey"></div>
<div id="select-price"></div>
</div>
</div>
<div id="time-board" class="content-wrap">
<h3 class="time-title">時刻表與票價查詢</h3>
<div class="query-wrap">
<p class="query-title">請選擇查詢條件</p>
<div class="query-rule-wrap">
<input type="date" id="query-date" class="query-date" name="query-date">
<select id="query-start" class="query-rule"></select>
<select id="query-end" class="query-rule"></select>
<select id="query-trip" class="query-rule"></select>
</div>
<div id="query-button" class="query-button">立即查詢</div>
</div>
<div id="time-table-wrap">
<h3 id="time-table-title" class="time-table-title"></h3>
<div class="time-table">
<div id="time-table-head" class="time-table-head"></div>
<div id="time-table-body" class="time-table-body"></div>
</div>
<h3 class="time-table-title">車廂票價參考</h3>
<div id="time-price-wrap" class="time-price-wrap"></div>
</div>
</div>
</div>
<script src="index.js"></script>
</body>
</html>
```
```javascript=
/* 立即函示 + 閉包 */
(function() {
function hasClass(el, className) {
return !!el.className.match(new RegExp('(\\s|^)' + className + '(\\s|$)'));
}
function addClass(el, className) {
if (!hasClass(el, className)) {
el.className += " " + className;
}
}
function removeClass(el, className) {
if (hasClass(el, className)) {
var reg = new RegExp('(\\s|^)' + className + '(\\s|$)');
el.className=el.className.replace(reg, ' ');
}
}
function altFind(arr, callback) {
for (var i = 0; i < arr.length; i++) {
var match = callback(arr[i], i);
if (match) {
return arr[i];
}
}
}
function railStation() {
var stationNav = document.getElementById('station-nav');
var stationItem = document.getElementsByClassName('station-item');
var stationCname = document.getElementById('station-cname');
var stationEname = document.getElementById('station-ename');
var stationAddress = document.getElementById('station-address');
var stationImage = document.getElementById('station-image');
var copyArray = []; /* 複製取回資料的陣列並處理 */
var renderArray = []; /* 渲染陣列 */
var stationArray = []; /* 各站 */
var imageArray = [
{
id: '0990',
path: 'https://www.thsrc.com.tw/UploadFiles/StationInfo/55d8ad33-063d-47ab-831b-06779a2e49dd.jpg'
},
{
id: '1000',
path: 'https://www.thsrc.com.tw/UploadFiles/StationInfo/02a8e78d-c8b1-4c13-9fb6-4095167fd0d8.jpg'
},
{
id: '1010',
path: 'https://www.thsrc.com.tw/UploadFiles/StationInfo/08f71160-6772-4663-8bb0-9be4e6bae343.jpg'
},
{
id: '1020',
path: 'https://www.thsrc.com.tw/UploadFiles/StationInfo/c90e3a8a-1598-46de-a565-31f017442477.jpg'
},
{
id: '1030',
path: 'https://www.thsrc.com.tw/UploadFiles/StationInfo/e69a00c8-0fc4-48cb-87cd-68a20f86d6ea.jpg'
},
{
id: '1035',
path: 'https://www.thsrc.com.tw/UploadFiles/StationInfo/3614c021-5756-480b-9615-b6133e6fbe74.jpg'
},
{
id: '1040',
path: 'https://www.thsrc.com.tw/UploadFiles/StationInfo/a7afd699-301a-4744-886b-f476c7a96bef.jpg'
},
{
id: '1043',
path: 'https://www.thsrc.com.tw/UploadFiles/StationInfo/2ee9fcdb-b4a4-4521-b037-c9aecac26119.jpg'
},
{
id: '1047',
path: 'https://www.thsrc.com.tw/UploadFiles/StationInfo/30ed9976-3fd2-4467-afaf-2b2d45a9c988.jpg'
},
{
id: '1050',
path: 'https://www.thsrc.com.tw/UploadFiles/StationInfo/e1d5d3c1-68ed-4c7b-994b-6b4294f65649.jpg'
},
{
id: '1060',
path: 'https://www.thsrc.com.tw/UploadFiles/StationInfo/9dafd11f-d20b-45bf-be9a-e000b14cc086.jpg'
},
{
id: '1070',
path: 'https://www.thsrc.com.tw/UploadFiles/StationInfo/cc9215d5-a252-4168-af6e-1a837c1d5f2a.jpg'
}
];
var apiObject = {
handleItemClick: function() {
for (var index = 0; index < stationItem.length; index++) {
const element = stationItem[index];
element.addEventListener('click', function() {
var id = element.getAttribute('data-id');
Array.prototype.forEach.call(stationItem, function(ele) {
removeClass(ele, 'active');
});
addClass(element, 'active');
apiObject.handleContentRender(id);
});
}
},
handleContentRender: function(id) {
var targetItem = altFind(renderArray, function(ele) {
return ele.id === id;
});
stationCname.innerHTML = targetItem.cName + '站';
stationEname.innerHTML = targetItem.eName;
stationAddress.innerHTML = targetItem.address;
stationImage.setAttribute('src', targetItem.imagePath);
},
handleNavRender: function() {
/* 處理初次渲染 */
var structureDom = '';
renderArray.map(function(ele) {
var item = '<div class="station-item" data-id="'+ ele.id +'">'+ ele.cName +'</div>';
structureDom = structureDom + item;
});
stationNav.innerHTML = structureDom;
stationCname.innerHTML = renderArray[0].cName + '站';
stationEname.innerHTML = renderArray[0].eName;
stationAddress.innerHTML = renderArray[0].address;
stationImage.setAttribute('src', renderArray[0].imagePath);
addClass(stationItem[0], 'active');
this.handleItemClick();
},
handleData: function(responseText) {
/* 當api成功回傳,處理api回傳資料 */
responseData = JSON.parse(responseText);
/* 未來對方API欄位名稱變更,只需修改此處 */
responseData.map(function(element) {
var imgPath = '';
altFind(imageArray, function(image) {
if (element.StationID === image.id) {
imgPath = image.path;
}
});
copyArray.push({
id: element.StationID,
address: element.StationAddress,
cName: element.StationName.Zh_tw,
eName: element.StationName.En,
imagePath: imgPath
});
});
/* 使用jQuery的$.extend做copy array */
renderArray = $.extend(true, [], copyArray);
/* 取出各站中文名 */
renderArray.map(function(ele) {
stationArray.push(ele.cName);
})
this.handleNavRender();
},
callApi: function() {
if (copyArray.length === 0) {
$.ajax({
method: 'GET',
url: 'https://ptx.transportdata.tw/MOTC/v2/Rail/THSR/Station?$format=JSON',
dataType: 'text'
})
.done(function(data) {
apiObject.handleData(data);
});
}
},
execute: function() {
this.callApi();
}
}
return apiObject;
}
function priceTable() {
var typeButton = document.getElementsByClassName('type-button');
var allTableContent = document.getElementsByClassName('all-table-content');
var priceWrap = document.getElementsByClassName('price-wrap');
var levelTable = document.getElementById('level-table');
var allTable = document.getElementById('all-table');
var selectTable = document.getElementById('select-table');
var selectStart = document.getElementById('select-start');
var selectEnd = document.getElementById('select-end');
var selectPrice= document.getElementById('select-price');
var selectJourney = document.getElementById('select-journey');
var copyArray = []; /* 複製取回資料的陣列並處理 */
var renderArray = []; /* 渲染陣列 */
var stationArray = []; /* 各站id陣列 */
var faresLength = 3; /* 票價種類 */
var apiObject = {
handleType: function(type) {
Array.prototype.forEach.call(priceWrap, function(ele) {
removeClass(ele, 'active');
});
switch (type) {
case 4:
addClass(allTable, 'active');
break;
case 5:
addClass(selectTable, 'active');
break;
default:
apiObject.handleCreateLevelTable(type);
addClass(levelTable, 'active');
break;
}
},
handleTypeButton: function() {
var type = '';
for (var index = 0; index < typeButton.length; index++) {
typeButton[index].addEventListener('click', function() {
Array.prototype.forEach.call(typeButton, function(ele) {
removeClass(ele, 'active');
});
addClass(this, 'active');
type = this.getAttribute('data-type');
apiObject.handleType(parseInt(type, 10));
});
}
},
handleRenderSelect: function(journey) {
/* 起訖站票價跟地點 */
selectJourney.innerText = journey.startCName +'到'+ journey.endCName;
selectPrice.innerHTML = '<p class="select-price-item">商務票價格為:'+ journey.fares[0].price +'</p>' + '<p class="select-price-item">標準票價格為:'+ journey.fares[1].price +'</p>' + '<p class="select-price-item">自由票價格為:'+ journey.fares[2].price +'</p>'
},
handleSelectTableChange: function() {
/* 起訖站下拉選單事件 */
var startSpot = '';
var endSpot = '';
var journey = [];
selectStart.addEventListener('change', function() {
startSpot = this.value;
if (this.value === '0') {
return;
}
if (!endSpot || endSpot === '0') {
journey = renderArray.filter(function(ele) {
return ele.startId === startSpot;
});
return;
}
if (selectStart.value === selectEnd.value) {
alert('起點站/終點站 不能相同');
} else {
journey = altFind(renderArray, function(ele) {
return ele.startId === startSpot && ele.endId === endSpot;
});
apiObject.handleRenderSelect(journey);
}
});
selectEnd.addEventListener('change', function() {
endSpot = this.value;
if (this.value === '0') {
return;
}
if (!startSpot || startSpot === '0') {
journey = renderArray.filter(function(ele) {
return ele.endId === endSpot;
});
return;
}
if (selectStart.value === selectEnd.value) {
alert('起點站/終點站 不能相同');
} else {
journey = altFind(renderArray, function(ele) {
return ele.startId === startSpot && ele.endId === endSpot;
});
apiObject.handleRenderSelect(journey);
}
});
},
handleCreateSelectTable: function() {
/* 起訖站票價 */
var tmpStartDom = '<option value="0">請選擇起點</option>';
var tmpEndDom = '<option value="0">請選擇終點</option>';
stationArray.map(function(ele) {
tmpStartDom = tmpStartDom + '<option value="'+ ele.id +'">'+ ele.cName +'</option>';
tmpEndDom = tmpEndDom + '<option value="'+ ele.id +'">'+ ele.cName +'</option>';
});
selectStart.innerHTML = tmpStartDom;
selectEnd.innerHTML = tmpEndDom;
this.handleSelectTableChange();
},
handleCreateLevelTable: function(type) {
/* 個別票價 */
var tmpDom = '';
stationArray.forEach(function(ele) {
var price = '';
ele.list.forEach(function(item){
price = price + '<div class="price-item"><div>'+ item.endCName +'</div><div class="price-dolor">'+ item.fares[type].price +'</div></div>';
});
tmpDom = tmpDom + '<div class="price-box"><div class="price-item">'+ ele.cName +'</div>'+ price +'</div>';
});
levelTable.innerHTML = tmpDom;
},
handleCreateAllTable: function() {
/* 所有票價 */
for (var index = 0; index < faresLength; index++) {
var tmpDom = allTableContent[index].innerHTML;
stationArray.forEach(function(ele) {
var price = '';
ele.list.forEach(function(item){
price = price + '<div class="price-item"><div>'+ item.endCName +'</div><div class="price-dolor">'+ item.fares[index].price +'</div></div>';
});
tmpDom = tmpDom + '<div class="price-box"><div class="price-item">'+ ele.cName +'</div>'+ price +'</div>';
});
allTableContent[index].innerHTML = tmpDom;
}
},
handleStation: function() {
var tmpArray = [];
renderArray.forEach(function(ele) {
tmpArray.push(ele.startId);
});
stationArray = tmpArray.filter(function(element, index, arr) {
return arr.indexOf(element) === index;
}).sort();
stationArray.forEach(function(ele, index) {
stationArray.splice(index, 1, {
id: ele,
list: []
});
});
renderArray.map(function(ele) {
altFind(stationArray, function(station, index) {
if (ele.startId === station.id) {
if (!stationArray[index].cName) {
stationArray[index].cName = ele.startCName;
}
stationArray[index].list.push(ele);
stationArray[index].list.sort(function(a, b) {
return a.endId - b.endId;
});
}
});
});
},
handleData: function(responseText) {
/* 當api成功回傳,處理api回傳資料 */
responseData = JSON.parse(responseText);
/* 未來對方API欄位名稱變更,只需修改此處 */
responseData.map(function(element) {
var faresRenameArray = [];
var faresSortArray = element.Fares.sort(function(a, b) {
if (a.TicketType < b.TicketType) {
return -1;
}
if (a.TicketType > b.TicketType) {
return 1;
}
return 0;
});
faresSortArray.forEach(function(ele) {
faresRenameArray.push({
type: ele.TicketType,
price: ele.Price
});
});
copyArray.push({
startId: element.OriginStationID,
endId: element.DestinationStationID,
startCName: element.OriginStationName.Zh_tw,
startEName: element.OriginStationName.En,
endCName: element.DestinationStationName.Zh_tw,
endEName: element.DestinationStationName.En,
fares: faresRenameArray
});
});
/* 使用jQuery的$.extend做copy array */
renderArray = $.extend(true, [], copyArray);
renderArray.sort(function(a, b) {
return a.startId - b.startId;
});
this.handleStation();
this.handleCreateAllTable();
this.handleCreateSelectTable();
},
execute: function() {
this.handleTypeButton();
}
}
return apiObject;
}
function timeTable() {
var queryStart = document.getElementById('query-start');
var queryEnd = document.getElementById('query-end');
var queryDate = document.getElementById('query-date');
var queryTrip = document.getElementById('query-trip');
var queryButton = document.getElementById('query-button');
var timeTableTitle = document.getElementById('time-table-title');
var timeTableHead = document.getElementById('time-table-head');
var timeTableBody = document.getElementById('time-table-body');
var timePriceWrap = document.getElementById('time-price-wrap');
var queryRule = document.getElementsByClassName('query-rule');
var copyArray = []; /* 複製取回資料的陣列並處理 */
var renderArray = []; /* 渲染陣列 */
var stationArray = []; /* 各站id陣列 */
var tripArray = []; /* 所有車次陣列 */
var startStationId = '0';
var endStationId = '0';
var apiObject = {
handleRenderTrip: function(date, trip) {
/* 產生指定日期車次的時刻表 */
var tripDom = '';
var startCName = '';
var endCName = '';
var tripStartId = '';
var tripEndId = '';
var fares = [];
altFind(tripArray, function(ele) {
if (ele.trainNumber === trip) {
tripStartId = ele.startId;
tripEndId = ele.endId;
startCName = ele.startCName;
endCName = ele.endCName;
ele.stopTimes.map(function(stopTime) {
var stationCName = '<p>' + stopTime.StationName.Zh_tw + '</p>';
var departureTime = '<p>' + stopTime.DepartureTime + '</p>';
tripDom = tripDom + '<div class="item-trip">' + stationCName + departureTime + '</div>';
});
}
});
altFind(stationArray, function(startStation) {
if (tripStartId === startStation.id) {
altFind(startStation.list, function(endStation) {
if (tripEndId === endStation.endId) {
fares = endStation.fares;
}
});
}
});
timeTableTitle.innerHTML = '<div>' + date + '的' + trip + '車次' + '</div><div>從' + startCName + '站出發到' + endCName + '站</div>';
timeTableHead.innerHTML = '<div class="item-table">各站出發時間</div>';
timeTableBody.innerHTML = '<div>' + tripDom + '</div>';
timePriceWrap.innerHTML = '<div class="price-tr">商務票價格:'+ fares[0].price +'</div>' + '<div class="price-tr">標準票價格:'+ fares[1].price +'</div>' + '<div class="price-tr">自由票價格:'+ fares[2].price +'</div>';
},
handleRenderTable: function(date, startId, endId, tmpArray) {
/* 產生指定日期起訖站的時刻表 */
var startCName = '';
var endCName = '';
var fares = [];
var tbodyDom = '';
altFind(stationArray, function(ele) {
if (ele.id === startId) {
startCName = ele.cName;
altFind(ele.list, function(eleList) {
if (eleList.endId === endId) {
endCName = eleList.endCName;
fares = eleList.fares;
}
});
}
});
tmpArray.map(function(ele) {
var trainNumber = '<div class="item-table">' + ele.trainNumber + '</div>';
var departureTime = '<div class="item-table">' + ele.departureTime + '</div>';
var arrivalTime = '<div class="item-table">' + ele.arrivalTime + '</div>';
tbodyDom = tbodyDom + '<div>' + trainNumber + departureTime + arrivalTime + '</div>';
});
timeTableTitle.innerHTML = date + ' ' + startCName + '站 到 ' + endCName + '站';
timeTableHead.innerHTML = '<div class="item-table">車次</div><div class="item-table">出發時間</div><div class="item-table">到站時間</div>';
timeTableBody.innerHTML = tbodyDom;
timePriceWrap.innerHTML = '<div class="price-tr">商務票價格:'+ fares[0].price +'</div>' + '<div class="price-tr">標準票價格:'+ fares[1].price +'</div>' + '<div class="price-tr">自由票價格:'+ fares[2].price +'</div>';
},
handleQuery: function() {
var startId = queryStart.value;
var endId = queryEnd.value;
var date = queryDate.value;
var trip = queryTrip.value;
if (!queryDate.value) {
return alert('請選擇日期');
}
if (queryStart.value !== '0' && queryEnd.value !== '0') {
if (queryStart.value === queryEnd.value) {
return alert('起點/終點 不能是同一個點');
}
if (trip !== '0') {
apiObject.callDateDestination(date, startId, endId, trip);
} else {
apiObject.callDateDestination(date, startId, endId);
}
return;
}
if (queryStart.value !== '0' || queryEnd.value !== '0') {
return alert('請選擇 起點/終點');
}
if (trip && trip !== '0') {
apiObject.handleRenderTrip(date, trip);
}
},
handleTripSelect: function(tripDataArray) {
/* 車次下拉選單 */
queryTrip.innerHTML = '';
var optionDom = '<option value="0">請選擇車次</option>';
tripDataArray.map(function(ele) {
optionDom = optionDom + '<option value="' + ele.trainNumber + '">' + ele.trainNumber + '</option>'
});
queryTrip.innerHTML = optionDom;
},
handleDate: function() {
Date.prototype.addDays = function(days) {
this.setDate(this.getDate() + days);
return this;
}
var today = new Date();
var limitDay = new Date().addDays(28);
var transToday = today.toISOString().substr(0, 10);
var transLimitDay = limitDay.toISOString().substr(0, 10);
// queryDate.defaultValue = transToday;
queryDate.setAttribute('min', transToday);
queryDate.setAttribute('max', transLimitDay);
/* 使用預設當日取得當日所有車次的時刻表資料 */
this.callDate(transToday);
},
handleStationSelect: function() {
/* 起訖站下拉選單 */
var tmpStartDom = '<option value="0">請選擇起點</option>';
var tmpEndDom = '<option value="0">請選擇終點</option>';
stationArray.map(function(ele) {
tmpStartDom = tmpStartDom + '<option value="'+ ele.id +'">'+ ele.cName +'</option>';
tmpEndDom = tmpEndDom + '<option value="'+ ele.id +'">'+ ele.cName +'</option>';
});
queryStart.innerHTML = tmpStartDom;
queryEnd.innerHTML = tmpEndDom;
},
handleStation: function() {
var tmpArray = [];
renderArray.forEach(function(ele) {
tmpArray.push(ele.startId);
});
stationArray = tmpArray.filter(function(element, index, arr) {
return arr.indexOf(element) === index;
}).sort();
stationArray.forEach(function(ele, index) {
stationArray.splice(index, 1, {
id: ele,
list: []
});
});
renderArray.map(function(ele) {
altFind(stationArray, function(station, index) {
if (ele.startId === station.id) {
if (!stationArray[index].cName) {
stationArray[index].cName = ele.startCName;
}
stationArray[index].list.push(ele);
stationArray[index].list.sort(function(a, b) {
return a.endId - b.endId;
});
}
});
});
},
handleBindEvent: function() {
queryButton.addEventListener('click', this.handleQuery);
queryStart.addEventListener('change', function() {
var date = queryDate.value;
startStationId = this.value;
/* 篩選符合起訖站之車次下拉選單 */
if (endStationId !== '0' && startStationId !== '0') {
apiObject.callDateDestination(date, startStationId, endStationId, '0');
} else if (endStationId === '0' && startStationId === '0') {
apiObject.handleTripSelect(tripArray);
}
});
queryEnd.addEventListener('change', function() {
var date = queryDate.value;
endStationId = this.value;
/* 篩選符合起訖站之車次下拉選單 */
if (startStationId !== '0' && endStationId !== '0') {
apiObject.callDateDestination(date, startStationId, endStationId, '0');
} else if (endStationId === '0' && startStationId === '0') {
apiObject.handleTripSelect(tripArray);
}
});
queryDate.addEventListener('change', function() {
var date = queryDate.value;
if (!!date) {
Array.prototype.forEach.call(queryRule, function(ele) {
addClass(ele, 'show');
});
}
if (startStationId !== '0' && endStationId !== '0') {
apiObject.callDateDestination(date, startStationId, endStationId, '0');
} else {
apiObject.callDate(this.value);
}
});
},
handleData: function(responseText) {
/* 當api成功回傳,處理api回傳資料 */
responseData = JSON.parse(responseText);
/* 未來對方API欄位名稱變更,只需修改此處 */
responseData.map(function(element) {
var faresRenameArray = [];
var faresSortArray = element.Fares.sort(function(a, b) {
if (a.TicketType < b.TicketType) {
return -1;
}
if (a.TicketType > b.TicketType) {
return 1;
}
return 0;
});
faresSortArray.forEach(function(ele) {
faresRenameArray.push({
type: ele.TicketType,
price: ele.Price
});
});
copyArray.push({
startId: element.OriginStationID,
endId: element.DestinationStationID,
startCName: element.OriginStationName.Zh_tw,
startEName: element.OriginStationName.En,
endCName: element.DestinationStationName.Zh_tw,
endEName: element.DestinationStationName.En,
fares: faresRenameArray
});
});
/* 使用jQuery的$.extend做copy array */
renderArray = $.extend(true, [], copyArray);
renderArray.sort(function(a, b) {
return a.startId - b.startId;
});
this.handleStation();
this.handleStationSelect();
this.handleDate();
this.handleBindEvent();
},
callDateDestination: function(date, startId, endId, trip) {
/* 取得指定[日期],[起迄站間]之時刻表資料 */
$.ajax({
method: 'GET',
url: 'https://ptx.transportdata.tw/MOTC/v2/Rail/THSR/DailyTimetable/OD/'+ startId +'/to/'+ endId +'/'+ date +'?$format=JSON',
dataType: 'text'
})
.done(function(data) {
var tmpArray = []
responseData = JSON.parse(data);
responseData.map(function(ele) {
tmpArray.push({
trainNumber: ele.DailyTrainInfo.TrainNo,
departureTime: ele.OriginStopTime.DepartureTime,
arrivalTime: ele.DestinationStopTime.ArrivalTime
});
});
tmpArray.sort(function (a, b) {
if (a.departureTime < b.departureTime) {
return -1;
}
if (a.departureTime > b.departureTime) {
return 1;
}
return 0;
});
if (trip !== '0') {
altFind(tmpArray, function(ele) {
if (ele.trainNumber === trip) {
tmpArray=[];
tmpArray.push(ele);
}
});
apiObject.handleRenderTable(date, startId, endId, tmpArray);
} else if (trip === '0') {
apiObject.handleTripSelect(tmpArray);
}
});
},
callDate: function(date) {
/* 取得指定[日期]所有車次的時刻表資料(高鐵提供近28天每日時刻表) */
$.ajax({
method: 'GET',
url: 'https://ptx.transportdata.tw/MOTC/v2/Rail/THSR/DailyTimetable/TrainDate/'+ date +'?$format=JSON',
dataType: 'text'
})
.done(function(data) {
var tmpArray = [];
responseData = JSON.parse(data);
responseData.map(function(ele) {
tmpArray.push({
trainNumber: ele.DailyTrainInfo.TrainNo,
startId: ele.DailyTrainInfo.StartingStationID,
endId: ele.DailyTrainInfo.EndingStationID,
startCName: ele.DailyTrainInfo.StartingStationName.Zh_tw,
endCName: ele.DailyTrainInfo.EndingStationName.Zh_tw,
stopTimes: ele.StopTimes
});
});
/* 使用jQuery的$.extend做copy array */
tripArray = $.extend(true, [], tmpArray);
apiObject.handleTripSelect(tripArray);
});
}
}
return apiObject;
}
function handleOnload(assembleObj){
var navItem = document.getElementsByClassName('nav-item');
var contentWrap = document.getElementsByClassName('content-wrap');
var railStation = assembleObj.railStation();
var priceTable = assembleObj.priceTable();
var timeTable = assembleObj.timeTable();
var apiObject = {
callApi: function() {
$.ajax({
method: 'GET',
url: 'https://ptx.transportdata.tw/MOTC/v2/Rail/THSR/ODFare?$format=JSON',
dataType: 'text'
})
.done(function(data) {
priceTable.handleData(data);
timeTable.handleData(data);
});
},
handleClick: function() {
Array.prototype.forEach.call(navItem, function(ele) {
ele.addEventListener('click', function() {
var dataIndex = this.getAttribute('data-index');
Array.prototype.forEach.call(navItem, function(ele) {
removeClass(ele, 'active');
});
Array.prototype.forEach.call(contentWrap, function(ele) {
removeClass(ele, 'active');
});
addClass(contentWrap[dataIndex], 'active');
addClass(this, 'active');
});
});
},
execute: function() {
railStation.execute();
priceTable.execute();
this.handleClick();
this.callApi();
}
}
return apiObject;
};
var assembleObj = {
railStation: railStation,
priceTable: priceTable,
timeTable: timeTable
}
var executeOnload = handleOnload(assembleObj);
executeOnload.execute();
})();
/* 立即函示 + 閉包 */
```
```css=
.clearfix:after {
display: table;
content: "";
clear: both;
}
body {
margin: 0;
}
p {
margin: 0;
}
.body-title {
margin: 0;
color: #555354;
line-height: 60px;
text-align: center;
}
.nav-wrap {
margin-bottom: 30px;
background: #585455;
color: #FFF;
text-align: center;
}
.nav-item {
display: inline-block;
padding: 0 15px;
cursor: pointer;
line-height: 40px;
user-select: none;
transition: all .3s ease;
}
.nav-item:hover,
.nav-item.active {
background: #D85221;
}
/* station */
.station-title,
.time-title {
margin: 0 auto 20px;
color: #D85221;
font-size: 24px;
font-weight: bold;
}
.station-item {
width: 75px;
height: 40px;
line-height: 40px;
cursor: pointer;
text-align: center;
float: left;
}
.station-item:hover,
.station-item.active {
color: #D85221;
font-size: 20px;
}
.station-item:hover:after,
.station-item.active:after {
display: block;
content: '';
background: #D85221;
width: 100%;
height: 5px;
}
.station-content {
padding: 25px;
background: #F7F7F7;
}
.station-content-wrap {
float: left;
}
.station-image {
float: right;
}
.station-cname {
color: #868686;
font-size: 25px;
font-weight: bold;
}
.station-ename {
margin-bottom: 15px;
color: #868686;
font-size: 25px;
}
/* content-wrap */
.content-wrap {
display: none;
margin: 0 auto 60px;
width: 100%;
max-width: 900px;
}
.content-wrap.active {
display: block;
}
/* price-wrap */
.price-wrap {
display: none;
}
.price-wrap.active {
display: block;
}
.price-wrap#select-table {
margin: 0 auto;
width: 400px;
}
.price-title {
color: #D85221;
text-align: center;
font-size: 24px;
letter-spacing: 5px;
}
.price-box {
margin-bottom: 20px;
text-align: center;
}
.price-item {
display: inline-block;
width: 75px;
}
.price-dolor {
border: solid 1px #CCC;
height: 50px;
line-height: 50px;
}
.spot-wrap {
margin-bottom: 30px;
text-align: center;
}
.spot-content {
display: inline-block;
margin: 0 20px;
}
.spot-content p {
color: #D85221;
font-size: 20px;
}
.spot-content select {
width: 150px;
height: 35px;
font-size: 20px;
}
.select-journey {
margin-bottom: 15px;
color: #D85221;
font-size: 24px;
font-weight: bold;
}
.select-price-item {
padding: 0 20px;
height: 40px;
line-height: 40px;
color: #494949;
font-size: 20px;
}
.select-price-item:nth-child(2n+1) {
background: #F7F7F7;
}
.select-price-item:nth-child(2n) {
background: #DCDCDC;
}
/* type-wrap */
.type-wrap {
margin-bottom: 30px;
text-align: center;
}
.type-button {
display: inline-block;
padding: 5px;
cursor: pointer;
user-select: none;
font-weight: bold;
letter-spacing: 1px;
}
.type-button:hover,
.type-button.active {
color: #87C252;
}
/* time-table */
.time-table {
width: 100%;
}
.time-table-title {
color: #D85221;
}
.time-table-head {
background: #585455;
text-align: center;
}
.time-table-head .item-table {
color: #FFF;
}
.time-table-body {
text-align: center;
}
.time-table-body>div:nth-child(2n+1) {
background: #F7F7F7;
}
.time-table-body>div:nth-child(2n) {
background: #DCDCDC;
}
.time-table-body .item-table:first-child {
color: #D85221;
}
.item-trip {
display: inline-block;
padding: 10px 0;
width: calc(100% / 12);
color: #494949;
text-align: center;
}
.item-table {
display: inline-block;
width: 33.33%;
height: 40px;
font-size: 18px;
line-height: 40px;
}
/* query-wrap */
.query-wrap {
padding: 20px;
background: #F7F7F7;
}
.query-title {
margin-bottom: 15px;
font-size: 20px;
color: #585455;
}
.query-button {
background: #6F6F6F;
height: 40px;
cursor: pointer;
user-select: none;
color: #FFF;
line-height: 40px;
text-align: center;
}
.query-rule-wrap {
margin-bottom: 20px;
}
.query-date {
padding: 5px;
width: 150px;
height: 40px;
}
.query-rule {
padding: 5px;
width: 150px;
height: 40px;
opacity: 0;
visibility: hidden;
transition: all .5s ease;
}
.query-rule.show {
opacity: 1;
visibility: visible;
}
/* time-table-wrap */
.price-tr {
padding: 0 20px;
height: 40px;
line-height: 40px;
color: #494949;
font-size: 20px;
}
.price-tr:nth-child(2n+1) {
background: #F7F7F7;
}
.price-tr:nth-child(2n) {
background: #DCDCDC;
}
```