嗨一大家,記得之前我們在屬性綁定章節,有講到 CSS 樣式可以使用 v-bind
屬性綁定樣式嗎~
但官方文件後來卻提到了:
但是,在處理比較複雜的綁定時,通過拼接生成字符串是麻煩且易出錯的。因此,Vue 專門為 class 和 style 的 v-bind 用法提供了特殊的功能增強。除了字符串外,表達式的值也可以是對象或數組。
看起來是因為字串容易凸槌,所以專門為 CSS 樣式提供了「陣列」及「物件」的綁定方式。
我們先今天來看看 class
的綁定方式吧~
v-bind:class=""
簡寫
:class=""
屬性綁定的特點就是「響應性」,當綁定的數據 ""
中的值改變時,Vue 就會負責處理所有的 UI 更新。
""
中定義一個物件 {}
。
其 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>
isActive
值若設為假值,active
這個 class
將不會被渲染上去:
<script setup>
import { ref } from "vue";
const isActive = ref(false);
</script>
將 class
屬性綁定為「物件」後,可以更靈活的實現控制多個 class
的需求。
我們可以透過以下方式操作物件值:
computed
:class
指令可與「一般」的 class
屬性綁定共存喔。
接下來的範例,將會以這個需求為假設,去使用不同方式達成~
畫面上有這些元素:
- 正方形
- 按鈕
- 圓形(點選按鈕後才出現)
點選 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>
:
isSquare
使用 ref
綁定,設置值為 true
。isCircle
使用 ref
綁定,設置值為 false
。changeColor
函式,將 isCircle
的值,設為 true
(isCircle.value
做的是對 RefImpl
物件取值)。<template>
<h3 class="static" :class="{ square: isSquare, circle: isCircle }"></h3>
<br />
<button @click="changeColor">點我變圓形</button>
</template>
模板中:
class
樣式 static
。:class="{ square: isSquare, circle: isCircle }"
:""
中綁定物件,並使用「多個鍵值組」的方式綁定 square: isSquare
和 circle: isCircle
的 class
狀態。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>
也看一下我們為 square
和 circle
兩個 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>
我們需要注意以下部分:
reactive
包裹一個物件,在物件中定義要綁定的 class
屬性和值(也就是把在 ""
的 多個鍵值組 包起來)。changeColor
函式更改 circle: isCircle
的值方式,需要調整:透過取得 shape
物件中的 circle
屬性,做更改。<template>
中 <h3 class="static" :class="shape"></h3>
的 class
指令直接綁定為 shape
物件。會是看到同樣的結果!
複習一下 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>
shapeType
為:ref
狀態 "square"
(預設圖形為正方形)。classObj
變數為 computed
物件,其中有:square
屬性:值為 shapeType.value === "square"
circle
屬性:值為 shapeType.value === "circle
changeShape
函式:shapeType.value
的值。shapeType.value = shapeType.value === "square" ? "circle" : "square";
中會判斷 shapeType.value === "square"
為 true
/false
,再將 shapeType.value
指定為 "circle"
/"square"
。shapeType.value
是 "square"
,將會重新賦值為 "circle"
。):class
指令綁定為 classObj
物件。<button>
綁定 @click
事件,執行 changeShape
這個表達式。腦中模擬一下,預想,我們會因為以下步驟,達成需求情境:
shapeType
預設是 square
,一開始圖形會是正方形。changeShape
會 將 shapeType.value
改為"circle"
。ref()
中的值會更新為 "circle"
。classObj
是 computed
屬性,它會重新計算,此時將渲染出 "circle"
這個 class
。看一下瀏覽器上呈現的結果:
補上 console.log
來印出 按下按鈕後,物件內的 _value
:
function changeShape() {
shapeType.value = shapeType.value === "square" ? "circle" : "square";
console.log(`變形了`, shapeType);
}
console.log(`第一次`, shapeType);
再觀察一下!
""
中定義一個陣列 []
。
: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
。isCircle
為 false
,特別注意,這個值會被轉為空字串 ""
,將不會渲染。isCircle
的值會改為 "circle"
才會渲染。這邊可以注意一下和「綁定物件」的區別,在這邊如果我們定義:在點了按鈕後,將 isCircle
更改為 true
:
const isSquare = ref("square");
const isCircle = ref(false);
function changeColor() {
// 錯誤示範
isCircle.value = true;
console.log(isCircle.value);
}
是不會渲染的!
原因在於,陣列的元素並非完全由真假值控制動態切換,而是直接對應到特定的 class
。
即使陣列元素是預期接受 class
名稱,但若是綁定了 JS 定義中的假值:false
、null
、undefined
、0
和 ""
,它們都會被視為不渲染該該元素。
當我們想把 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
囉!
https://github.com/Jamixcs/2024iThome-jamixcs/tree/main/src/components/day17