0%

Vue 全家桶系列 - 古早味事件燉畫面綁定

為了多一點 Vue 的實戰練習,經網路推薦宅幹嘛 Vue 系列,透過 Alex 幽默又生活化的講述,覺得讓這個框架又顯得易學很多,這次就跟著宅幹嘛在 2018 年 IT 鐵人賽 Vue.js 手牽手,一起嗑光全家桶來做一系列的練習。

day4

學習重點

  • 事件綁定。
  • 屬性綁定。
  • 餘數觀念。

畫面結構

上方圖片可以看到畫面有幾樣資訊:

  1. 頁面圖片。
  2. 頁面標題。
  3. 選擇箭頭按鈕。
  4. 排序編號、項目名稱、選單標題。
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
<div id="app">
<div class="container">
<img
src="https://images.unsplash.com/photo-1593642634315-48f5414c3ad9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80"
/>
<h1>Practice Vue With Alex</h1>
</div>

<div class="container">
<div class="option">
<a href="#">
<i class="fas fa-caret-left fa-3x"></i>
</a>
<div class="optionTitle">
<span class="number">1</span>
<span class="type">練習一</span>
<span class="title">選單事件綁定</span>
<a href="#"></a>
</div>
<a href="#">
<i class="fas fa-caret-right fa-3x"></i>
</a>
</div>
</div>
</div>

資料區

下方為準備的資料區域:

  1. title: 預備好的標題字串。
  2. src: 圖片。
  3. 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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
let data = {
title: "Practice Vue With Alex",
src:
"https://images.unsplash.com/photo-1593642634315-48f5414c3ad9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80",
index: 0,
menu: [
{
type: "練習一",
title: "選單事件綁定",
link: "#",
},
{
type: "練習二",
title: "雙向資料表單處理",
link: "#",
},
{
type: "練習三",
title: "使用者輸入呈現",
link: "#",
},
{
type: "練習四",
title: "篩選資料轉換",
link: "#",
},
{
type: "練習五",
title: "互動式資料選單",
link: "#",
},
{
type: "練習六",
title: "CSS + jQuery 動畫",
link: "#",
},
{
type: "練習七",
title: "資料觀測與設定",
link: "#",
},
{
type: "練習八",
title: "家鄉通訊錄 API",
link: "#",
},
{
type: "練習九",
title: "TodoList 實做",
link: "#",
},
],
};

雙向綁定做出標題與圖片

  1. 就用雙括號將標題的字串用 Vue 全家桶系列 - 古早味事件燉畫面綁定 帶入 templete 中。
  2. 使用屬性綁定圖片 :src="src"。即完成綁定,等等加上 Vue 實體就會正確顯示在畫面上。
1
2
3
4
<div class="container">
<img :src="src" />
<h1>{{title}}</h1>
</div>

資料起始點設定

因為目前資料中有十筆資料,但正常來說畫面顯示應該只有一筆,所以在資料中的起始點多給一個屬性 index,其值為 0 ,代表我一開始要從第一筆顯示。

1
2
3
4
5
6
7
8
9
let data = {
title: "Practice Vue With Alex",
src:
"https://images.unsplash.com/photo-1593642634315-48f5414c3ad9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80",
index: 0, //從第 0 筆開始
menu: [
...資料部分略...
],
};

用 Vue 把畫面與資料連起來

有畫面也有資料了,中間的媒介就是 Vue 了,如果用這樣就更好理解。
再來就是建立 Vue 的實體,並把畫面與資料先建立好。

Vue

1
2
3
4
let vm=new Vue({
el: "#app",
data: data,
})

把剩下的畫面的資料也綁好,如下:

HTML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div class="option">
<a href="#">
<i class="fas fa-caret-left fa-3x"></i>
</a>
<div class="optionTitle">
<span class="number">{{index+1 }}</span>
<span class="type">{{menu[index].type}}</span>
<span class="title">{{menu[index].title}}</span>
<a :href="menu[index].link"></a>
</div>
<a href="#">
<i class="fas fa-caret-right fa-3x"></i>
</a>
</div>

點擊事件

在要點擊的按鈕上加 v-on 事件,並且給予對應的 methods,其事件名稱為 changePage(),因為會有往前跟往後,所以參數就給予 -11

html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div class="option">
<a href="#" @click.prevent="changePage(-1)">
<i class="fas fa-caret-left fa-3x"></i>
</a>
<div class="optionTitle">
<span class="number">{{index+1 }}</span>
<span class="type">{{menu[index].type}}</span>
<span class="title">{{menu[index].title}}</span>
<a :href="menu[index].link"></a>
</div>
<a href="#" @click.prevent="changePage(1)">
<i class="fas fa-caret-right fa-3x"></i>
</a>
</div>

vue

因為在前面事件有帶入參數,所以在方法中也給予一個對應的參數名稱,其名稱可自訂。

  • Vue 的 index 做加總。

    this 在 vue 中已被包裝指向 vue 本身,所以不會在指到 window 物件。

  • 判斷,如果此 index 小於 0 ,則 index 就為第一筆。
  • 或是此 index 大於 9,則此 index 就會是 9。因為陣列排序從 0 開始,所以資料長度要 -1。簡單說就是自己等於自己。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
var vm = new Vue({
el: "#app",
data: data,
methods: {
changePage(change) {
this.index += change;
if (this.index < 0) {
this.index = 0;
} else if (this.index > menu.length - 1) {
this.index = change - 1;
}
},
},
});

但有趣的可以使用餘數的觀念,就會變成下方寫法。

1
this.index = (this.index + change + this.menu.length) % this.menu.length;

什麼是餘數

這是一個很不錯的技巧,數學極爛的我真是覺得小時候應該多熟悉點基本數學觀念,但餘數這個還可以,舉例:

20 / 3=182
39/5=74

這是國小除法應該會教到,那這有什麼關係,以上兩個規則會發現,
3 的餘數為 0、1、2。
5 的餘數為 0、1、2、3、4。

由此可知,陣列的數量與餘數的數量相同,如果把數字帶入下方公式就會很明顯得到結果。

目前資料有 10 筆資料,所以:

this.index = 0, 陣列起始為 0
change = 1 or -1
this.menu.length = 10

1
this.index = (this.index + change + this.menu.length) % this.menu.length;

但這邊為什麼要加上 this.menu.length 呢? 如果不帶陣列長度的話會變這樣:

加號的話,(0 +1) %10 會餘 1,加號沒什問題。

但如果是帶 -1 的時候會變 (0 -1 )%10 ,餘數會變 -1,然後就壞掉了。

所以加上陣列長度是確保加總值會維持為真值,也就是正值,就不會壞掉了。

加號:(0 +1+10) %101
減號:(0 -1+10) %109

這招好強啊!!

是用於圖片輪播或是循環選單,而且可以一行抵六行,更簡潔的寫法!

寫到這邊基本上功能都已經完成且可以正常運作。

優化程式碼

為了讓程式碼更好閱讀,可以把重複出現的程式碼使用 computed 屬性統一整理,就把剛剛重複出現的兩個程式碼整理好,

computed

1
2
3
4
5
6
7
8
9
computed: {
//重複的變數
today() {
return this.menu[this.index];
},
total() {
return this.menu.length;
},
},

最後再把該 this.menu[this.index]this.menu.length 替換成這兩個方法即可。

當第一跟最後的隱藏箭頭圖示

為了讓使用者更合理使用介面,當資料選到第一項與最後一項的時候,要隱藏左邊跟右邊的箭頭。

這時使用 v-if 判斷箭頭的條件。
左邊箭頭

1
2
3
4
5
<!-- 若不是第一天就顯示 -->
<!-- index != 0 -->
<a v-if="index > 0" href="#" @click.prevent="changePage(-1) ">
<i class="fas fa-caret-left fa-3x"></i>
</a>

右邊箭頭

1
2
3
4
5
<!-- 若不是最後一天就顯示 -->
<!-- index != this.menu.length -->
<a v-if="index < total -1" href="#" @click.prevent="changePage(1)">
<i class="fas fa-caret-right fa-3x"></i>
</a>

這樣在選到第一個跟最後一個的時候,就會隱藏起頭與最後的箭頭了!

最後程式碼可以看 CodePen

參考資料

開胃餐點 - 古早味事件燉畫面綁定