iT邦幫忙

2022 iThome 鐵人賽

DAY 11
0
自我挑戰組

清空我的最愛之前端筆記系列 第 11

[ Day 11 ] [ JS ] 使用 JavaScript 操作 Pseudo-elements 偽元素

  • 分享至 

  • xImage
  •  

今天是第 11 天,想跟大家分享的是使用 JavaScript 來操作偽元素。由於偽元素是不存在 DOM 裡,基本上是不能透過正規 JavaScript 方法來操作,但是神通廣大的 JavaScript 仍然還是有別的方法可以辦到。不過偽元素終究不是真正的元素,所以如果可以,還是建議不要使用喔 ~~

讀取偽元素屬性的值

先介紹 Window 物件的 window.getComputedStyle() 方法,它可以用來讀取 HTML 元素的 CSS 屬性與值,所以偽元素也適用。

語法

window.getComputedStyle(element, pseudoElement)

會 return CSSStyleDeclaration Object,CSSStyleDeclaration Object 可以使用 getPropertyValue() 或是點記法 (dot notation) 取屬性的值

Example 1

// HTML
<div class="example1">
  <div id="pri-text1">I am div element.</div>
  <div id="render-text1"></div>
  <div id="render-text2"></div>
</div>
// CSS
#pri-text1::before {
  content: "我是偽元素的 content";
  background-color: yellow;
}

我想要在 <div id="render-text1"></div> ,顯示偽元素 content 的值,
並在 <div id="render-text2"></div> 顯示偽元素 color 的值。

首先,先使用 window.getComputedStyle(priText1, "::before") 取得 CSSStyleDeclaration Object。
再來,第二、三行與第四、五行分別使用點記法 (dot notation)與 getPropertyValue() 取得屬性值。

// JS
const priText1 = document.getElementById("pri-text1");
const renderText1 = document.getElementById("render-text1");
const renderText2 = document.getElementById("render-text2");
const cssObj = window.getComputedStyle(priText1, "::before");

renderText1.innerHTML = cssObj.content + "<br>" + cssObj.backgroundColor;

renderText2.innerHTML =
  cssObj.getPropertyValue("content") +
  "<br>" +
  cssObj.getPropertyValue("background-color");

由下圖可以觀察到,第二、四行有取得 content 的值,第三、五行有取得背景顏色的 rgb 數值。

https://ithelp.ithome.com.tw/upload/images/20220925/20152534mig6WzxMTd.png

修改偽元素屬性的值

有兩種方法

  • CSSStyleSheet 物件 + insertRule
  • <head> 插入 <style> 內部樣式

Example 2

一樣先在 <div> 增加 ::before,content 的內容文字為藍色。

// HTML
<div id="pri-text2">I am div element.</div>
// CSS
#pri-text2::before {
  content: "我是偽元素的 content";
  color: blue;
}

https://ithelp.ithome.com.tw/upload/images/20220925/20152534wHBevZaoFo.png

在 CSSStyleSheet 物件,並使用其 insertRule 修改樣式。
要注意的是,新樣式的選擇器的 CSS 優先權要比原來的還高,才會覆蓋掉。

// JS
const priText2 = document.getElementById("pri-text2");

// -- div#pri-text2 比 #pri-text2 的 CSS 優先權還要高
document.styleSheets[0].insertRule("div#pri-text2::before { color: green }", 0);

https://ithelp.ithome.com.tw/upload/images/20220925/20152534mmlnmOdRV5.png

上圖可以看到,偽元素的文字顏色如預期變成綠色。

Example 3

與 example2 預設一樣。
不同的是,在 <head> 插入 <style> 內部樣式來修改。

// JS
const priText3 = document.getElementById("pri-text3");

let style = document.createElement("style");
document.head.appendChild(style);
sheet = style.sheet;
sheet.insertRule("#pri-text3::before { color: purple }");

https://ithelp.ithome.com.tw/upload/images/20220925/20152534y6WKdiHqiv.png

一樣從上圖可以看到,偽元素的文字顏色如預期變成紫色。

修改偽元素的 content 屬性

這個例子,我想要點擊按鈕,來更換喜歡的水果。
先在 CSS 使用 content 的 attr() 來取得 <div>data-text,然後在 JavaScript 使用 setAttribute() 來設定 DOM 事件來更換 data-text

Example 4

// HTML
<div class="example4">
  <div id="pri-text4" data-text="apple">I like</div>
  <button id="btn1">顯示 orange</button>
  <button id="btn2">顯示 banana</button>
</div>
// CSS
#pri-text4::after {
  content: " " attr(data-text) ".";
  color: green;
}

https://ithelp.ithome.com.tw/upload/images/20220925/20152534TG5zK7t2Eg.png

// JS
const priText4 = document.getElementById("pri-text4");
const btn1 = document.getElementById("btn1");
const btn2 = document.getElementById("btn2");

btn1.addEventListener("click", function () {
  priText4.setAttribute("data-text", "orange");
});

btn2.addEventListener("click", function () {
  priText4.setAttribute("data-text", "banana");
});

https://ithelp.ithome.com.tw/upload/images/20220925/20152534BpF06XMGlZ.png
https://ithelp.ithome.com.tw/upload/images/20220925/20152534qosWjIvmxB.png

分別點擊按鈕,都可以成功顯示水果名稱。

Codepen

參考資料:
oxxostudio - CSS 偽元素 ( JavaScript 操控 )
程式前沿 - JS控制偽元素的方法彙總
MDN - CSSStyleSheet.insertRule()
W3schools - Window getComputedStyle()

文章同步更新於 medium


上一篇
[ Day 10 ] [ CSS ] Pseudo-elements 偽元素 (2)
下一篇
[ Day 12 ] [ JS ] Require 與 Import 的區別
系列文
清空我的最愛之前端筆記16
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言