0%

[Vue] 進階指令與模板語法 (上)

了解了 Vue 的基本指令以後,接著繼續來了解指令及模板的進階用法吧!

v-once — 單次綁定

v-textv-once 同時寫在一個 HTML 元素上,如此一來這個元素的內容在第一次寫入完成後,之後就不會再被變動。

雙花括號輸出資料加總

如果 data 中有多個特性的值為數字,可以用雙花括號在 HTML 輸出這些特性作為變數組成的算式,並在畫面上渲染出計算結果;或者也可以將數個字串型別的特性直接在雙花括號中串接,一樣可以渲染出字串連接的結果。

動態操控 disabled 屬性

v-bind 綁定 disabled 屬性與 data 特性,當切換對應的 data 值(值為布林)時,就能隨之切換 HTML 的可用狀態。

動態切換 className 的多種寫法

  • 用物件帶值:在 Vue 基礎概述 (下) 講過,也就是在要切換 className 的 HTML 元素上使用 v-bind 並且值用物件形式帶入,像下面這樣:
    :class="{'要加入的 className': 判斷式}"

  • 用陣列帶值:在 data 創一個空陣列,在要套用 className 的元素上設定 :class="data 陣列名",觸發樣式切換的元素(例如 checkbox)加上 v-model="data 陣列名"value="要切換的 className",這樣如果要啟用 className 就能透過觸發元素將 value 傳進 data 裡的陣列,而如果要拿掉 className 一樣也是透過觸發元素刪掉該陣列中的 value

插入行內樣式 (style)

  • 用物件帶值:要注意 style 樣式屬性的名稱跟 CSS 不太一樣,style 的樣式屬性採用駝峰式命名法。也可以用參數的方式從 data 傳物件到 style 屬性,這樣做的話可以在物件內放入數個特性(樣式)
1
2
3
4
<!-- 基本款 -->
:style="{'樣式屬性': '樣式的值'}"
<!-- 傳參數版 -->
:style="styleObject"
  • 用陣列帶值:陣列元素必須以物件方式寫入;或用參數,可以在陣列內放入數個物件參數。
1
2
3
4
<!-- 基本款 -->
[{'樣式屬性1': '樣式的值1'}, {'樣式屬性2': '樣式的值2'}]
<!-- 傳參數版 -->
[styleObject1, styleObject2]

v-for 使用細節

可以用於疊代 data 中的陣列及物件。

v-for 與 key 屬性

引述自官網:「使用 v-for 渲染的元素列表時,默認使用『就地更新』的策略。如果數據項的順序被改變,Vue 將不會移動 DOM 元素來匹配數據項的順序,而是就地更新每個元素,並且確保它們在每個索引位置正確渲染。」

也就是說,預設狀況下,資料的索引值是固定的,當畫面上資料順序變換時,是將內容進行替換,而不是替換 DOM 元素位置。

如果希望 DOM 元素位置替換呢?在每筆資料上綁定 key 屬性,該屬性必須對應一個唯一值。
參照:官方文件(列表渲染)如何理解vue的key属性

v-for 跟 filter() 連用

來寫一個可以過濾資料的小範例吧!

  1. 結構:
  • data 資料 - arrayData 為一個包含多個物件資料的陣列
  • 負責輸入的 HTML 元素(例如 input text) - 設定 v-model="filterText"(等一下過濾 arrayData 的條件)
  • 負責輸出的 HTML 元素 - 設定 v-for="(item,key) in filterArray"filterArray 初始狀態為空陣列)
  1. methods 新增方法:
1
2
3
4
5
6
7
8
filterData: function(){
var vm = this;
// 用 for loop 時裡面的 this 不是指向 Vue,所以要在外面先定義好 this
vm.filterArray = vm.arrayData.filter(function(item){
return item.name.match(vm.filterText);
// 回傳與輸入文字相符的 name 值
});
}

⚠️ match() 方法:
用於在字串中檢索指定的值,此方法類似 indexOf(),不過它回傳的是指定的值而不是索引值。

  1. 實際運行

v-for 無法運行的狀況

methods 方法中用陣列特性及索引去修改 data 資料是無效的,因為 Vue 無法探測普通的新增屬性。

1
2
3
4
5
6
// 無效的修改方式
this.arrayData.length = 0; // arrayData 的陣列元素依然存在陣列中
this.arrayData[0] = {
name: '阿強',
age: 99
}

正確修改的方式是用 Vue.set() 新增 data 裡沒有的資料,用這個方式才能讓資料保持響應式,帶動 View 正常更新。

Vue.set() 第一個參數是陣列名,第二個參數是陣列元素索引值,第三個是要新增的內容

1
2
3
4
Vue.set(this.arrayData, 0, {
name: '阿強',
age: 99
})

v-for 用於純數字

在 HTML 元素上使用 v-for="item in 10",並在標籤內用雙花括號包住 item 就能渲染出 1 到 10 的數字。

v-for 用於 <template>

<template> 使用 v-for,可以讓內部的子元素以群組的方式一起疊代。

⚠️ HTML <template> 模板結構:

模板結構中的內容在頁面載入時不受渲染,但可以在運行時使用 JavaScript 實例化。

你可以把 <template> 想成文件裡面,被儲存以待稍後使用的內容片段。在頁面載入時,解析器雖然會處理 <template> 元件的內容,但元素本身並不會被渲染

<template> 內的內容可以用 JavaScript 抓取節點、複製到要插入的 DOM 之下,類似這樣:

1
2
3
4
5
6
7
8
<!-- HTML -->
<!-- 在 template 上面有一些表格元素 -->
<template id="itemRow">
<tr>
<td></td>
<td></td>
</tr>
</template>
1
2
3
4
5
6
7
// JS
var template = document.querySelector('#itemRow');
var td = t.content.querySelectorAll("td");
td[0].textContent = "123";
td[1].textContent = "abc";
var clone = document.importNode(template.content, true);
要插入的DOM.appendChild(clone);

⚠️ 關於 importNode()
importNode()document 物件的方法,功用是把一個節點從另一個文件(document)複製到該文件以便運用。第二個參數(布林值)必填,如果為 true,會複製 importNode() 的所有子節點。

參考資料:HTML5 <template> 标签元素简介<template — HTML> | MDN

v-for 與 v-if 連用

v-forv-if 同時綁在一個元素上時,v-for 先執行,接著才執行 v-if。兩者連用可以從迴圈中過濾出符合條件的結果。不過這樣做會導致畫面上雖然只渲染部分資料,但卻必須巡訪過全部資料才能輸出。

因此 Vue 官方建議在 computed 新增方法,使用 filter() 進行條件過濾,此時 v-for 對應的值要改為 item in 方法名,比較能提升效能。

另外一個提升效能的方法是把 v-if 放在 v-for父層元素,如此一來我們不會再對列表中的每個項目檢查條件,取而代之的是,我們只檢查它一次,且不會在條件不成立的時候運算 v-for

參照:避免 v-if 和 v-for 用在一起(官方文件)


下篇要講的是 v-ifcompuedwatch、表單細節操作、v-on 細節。