0%

[Vue] Vue 元件 - 製作空污城市關注網頁

大家還記得元件系列第一篇筆記中,提到的 Demo 嗎?
本篇筆記要帶領大家回顧元件系列中所有的觀念,一步一步拆解這個 Demo 該如何製作!

首先先把成品放在最前面供參:

功能一:用 <select> 篩選特定縣市的測站

HTML

  1. <select>v-model 綁定根實例的 filter 特性
  2. <option>v-for="county in location" + :value="county" 渲染
  3. 元件模板:寫在 .app 外面,用 <script type="text/x-template"> 製作
  4. 元件置入的地方:這次是用 Bootstrap 卡片元件來製作,所以元件模板置入的地方就在 .card-columns 裡面
  5. 元件:用 v-for 渲染所有城市,並且在這裡進行內外層資料傳遞 (外傳內 -> 所有城市資料) (內傳外 -> 關注的城市)

Vue 根實例

  1. AJAX 取得資料,篩選出所有縣市並存到 data
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
var app = new Vue({
el: "#app",
data: {
data: [],
location: [], // 從 AJAX 取回來的資料中篩選不重複的縣市
stared: [],
filter: "" // select 選擇的城市會存在這裡
},
created: function() {
this.getData();
},
methods: {
getData() {
const vm = this;
const api =
"https://cors-anywhere.herokuapp.com/http://opendata2.epa.gov.tw/AQI.json";

// 使用 jQuery ajax
$.get(api).then(function(response) {
vm.data = response;
//console.log(response);
// 取出所有測站的所在縣市
const siteCounty = [];
vm.data.forEach(item => siteCounty.push(item.County));
// 篩選不重複的城市
vm.location = siteCounty.filter(
(element, index, array) => array.indexOf(element) === index
);
// 陣列中第一個符合條件的索引等於本身索引的元素才會被回傳
});
}
},

});
  1. <select> 選出縣市後,顯示符合條件的測站
    computed 中,用 if 判斷 <select> 是否有選擇特定縣市,沒選的話就呈現所有測站資料。以及用 filter() 過濾根實例的 data,篩選出符合條件(縣市)的測站
1
2
3
4
5
6
7
8
9
10
11
12
13
computed: {
filterData: function () {
if (this.filter == '') {
return this.data;
// 如果沒有選擇縣市,就顯示所有測站
}
let filtered = this.data.filter((item) => {
return item.County == this.filter;
// 從所有測站中,找出所在縣市與 select 相同的測站
});
return filtered; // 回傳一個陣列
},
}

Vue 元件

1
2
3
4
Vue.component('card-component', {
props: ['cardData'], // 接收根實例的 data 資料
template: '#cardTemplate',
});

功能二:點擊星星設為關注城市,且設定 localStorage

星星按鈕是位於元件中的元素,所以就要用到 $emit 把內層資料傳到外層。

HTML

  1. 元件模板:星星按鈕為用 <a> 包住的 fontawesome icon,在 <a> 加上 click 事件且綁定至元件的 methods(用 emit 傳遞資料);在 <i> 上用 v-bind 綁定 className 切換(切換星星點擊後的樣式)。
1
2
3
4
<a href="#" class="float-right" @click.prevent="clickStar">
<i :class="starStyle"></i>
</a>
<!--clickStar 是元件的 method, 用 $emit 傳到外層-->
  1. 元件:加入 :star="stared"@change-stared="setStar"。前者是用於 localStorage 紀錄已關注的測站,後者是要配合 emit 從元件傳資料到根實例。
  2. 元件 2:在「關注城市」的欄位下,貼上同一個元件,只需要把 v-for 的來源陣列改成 staredData 就好。

Vue 元件

  1. props 中加入 star,接收根實例的 localStorage 資料。
  2. methods 中寫一個 function,把星星被點擊的測站送進根實例的 methods
1
2
3
4
5
methods: {
clickStar: function(){
this.$emit('change-stared', this.cardData.SiteName);
}
},
  1. computed 中新增 starStyle(),點選的城市不存在關注中時,星星為實心;已存在時,空心。

Vue 根實例

  1. data.stared 中取出 localStorage 紀錄
1
2
stared: JSON.parse(localStorage.getItem('staredSites')) || [],
// staredSites 從 setStar 傳入,會再傳到元件去用
  1. methods 中新增 setStar(),接收 $emit 傳遞被點擊的城市名稱,並判斷是否存在 stared 陣列中
  2. computed 中新增 staredData(),從 data 中找出已存在於 this.stared 的測站

功能三:依據汙染程度呈現不同顏色

在 CSS 中事先寫好不同汙染程度對應的 class,每個 class 都設定不同的背景顏色,等一下要把這些 class 套用到卡片上。

HTML

  1. 元件模板:在 .card 上用 v-bind 切換 className:class="airColor"

Vue 元件

computed 新增 airColor(),用 switch 判斷汙染等級的顏色。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
airColor: function(){
let status = this.cardData.Status;
switch (status) {
case '普通':
return 'status-aqi2';
break;
case '對敏感族群不健康':
return 'status-aqi3';
break;
case '對所有族群不健康':
return 'status-aqi4';
break;
case '非常不健康':
return 'status-aqi5';
break;
case '危害':
return 'status-aqi6';
break;
}
}