JavaScript30 為Wes Bos推出的一項為期30天的挑戰,旨在幫助人們用純JavaScript來實現效果,初學者若想在JS方面快速精進,不妨一試。本題為第三題。
實現效果
本題當實現這樣的效果,利用JavaScript及CSS3來改變CSS的值,使得拖動滑塊及選中顏色時,可以實時調整圖片的內邊距(padding
)、模糊度(blur
)及背景顏色(background
),同時標題中JS二字的顏色也隨之更改。
頁面基礎佈局
<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="DSC01672.jpg">
複製程式碼
解題思路有兩種
一、
- 獲取對應
input
元素; - 建立
changeImg
動作,獲取對應input
元素的value
值,並賦值給圖片的內邊距(padding
)、模糊度(blur
)及背景顏色(background
); - 為每個
input
元素新增監聽事件,當發生change或是mouseover動作時,觸發changeImg
動作,即時改變顏色或者滑塊值;
二、
- CSS部分
- 宣告全域性CSS變數;
- 將變數與對應元素
<img>
、<hl >
關聯;
- JavaScript部分
- 獲取對應
input
元素; - 建立
changeImg
動作,獲取對應input
元素引數名及引數值,賦值給對應CSS變數blur
、spacing
、color
; - 為每個
input
元素新增監聽事件,當發生change或是mouseover動作時,觸發changeImg
動作,即時改變顏色或者滑塊值。
- 獲取對應
第一種方法程式碼如下:
CSS部分程式碼
body {
text-align: center;
background: #193549;
color: white;
font-family: `helvetica neue`, sans-serif;
font-weight: 100;
font-size: 50px;
}
img {
width: 364.8px;
height: 547.2px;
}
.controls {
margin-bottom: 50px;
}
input {
width: 100px;
}
複製程式碼
JavaScript完整程式碼:
const inputs = document.querySelectorAll(`.controls input`);
const spacing = document.querySelector(`#spacing`);
const blur = document.querySelector(`#blur`);
const base = document.querySelector(`#base`);
const image = document.querySelector(`img`);
const h = document.querySelector(`.hl`);
function changeImg() {
image.style.padding = `${spacing.value}px`;
image.style.filter = `blur(${blur.value}px)`;
image.style.background = `${base.value}`;
h.style.color = `${base.value}`;
}
inputs.forEach(input => input.addEventListener(`mouseover`, changeImg));
inputs.forEach(input => input.addEventListener(`change`, changeImg));
複製程式碼
知識點
input
標籤中type="range"
,呈現效果為可左右移動的滑動杆,如下所示:
- 使用
querySelectorAll(`.controls input`)
獲得的inputs
,可返回一個nodelist
,與Array
有所區別,但同樣可以用forEach
遍歷。 CSS
濾鏡filter
,即圖片濾鏡,可調整圖片特效,常見如模糊度blur()
,明暗brightness()
,對比度contrast()
等,可以一次設定一個濾鏡也可以同時設定多個濾鏡,具體參考此處。
第二種方法程式碼如下:
CSS部分程式碼
:root {
--spacing: 10px;
--blur: 10px;
--base: #ffffff;
}
img {
padding: var(--spacing);
filter: blur(var(--blur));
background: var(--base);
width: 364.8px;
height: 547.2px;
}
.hl {
color: var(--base);
}
body {
text-align: center;
background: #193549;
color: white;
font-family: `helvetica neue`, sans-serif;
font-weight: 100;
font-size: 50px;
}
.controls {
margin-bottom: 50px;
}
input {
width: 100px;
}
複製程式碼
JS部分程式碼
const inputs = document.querySelectorAll(`.controls input`);
function changeImg() {
const suffix = this.dataset.sizing || ``;
document.documentElement.style.setProperty(`--${this.name}`, this.value + suffix);
}
inputs.forEach(input => input.addEventListener(`change`, changeImg));
inputs.forEach(input => input.addEventListener(`mouseover`, changeImg));
複製程式碼
解題難點
1.如何處理引數值(前兩個有單位 px 、第三個沒有)
<input type="range" name="blur" min="0" max="25" value="10" data-sizing="px">
<input type="color" name="base" value="#8aa8af">
複製程式碼
可見前兩個input
元素中,已設定data-sizing: "px"
,而只要加上 data-
字首,我們就可以運用dataset
屬性來訪問所有含有data-
的值。在JavaScript
中,可以通過dataset.sizing
來獲取單位。
const suffix = this.dataset.sizing || ``;
複製程式碼
表示,針對前兩個引數值的單位為`px`
,針對顏色為空,以防報錯。
2.如何用 JavaScript 改變 CSS 屬性值?
在JavaScript
中,document.documentElement
即代表文件根元素。所以要改變全域性的 CSS 變數,可以這樣寫:
document.documentElement.style.setProperty(`--${this.name}`, this.value + suffix);
複製程式碼
為了更好理解setProperty
及聯絡解題思路一:
style.setProperty(`padding`, `15px`);
/* 等同於 */
style.padding = `15px`;
複製程式碼
實際應用中,前者的做法會更方便帶引數進去。
知識點
1.CSS變數
方法二的亮點在於建立了CSS變數,實際上,當我們需要構建大型站點時,使用CSS變數,能避免程式碼冗餘,可重複使用,同時,變數名稱本身包含語義資訊,使得CSS檔案更易。具體使用方法如下:
宣告一個全域性CSS 變數:
:root {
--global-color: #666;
--pane-padding: 5px 42px;
}
複製程式碼
使用一個全域性CSS 變數:
.demo{
color: var(--global-color);
}
複製程式碼
其中:root
表示DOM元件的根元素,相當於<html>
,常見於宣告全域性CSS變數。關於CSS變數,若想深入理解,可參閱這裡。
2.模板字串
關於模板字串,其實在第一題就有提到,但值得注意的是,在寫法上,是使用反引號“包裹字串,而非“,記錄一筆,不能再犯,以防小哥哥再嚴肅地批評我!