Try   HackMD

Day 3:Playing with CSS Variables and JS

竹白記事本,Javascript 30,紀錄。

tags: Javascript 30

實現效果

使用 JavaScript 搭配原生 CSS 變數,製作出一個即時濾鏡效果工具。

可調整模糊、邊框色、內距大小。

重點

  1. CSS Variables
  2. 標題的 JS 顏色也要變化
  3. 定義好得 data-sizing 用來判斷單位

基礎語法

CSS

DOM

說明

1. CSS

必須先宣告全域的 CSS 變數,並套用到對應的頁面元素中(圖片、標題)。

2. CSS Variables 支援度

style 所繼承的 CSSStyleDeclaration 介面,不支援 CSS Variables 的樣式屬性,所以必須使用 setProperty() 來設定樣式屬性。

實作

1. 步驟

Step 1 新增 CSS 變數

:root {
  --base: #ffc600;
  --spacing: 10px;
  --blur: 10px;
}

img {
  padding: var(--spacing);
  background: var(--base);
  filter: blur(var(--blur));
}

.hl {
  color: var(--base);
}

:root 等同 html 選取器。

將資料變數放在 CSS 的優缺點:

  • 減少 JS 放資料的負擔
  • 只修改一處 CSS 變數,所有套用此變數的樣式都會一起變動
  • 寫程式時需要到 CSS 查看變數與修改

Step 2 對所有 input 標籤 註冊監聽事

const input = const inputs = document.querySelectorAll('.controls input');

注意,querySelectorAll 出來的是 NodeList 類陣列,不是陣列,陣列部分的功能它沒有。在 Day 1 中有提到過。

inputs.forEach(function(key) {
  key.addEventListener('change', changeHandler);
});

為每個 input 標籤註冊監聽事件,當 change 事件發生,執行 changeHandler 函式。

由於 change 事件並不即時,滑鼠放開才會執行,所以還需要再加入 mousemove 事件,使拉動滑桿時,也能更新效果。

inputs.forEach(function(key) {
  key.addEventListener('change', changeHandler);
  key.addEventListener('mousemove', changeHandler);
});

Step 3 建立 changeHandler 函式

不使用 CSS 變數的作法:

function changeHandler() {
  const img = document.querySelector('img');
  const hl = document.querySelector('.hl');
  
  switch (this.name) {
    case 'spacing':
      img.style.padding = this.value + 'px';
      break;
    case 'blur':
      img.style.filter = `blur(${this.value}px)`;
      break;
    case 'base':
      img.style.backgroundColor = this.value;
      hl.style.color = this.value;
      break;
  }
}

這樣的缺點是,當有兩處以上需要變動,就要手動增加。

依照題目使用 CSS 變數作法:

document.querySelector('html')
document.querySelector('root')
document.documentElement

這三個是一樣的,依個人喜好選擇。

function changeHandler() {
  const unit = this.dataset.sizing || '';

  document.documentElement.style.setProperty(
    `--${this.name}`, this.value + unit
  );
}

原始碼 HTML 有提供 data-sizing 屬性,是用來判斷要不要加上單位,因此這邊用 dataset 取得。

由於 --變數 是較新的 CSS 屬性 style 不論是 .[] 都不支援,因此這裡用 setProperty 來加上 CSS 屬性。

這邊的 this 指向觸發 changeHandler() 的元素,因此可以獲取該元素的 data-sizingnamevalue 值。

Step End

(function() {

  const inputs = document.querySelectorAll('.controls input');

  function changeHandler() {
    const unit = this.dataset.sizing || '';

    document.documentElement.style.setProperty(
      `--${this.name}`, this.value + unit
    );
  }

  inputs.forEach(function(key) {
    key.addEventListener('change', changeHandler);
    key.addEventListener('mousemove', changeHandler);
  });
})();

2. 進節

改用事件委派

與 Day1 相同,改用事件委派可以減少監聽器。

const inputs = document.querySelector('.controls');

function changeHandler(e) {
  if (e.target.nodeName !== 'INPUT') {
    return;
  }

  const unit = e.target.dataset.sizing || '';

  document.documentElement.style.setProperty(
    `--${e.target.name}`,
    e.target.value + unit
  );
}

inputs.addEventListener('change', changeHandler);
inputs.addEventListener('mousemove', changeHandler);

3. 實作連結