iT邦幫忙

2024 iThome 鐵人賽

DAY 17
2
Modern Web

欸你是要進 Vue 了沒?系列 第 17

欸你是要進 Vue 了沒? - Day17:Vue 屬性綁定之 class && style 功能增強系列(class 篇)

  • 分享至 

  • xImage
  •  

嗨一大家,記得之前我們在屬性綁定章節,有講到 CSS 樣式可以使用 v-bind 屬性綁定樣式嗎~

但官方文件後來卻提到了:

但是,在處理比較複雜的綁定時,通過拼接生成字符串是麻煩且易出錯的。因此,Vue 專門為 class 和 style 的 v-bind 用法提供了特殊的功能增強。除了字符串外,表達式的值也可以是對象或數組。

看起來是因為字串容易凸槌,所以專門為 CSS 樣式提供了「陣列」及「物件」的綁定方式。
/images/emoticon/emoticon39.gif

我們先今天來看看 class 的綁定方式吧~

前情提要

語法

v-bind:class=""

簡寫

:class=""

特點

屬性綁定的特點就是「響應性」,當綁定的數據 "" 中的值改變時,Vue 就會負責處理所有的 UI 更新。

class 綁定物件

"" 中定義一個物件 {}
key 為:要綁定的 class 名稱;value 為:值。

:class="{ class 名稱: 值 }"

實現動態切換

設置 value 為真假值,可以實現該 class 是否要被渲染上去。

<div :class="{ active: isActive }"></div>
// 這邊的 active 是自定義的 class 名稱

isActive 值若設為真值,active 這個 class 將會被渲染上去:

<script setup>
import { ref } from "vue";

const isActive = ref(true);
</script>

https://ithelp.ithome.com.tw/upload/images/20240930/20169139NG1Yu2CFZL.png
isActive 值若設為假值,active 這個 class 將不會被渲染上去:

<script setup>
import { ref } from "vue";

const isActive = ref(false);
</script>

https://ithelp.ithome.com.tw/upload/images/20240930/20169139iY0ig8gqK6.png

實現多個 class 操作

class 屬性綁定為「物件」後,可以更靈活的實現控制多個 class 的需求。
我們可以透過以下方式操作物件值:

  1. 多個鍵值組合
  2. 響應式物件
  3. computed

小道消息

:class 指令可與「一般」的 class 屬性綁定共存喔。

範例需求解說

接下來的範例,將會以這個需求為假設,去使用不同方式達成~

畫面上有這些元素:

  1. 正方形
  2. 按鈕
  3. 圓形(點選按鈕後才出現)

點選 2. 後 1. 會變成 3.

我是誰我在哪

先思考一下,為什麼要走到這步?為什麼要用物件綁定 class 屬性?

因為想要達成:動態控制多個 class
也就是想做到:在達到某些操作之後,依賴 Vue 的響應性功能動態更改多個樣式的狀態,並達成介面渲染更新。
因此這邊就會搭配 Vue 的響應式系統去操作哦!

開始!

多個鍵值組合

:class="{ key1: value1, key2: value2 }"
// key 可以有很多組,代表不同的 class 狀態,用逗號 (,) 分隔。

我們可以這樣做:

<script setup>
import { ref } from "vue";

const isSquare = ref(true);
const isCircle = ref(false);
function changeColor() {
  isCircle.value = true;
}
</script>

<template>
  <h3 class="static" :class="{ square: isSquare, circle: isCircle }"></h3>
  <br />
  <button @click="changeColor">點我變圓形</button>
</template>

<style>
.static {
  width: 200px;
  height: 200px;
  border: 2px solid black;
}
.square {
  background-color: rgb(227, 223, 255);
}
.circle {
  background-color: rgb(173, 165, 227);
  border-radius: 50%;
}
</style>

一步一步來解釋~

<script setup>
import { ref } from "vue";

const isSquare = ref(true);
const isCircle = ref(false);
function changeColor() {
  isCircle.value = true;
}
</script>

以上 <script setup>

  1. isSquare 使用 ref 綁定,設置值為 true
  2. isCircle 使用 ref 綁定,設置值為 false
  3. 定義 changeColor 函式,將 isCircle 的值,設為 trueisCircle.value 做的是對 RefImpl 物件取值)。
<template>
  <h3 class="static" :class="{ square: isSquare, circle: isCircle }"></h3>
  <br />
  <button @click="changeColor">點我變圓形</button>
</template>

模板中:

  1. 以一般方式定義 class 樣式 static
  2. :class="{ square: isSquare, circle: isCircle }""" 中綁定物件,並使用「多個鍵值組」的方式綁定 square: isSquarecircle: isCircleclass 狀態。
  3. button 使用 v-on 簡寫綁定 @click 事件,點按鈕會觸發 changeColor 這個表達式。
<style>
.static {
  width: 200px;
  height: 200px;
  border: 2px solid black;
}
.square {
  background-color: rgb(227, 223, 255);
}
.circle {
  background-color: rgb(173, 165, 227);
  border-radius: 50%;
}
</style>

也看一下我們為 squarecircle 兩個 class 定義的樣式。

點選按鈕!
注意看看,瀏覽器上的 class 屬性多了 circle
因為 changeColor 函式執行,將 isCircle 的值設為 true,因此會加上 .circle 這個樣式,就看到設置的背景顏色和圓形啦!~

響應式物件

如果我們將剛剛 {} 中的「兩個鍵值組」包成 reactive 物件呢?
複習!

reactive 的特性是:可讓其中的物件直接具有響應性,當這些屬性的值改變時,依賴於這些屬性的其他響應式系統(如 ref)也會自動更新喔。

直接來實作:

<script setup>
import { reactive, ref } from "vue";

const isSquare = ref(true);
const isCircle = ref(false);
const shape = reactive({
  square: isSquare,
  circle: isCircle,
});
function changeColor() {
  shape.circle = true;
}
</script>

<template>
  <h3 class="static" :class="shape"></h3>
  <br />
  <button @click="changeColor">點我變圓形</button>
</template>

我們需要注意以下部分:

  1. reactive 包裹一個物件,在物件中定義要綁定的 class 屬性和值(也就是把在 "" 的 多個鍵值組 包起來)。
  2. changeColor 函式更改 circle: isCircle 的值方式,需要調整:透過取得 shape 物件中的 circle 屬性,做更改。
  3. <template> <h3 class="static" :class="shape"></h3>class 指令直接綁定為 shape 物件。

會是看到同樣的結果!

computed 屬性

複習一下 computed 的特點,會在「其依賴的數據變化時」自動重新更新。
而官方表示將它綁定於 class 屬性是一個常見且很有用的技巧哦!

我們可以利用 computed 來創造一個「依賴於響應式系統」的物件,這樣當依賴的資料發生變化時,可以自動偵測並渲染相應的 class

如果今天我可愛的客戶想動態切換兩個形狀呢?點按鈕正方形會變圓形,再點一次又變回正方形呢?

開完會 PM 可能會先寫需求變更單。
你老闆可能會說:要多久,他加班可以做完嗎?

我們可以這樣施法:

<script setup>
import { ref, computed } from "vue";

const shapeType = ref("square");

const classObj = computed(() => ({
  square: shapeType.value === "square",
  circle: shapeType.value === "circle",
}));

function changeShape() {
  shapeType.value = shapeType.value === "square" ? "circle" : "square";
}
</script>

<template>
  <h3 class="static" :class="classObj"></h3>
  <br />
  <button @click="changeShape">點我變形</button>
</template>
  1. 定義 shapeType 為:ref 狀態 "square"(預設圖形為正方形)。
  2. 定義 classObj 變數為 computed 物件,其中有:
  • square 屬性:值為 shapeType.value === "square"
  • circle 屬性:值為 shapeType.value === "circle
    兩者屬性值皆為真/假值,負責動態控制是否呈現。
  1. changeShape 函式:
    負責更改 shapeType.value 的值。
    shapeType.value = shapeType.value === "square" ? "circle" : "square"; 中會判斷 shapeType.value === "square"true/false,再將 shapeType.value 指定為 "circle"/"square"
    (例如當下 shapeType.value"square",將會重新賦值為 "circle"。)
  2. :class 指令綁定為 classObj 物件。
  3. <button> 綁定 @click 事件,執行 changeShape 這個表達式。

腦中模擬一下,預想,我們會因為以下步驟,達成需求情境:

  1. shapeType 預設是 square,一開始圖形會是正方形。
  2. 點選按鈕後 changeShape 會 將 shapeType.value 改為"circle"
  • ref() 中的值會更新為 "circle"
  • classObjcomputed 屬性,它會重新計算,此時將渲染出 "circle" 這個 class
  1. 再點選按鈕,就會重複以上步驟的基礎,兩個圖形切換。

看一下瀏覽器上呈現的結果:

補上 console.log 來印出 按下按鈕後,物件內的 _value

function changeShape() {
  shapeType.value = shapeType.value === "square" ? "circle" : "square";
  console.log(`變形了`, shapeType);
}
console.log(`第一次`, shapeType);

再觀察一下!

class 綁定陣列

基本綁定方式

"" 中定義一個陣列 []

:class="[ 陣列元素, 陣列元素 ]"

這邊的陣列元素可以用「響應式狀態」綁定 class 的名稱。

因此我們又可以魔改範例:

<script setup>
import { ref } from "vue";

const isSquare = ref("square");
const isCircle = ref(false);
function changeColor() {
  isCircle.value = "circle";
}
</script>

<template>
  <h3 class="static" :class="[isSquare, isCircle]"></h3>
  <br />
  <button @click="changeColor">點我變圓形</button>
</template>

:class="[isSquare, isCircle] 中:

  • isSquare"square",會渲染對應的這個 class
  • isCirclefalse,特別注意,這個值會被轉為空字串 "",將不會渲染。
  • 而點了按鈕,isCircle 的值會改為 "circle" 才會渲染。

這邊可以注意一下和「綁定物件」的區別,在這邊如果我們定義:在點了按鈕後,將 isCircle 更改為 true

const isSquare = ref("square");
const isCircle = ref(false);
function changeColor() {
  // 錯誤示範
  isCircle.value = true;
  console.log(isCircle.value);
}

是不會渲染的!
原因在於,陣列的元素並非完全由真假值控制動態切換,而是直接對應到特定的 class

即使陣列元素是預期接受 class 名稱,但若是綁定了 JS 定義中的假值:falsenullundefined0"",它們都會被視為不渲染該該元素。

三元表達式

當我們想把 isCircle 的渲染的條件以三元表達式定義,也可以這麼寫:

<h3 class="static" :class="[isSquare, isCircle ? 'circle' : '']"></h3>

陣列中可以放物件

官方文件:然而,這可能在有多個依賴條件的 class 時會有些冗長。因此你也可以在數組中嵌套對象

物件中的鍵值組,可以用真假值或邏輯來控制動態切換。

<h3 class="static" :class="[isSquare, { circle: isCircle }]"></h3>

isSquare:直接放 isSquare 的名稱,會始終渲染對應的 class
isCircle:用布林值來控制是否添加 circle 這個 class

在組件上使用​

官方文件:本節假設你已經有 Vue 組件的知識基礎。如果沒有,你也可以暫時跳過,以後再閱讀。

(我先跳過 XD,之後再回來補齊)
有基礎的大家可以坐火箭飛過去

小結

這邊的範例和實作讓我寫到有點腦袋小爆炸!!
但是也體驗到了如果寫得好,就會很靈活的表現~~~(真是太好了)

明天我們來看下篇 style 囉!
/images/emoticon/emoticon74.gif

範例 code ⬇️

https://github.com/Jamixcs/2024iThome-jamixcs/tree/main/src/components/day17

參考資料


上一篇
欸你是要進 Vue 了沒? - Day16:Vue 的 computed 在算什麼東西
下一篇
欸你是要進 Vue 了沒? - Day18:Vue 屬性綁定之 class && style 功能增強系列(style 篇)
系列文
欸你是要進 Vue 了沒?22
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言