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.模板字符串
关于模板字符串,其实在第一题就有提到,但值得注意的是,在写法上,是使用反引号``包裹字符串,而非'',记录一笔,不能再犯,以防小哥哥再严肃地批评我!