iT邦幫忙

0

[鼠年全馬] W30 - Vue出一個旅館預約平台(4)

有朋友問我為什麼我的進度這麼緩慢...
殊不知,我每天都只有一個小時可以做額外自主練習阿QQ/images/emoticon/emoticon02.gif

這週接續著做Rooms資料處理的部分囉~
立馬開始!!


#Step 12

首先, 上週漏做了一段xD
RoomCard 有上下外距, 這個一樣是自己算出來的
來加上然後結束它~

<div class="d-flex justify-center roomcardmain">
  //RoomCard
</div>
.roomcardmain {
  margin-top: 65px;
  margin-bottom: 40px;
}

https://ithelp.ithome.com.tw/upload/images/20200731/201186867NreDxL8gO.jpg
美多了~

#Step 13

接著本週正題開始~
首先看一下 F2E 提供的API, 要先知道它會傳哪些欄位出來給我們接
順帶一提, 要用它的API要先註冊帳號喔!!! 註冊方式也在同個頁面~

API頁面直接滑到最後的 #[GET] 取得所有房型 部分
https://ithelp.ithome.com.tw/upload/images/20200731/201186866XnZr6apZk.jpg
會看到其中有個 item陣列, 其中包含:

  • id: 房間編號, 房間的唯一值, 要取得房間的詳細資訊必須使用它
  • imageUrl: 圖片網址, 房間的代表圖, 只有一張
  • normalDayPrice(integer): 平日價格
  • holidayPrice(integer): 假日價格
  • name: 房間名稱

看完之後應該會發現, 這欄位根本不夠阿/images/emoticon/emoticon01.gif
原來剩下的欄位都在另一個API- [GET] 單一房型細節
不過這邊 F2E 的範例就比較簡單, 實際傳回來的欄位多很多
放上我的Postman截圖
https://ithelp.ithome.com.tw/upload/images/20200731/20118686iagH8pnJDO.jpg
其中包含:

  • id: 房間編號, 房間的唯一值
  • name: 房間名稱
  • imageUrl(array): 圖片網址, 有多張
  • normalDayPrice(integer): 平日價格
  • holidayPrice(integer): 假日價格
  • descriptionShort(object): 房間簡單說明
    • GuestMin(integer): 最少人數
    • GuestMax(integer): 最多人數
    • Bed(array): 床型
    • Private-Bath(integer): 推測是浴室數量(?)
    • Footage(integer): 這個我真的不知道xD, 推測是設計師做的"大小"的欄位
  • description: 房間詳細說明
  • checkInAndOut(object): 入住退房時間
    • checkInEarly: 最早入住時間
    • checkInLate: 最晚入住時間
    • checkOut: 退房時間
  • amenities(object): 設施設備
    • Wi-Fi(boolean): wifi(xD)
    • Breakfast(boolean): 早餐
    • Mini-Bar(boolean): 迷你吧(xD)
    • Room-Service(boolean): 客房服務
    • Television(boolean): 電視
    • Air-Conditioner(boolean): 冷氣
    • Refrigerator(boolean): 冰箱
    • Sofa(boolean): 沙發
    • Great-View(boolean): 景觀
    • Smoke-Free(boolean): 禁止吸菸
    • Child-Friendly(boolean): 適合兒童
    • Pet-Friendly(boolean): 可帶寵物

有Google翻譯真好/images/emoticon/emoticon39.gif

看完之後大致上就可以了解哪個欄位必須放在RoomCard的哪個位置了(吧xD)

#Step 14

接著在開始ajax抓資料之前, 要先來安裝vue版的ajax - axios:

npm install axios

安裝完成之後, 開啟 main.js 引用它:

//main.js
//加這兩行
import axios from 'axios'
Vue.prototype.$http = axios

教學一下使用方式, 在要使用的地方放入以下這段, 把必填資訊(例如method、headers等等)填好就可以囉!!!

this.$http(
  {
    method: "", //填http傳遞方式 get/post/put...
    headers: {}, //F2E的API要求必須填這個, 詳見剛才的API使用方式
    url: "", //填目標的網址
  }).then((res) => {
    //存取成功時做什麼事
  }).catch((err) => {
    //存取錯誤時做什麼事
  });

#Step 15

預計抓資料的流程會是

  1. Rooms 取得 所有房型 的資料
  2. 把其中的 idimageUrl 傳入 RoomCard
  3. 再由 RoomCard 利用傳入的 id 取得 單一房型 的詳細資料來呈現

所以來開啟久違的 Rooms 吧~
先加上 created hook,準備把[取得 所有房型]的動作
另外 data 裡面可以先加個 item 空陣列, 等等資料取回來要放在這:

export default {
  ...,
  created() {
    ...
  },
  data: () => ({
    items: [],
  }),
};

hook內就可以放剛才的 axios method 囉~ 這裡都假設能正常取得資料(通常都要寫判斷~但是我懶xD):

this.$http({
  method: "get",
  headers: {
    Accept: "application/json",
    Authorization:
      "Bearer 這邊填你自己的token喔",
  },
  url: "https://challenge.thef2e.com/api/thef2e2019/stage6/rooms",
})
  .then((res) => {
    //成功取得資料時, 把items指定給data.items
    this.items = res.data.items; 
  })
  .catch((err) => {
    console.log(err);
  });

完成後可以開啟 chrome 的 Vue工具看看
https://ithelp.ithome.com.tw/upload/images/20200731/20118686AbYllByhx2.jpg
太蚌了資料都有進來/images/emoticon/emoticon42.gif
如此就完成取得房型資料了~

#Step 16

原本的v-for就可以改掉囉~

<RoomCard class="col-4" v-for="item in items" :key="item.id" />

再把 idimageUrl 傳入 RoomCard :

<RoomCard
  class="col-4"
  v-for="item in items"
  :key="item.id"
  :uid="item.id"
  :imageUrl="item.imageUrl"
/>

然後 Rooms 繼續封印xD

#Step 17

回到 RoomCard , 要來用 props 接收 Rooms 傳進來的資料
data 加上 room 物件, 等等資料取回來要放在這:

export default {
  name: "RoomCard",
  props: ["uid", "imageUrl"],
  data: () => ({
    room: {},
  }),
};

接著跟 Step 15 一樣, 加上 created hook, 裡面放 axios method:

created() {
  this.$http({
    method: "get",
    headers: {
      Accept: "application/json",
      Authorization:
        "Bearer 這邊填你自己的token喔",
    },
    url:
      "https://challenge.thef2e.com/api/thef2e2019/stage6/room/" + this.uid,
  })
    .then((res) => {
      //成功取得資料時, 把room指定給data.room
      this.room = res.data.room;
    })
    .catch((err) => {
      console.log(err);
    });
},

完成後一樣開啟 chrome 的 Vue工具來檢查
https://ithelp.ithome.com.tw/upload/images/20200731/201186863Wd6l8dn3a.jpg
資料確實有抓到呢!!!/images/emoticon/emoticon42.gif/images/emoticon/emoticon42.gif

#Step 18

再來我們就可以一一的把原本在畫面上放的假資料替換掉囉~
這裡沒什麼技巧, 就是慢慢對應替換而已
有一些需要處理的資料, 可以直接在花括號內處理
例如人數:

<div>人數</div>
 <div>
   <!--如果descriptionShort存在就判斷GuestMax與GuestMin是否相等-->
   <!--相等就放其中一個就好, 不相等就放"GuestMin~GuestMax"-->
   {{
     room.descriptionShort
       ? room.descriptionShort.GuestMax ===
         room.descriptionShort.GuestMin
         ? room.descriptionShort.GuestMin
         : `${room.descriptionShort.GuestMin}~${room.descriptionShort.GuestMax}`
       : ""
   }}
 </div>

或是床:

<div>床</div>
<div>
  <!--Array to string中間會自動加逗號-->
  {{ room.descriptionShort ? room.descriptionShort.Bed.toString() : "" }}
</div> 

也可以寫在 computed 裡面處理, 例如設施設備:
這邊很可惜的是就算用迴圈寫, 還是必須對應中文名稱...勢必要寫一長串code

computed: {
  roomAmenities() {
    let amenities = [];
    if (this.room.amenities) {
      //如果設施設備為true就塞到陣列
      if (this.room.amenities["Wi-Fi"]) {
        amenities.push(" wifi");
      }
      if (this.room.amenities["Breakfast"]) {
        amenities.push(" 早餐");
      }
      if (this.room.amenities["Mini-Bar"]) {
        amenities.push(" 小吧檯");
      }
      if (this.room.amenities["Room-Service"]) {
        amenities.push(" 客房服務");
      }
      if (this.room.amenities["Television"]) {
        amenities.push(" 電視");
      }
      if (this.room.amenities["Air-Conditioner"]) {
        amenities.push(" 冷氣");
      }
      if (this.room.amenities["Refrigerator"]) {
        amenities.push(" 冰箱");
      }
      if (this.room.amenities["Sofa"]) {
        amenities.push(" 沙發");
      }
      if (this.room.amenities["Great-View"]) {
        amenities.push(" 景觀");
      }
      if (this.room.amenities["Smoke-Free"]) {
        amenities.push(" 禁止吸煙");
      }
      if (this.room.amenities["Child-Friendly"]) {
        amenities.push(" 適合兒童");
      }
      if (this.room.amenities["Pet-Friendly"]) {
        amenities.push(" 可帶寵物");
      }
    }
    return amenities.toString();
  },
},

有更好解法請留言告訴我/images/emoticon/emoticon41.gif

對應完可以看到畫面上已經都是真實資料囉~
https://ithelp.ithome.com.tw/upload/images/20200731/20118686VAzQdGbo4f.jpg


首頁就剩[Footer]囉~留給下次吧xD
附上這次進度的雲端壓縮檔, 執行前記得先npm install

有需要改進或是任何意見建議歡迎下面留言~
/images/emoticon/emoticon29.gif/images/emoticon/emoticon29.gif/images/emoticon/emoticon29.gif


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

2
listennn08
iT邦高手 5 級 ‧ 2020-08-25 14:48:28

可以用 hash 去對應你的中文

// 資料來源
const amenities = {
  'Wi-Fi': true,
  Breakfast: false,
  'Mini-Bar': true,
  'Room-Service': false,
  Television: true,
  'Air-Conditioner': true,
  Refrigerator: true,
  Sofa: true,
  'Great-View': true,
  'Smoke-Free': true,
  'Child-Friendly': true,
  'Pet-Friendly': true,
};
// ---

const translate = {
  'Wi-Fi': 'wifi',
  Breakfast: '早餐',
  'Mini-Bar': '迷你吧',
  'Room-Service': '客房服務',
  Television: '電視',
  'Air-Conditioner': '冷氣',
  Refrigerator: '冰箱',
  Sofa: '沙發',
  'Great-View': '景觀',
  'Smoke-Free': '禁止吸菸',
  'Child-Friendly': '適合兒童',
  'Pet-Friendly': '可帶寵物',
};

const amenitiesCn = [];

Object.keys(amenities).forEach((el) => {
  if (amenities[el]) {
    amenitiesCn.push(translate[el]);
  }
});

/*
[
  'wifi',     '迷你吧',
  '電視',     '冷氣',
  '冰箱',     '沙發',
  '景觀',     '禁止吸菸',
  '適合兒童', '可帶寵物'
]
*/
餅乾 iT邦新手 4 級 ‧ 2020-08-25 15:49:20 檢舉

這個方法可以~~~太感謝了/images/emoticon/emoticon34.gif
多學了一招 哈哈哈

我改成了這樣~/images/emoticon/emoticon12.gif

roomAmenities() {
    let amenities = [];
    if (this.room.amenities) {
      const translate = {
        "Wi-Fi": "wifi",
        Breakfast: "早餐",
        "Mini-Bar": "迷你吧",
        "Room-Service": "客房服務",
        Television: "電視",
        "Air-Conditioner": "冷氣",
        Refrigerator: "冰箱",
        Sofa: "沙發",
        "Great-View": "景觀",
        "Smoke-Free": "禁止吸菸",
        "Child-Friendly": "適合兒童",
        "Pet-Friendly": "可帶寵物",
      };
      Object.keys(this.room.amenities).forEach((el) => {
        if (this.room.amenities[el]) {
          amenities.push(` ${translate[el]} `);
        }
      });
    }
    return amenities.toString();
  },
},

/images/emoticon/emoticon37.gif

我要留言

立即登入留言