iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 3
0
自我挑戰組

JavaScript 30 挑戰日誌系列 第 3

Day 03:操控 CSS 變數

  • 分享至 

  • xImage
  •  

作品 Demo 連結: 傳送門

作品目標:透過 input 調整 CSS 變數、重新渲染畫面
難易度:★★☆☆☆

HTML

<h2>Update CSS Variables with <span class='hl'>JS</span></h2>

<div class="controls">
    <label for="spacing">Spacing:</label>
    <input id="spacing" type="range" name="spacing" min="10" max="200" value="10" data-sizing="px">

    <label for="blur">Blur:</label>
    <input id="blur" type="range" name="blur" min="0" max="25" value="10" data-sizing="px">

    <label for="base">Base Color</label>
    <input id="base" type="color" name="base" value="#ffc600">
</div>

<img src="https://source.unsplash.com/7bwQXzbF6KE/800x500">

CSS

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

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

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

平常是使用 SCSS 的我第一次聽到 CSS 早已有內建變數還蠻 Shock 的!
CSS 所有的變數都必須儲存在 :root 的 Scope 內
宣告的方法是在名稱加上前綴 double dash --

而引用的方法就是在要放入變數的地方寫入 var(variableName)
非常的簡單!
(雖然我還是會繼續用更方便的 SCSS 就是了... 呵呵... ^^"

接下來我們就進入正式的 原生JavaScript 吧!

【第一步:選取將使用到的目標】

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

在這裡我們使用選取器先取得所有的 input 元素。

因為作者都是使用 ES6+ 的語法,所以決定從今天開始也跟進
畢竟也是未來的趨勢!

ES6+ 的變數宣告有三種
1. const
2. let
3. var

const - 宣告出來的變數是 不可變動

const 的作用範圍為 全域(但不會是 window 的屬性) 或是 區塊
你無法給 const 重新指派,否則 console 會報錯
但如果內容物為 物件 的話,改變物件內的 key/value 是合法的呦!

let - 內容物是可以變更的

let 的作用範圍為 所在的區塊,以及該區塊包含的子區塊

var 則是跟 ES5 是相同的東西

var 的作用範圍為 全域(window 的屬性) 或是 整個 function
但是如果都用 ES6+ 的寫法,則是強烈建議不要使用此方法
關於 ES6 的宣告可以參考這篇文章的詳細介紹:傳送門

【第二步:事件綁定】

inputs.forEach(input => input.addEventListener('change', inputHandler));
inputs.forEach(input => input.addEventListener('mousemove', inputHandler));

在此我們第一個綁定的是 change 事件
也就是在 input 數值確認改變之後,即執行後方的函數

那麼為什麼我們還需要再綁定一個 mousemove 事件呢?
那是因為 change 只有在"確認"要改變的值才會觸發
在我們這個地方的意思就是 當你拖拉 range input 時候並不會有任何反應
只有在你滑鼠左鍵放掉時才會觸發

但我們希望拖拉時就可以動態改變,
因此才再次加上了 mousemove 的事件

在此我們也再次使用到了 ES6+ 的新東西: 箭頭函數
如果轉譯為 ES5 的語法的話會如下

inputs.forEach(function(input){
    input.addEventListener('change', inputHandler)
});

箭頭函數前方的 input 為參數,
在 forEach 當中代表的是當下的 Element

參數的寫法會有三種狀況:
1. 沒有參數時: () => {}
2. 一個參數時可省略小括弧: parameterName => {}
3. 兩個(含)以上的參數時: (a, b) => {}

相關詳細說明請參考此處的文章: 傳送門

【第三步:撰寫 input 的 handler】

// HTML 內的 input 參考
// <input id="spacing" type="range" name="spacing" min="10" max="200" value="10" data-sizing="px">
// <input id="blur" type="range" name="blur" min="0" max="25" value="10" data-sizing="px">
// <input id="base" type="color" name="base" value="#ffc600">

function inputHandler(){
  let suffix = this.dataset.sizing || '';
  document.documentElement.style.setProperty('--' + this.name, this.value + suffix);
}

當我們 console 出 input 的數值
會發現只有純數值、沒有單位,導致無法使用
所以我們就要使用之前學過的自定義屬性 data-* 來自動加上單位

因為我們並不是每個 input 都有 data-sizing 屬性,
所以需要使用 this.dataset.sizing || '' 來為當前的 input 取值並指定給 suffix 變數,
避免 suffix 成為 undefined 狀態造成程式錯誤。

最後我們來把從 input 取得的數值傳到我們的根元素 <html> 上
document.documentElement == <html>

然後在其上使用 .style.setProperty 設置一個 style 的屬性

'--' + this.name, this.value + suffix

'--' 為 CSS 變數的前綴詞
this.name 為取得當前 input 的 name 屬性(可參考 HTML)
this.value 為取得當前 input 更動後的值
最後再加上後綴詞 suffix 變數(可能是 px 或是 空字串)
就完成囉!!

透過開發者工具可以看見 <html> 內的 style 會隨著你 input 的改變而跟著變動,
改變 CSS 變數後進而重新渲染整個畫面,大功告成!!

LEVEL UP!! (灑花


上一篇
Day 02:時鐘
下一篇
Day 04:陣列習題 (1)
系列文
JavaScript 30 挑戰日誌8
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言