午后・时光

【黑师音画帖小白教程】第二十六讲:学一点点JS(六)JS操作CSS变量

位置: 首页 > 马黑教程[ 发布时间: 2024.8.28  作者: 马黑黑  阅读: 86 ]

第二十六讲:学一点点JS(六)JS操作CSS变量

CSS变量是自定义的CSS属性,它有一个高大上的名称叫级联变量,称之为CSS变量更为通俗易懂。CSS变量主要用来解决两个层面的问题,一是基于CSS代码。考虑一下如下情形:当一大堆的属性设置都会用到相同的值,我们就可以给它们设置一个变量值,各属性通过变量名使用此变量值,日后想修改这一系列属性值时,只需修改被引用的变量值,非常方便。再考虑一下另一种情形:通过作用于特定属性的若干个变量来构建一种页面风格,可以同时创建几个风格,风格切换时只需仅需改变变量名,是不是也很高效?二是基于JS,这是本讲要讨论的课题,当然,正式探讨它之前,我们先来认真梳理一下CSS变量。

任何CSS属性的值都可以使用CSS变量来表示。CSS变量分两个步骤实现:第一步是声明变量被给变量赋值,格式为 --变量名: 变量值,双连接符 -- 是变量名的前缀,其后紧跟一个变量名称,加上小角冒号之后就可以给变量名进行赋值,例如,--color: red;,这里,--color 是变量名,相当于一个CSS属性,实际上就是一个自定义的CSS属性,赋值方法和其他CSS属性的做法一样,都是用键值对的方式完成,完了需要用小角分号 ; 收尾;第二步是在需要用到CSS变量值的属性中引用变量,使用关键字 var 来完成,格式为 属性名: var(--变量名);,例如,color: var(--color); 表示前景色 color 属性使用变量 --color 定义的颜色值。以下示例,通过 --color--bg 声明前景色和背景色变量,再在 colorbackground 属性中分别使用两个变量赋值:

<style>
.cDiv1 {
	--color: green;
	--bg: lightgray;
	width: 400px;
	height: 80px;
	color: var(--color);
	background: var(--bg);
	padding: 10px;
}
</style>

<div class="cDiv1">通过CSS变量设置元素的前景色和背景色</div>

这样,动态修改盒子的前景色、背景色时,我们可以不用去一一操作元素的对应CSS属性,只需改变对应的CSS变量值就能达到目的,这对大批量动态修改元素的特定属性值特别有用。下面的代码在上述代码基础上使用JS来动态操作盒子的前景色和背景色两个CSS变量,为了便于操作,CSS使用id选择器、盒子使用id标识属性:

<style>
#cDiv2 {
	--color: green;
	--bg: lightgray;
	width: 400px;
	height: 80px;
	color: var(--color);
	background: var(--bg);
	padding: 10px;
}
</style>

<div id="cDiv2">点击本div随机改变前景色和背景色</div>

<script>
/* 函数 :生成两个hsl颜色 */
create2HueColors = () => {
	var a = Math.round(Math.random() * 360); /* 变量 a : 获取 0~360 之间的随机整数 */
	var b = (a + 150) % 360; /* 变量 b :与 a 拉开150度的距离(取360的余数保证hue合理) */
	/* 返回存储两个hsl颜色的对象 */
	return {
		c1: `hsl(${a}, 100%, 50%)`, 
		c2: `hsl(${b}, 100%, 50%)`,
	};
};
/* div盒子点击事件 */
cDiv2.onclick = () => {
	var color = create2HueColors();
	cDiv2.style.setProperty('--color', color.c1);
	cDiv2.style.setProperty('--bg', color.c2);
};
</script>

代码中的函数 create2HueColors() 生成两个色域范围不沾边的色相值以便让前景色和背景色拉开区间,该函数返回一个对象,对象里记录所生成的两组 hsl 颜色,记作 c1 和 c2。div的点击事件是我们要看的重点:首先声明一个变量 color,通过调用函数 create2HueColors() 给它赋值;接着,使用JS内置的 setProperty() 方法改变CSS属性,要改变的是CSS变量 --color 和 --bg,它们的值都是从JS变量 color 中获取,一个是 color.c1,另一个是 color.c2,这是调用事先编写好的生成两个色相值的函数 create2HueColors() 所返回的值。setProperty() 方法我们在上一讲中介绍过,它用来给CSS属性赋值,CSS变量本质上是一个自定义的CSS属性,所以自然而然可以使用它来改变变量值。

我们还可以为上例既有CSS属性如宽高等的属性值设置CSS变量,一切凭需要进行设计。做音画帖最需要的是操纵CSS关键帧动画,当有较多的元素都运行不同的关键帧动画,如何统一管理这些动画的运行与暂停就是我们必须解决的问题,这个时候,CSS变量就能派上用场,我们可以设置一个 --state 变量,用以表示动画运行属性即 animation 属性的运行(running)或暂停(paused)这两种状态,然后根据 --state 属性的上一个属性值来决定下一个属性值,两个值来回轮换,以此达成操控动画的播放与暂停。试看如下例子,演示后可点击div切换动画运行状态:

<style>
#cDiv3 {
	--state: running;
	margin: 30px;
	width: 60px;
	height: 60px;
	background: olive;
	animation: rot 6s linear infinite var(--state);
}
@keyframes rot { to { transform: rotate(360deg); } }
</style>

<div id="cDiv3" title="点击切换动画状态"></div>

<script>
/* div盒子点击事件 */
cDiv3.onclick = () => {
	var currentState = window.getComputedStyle(cDiv3).getPropertyValue('--state');
	cDiv3.style.setProperty('--state', currentState === 'running' ? 'paused' : 'running');
};
</script>

CSS代码的重点是,#cDiv3 选择器通过 animation 属性运行关键帧动画 rot,并使用 --state 变量来控制运行状态,--state 的初始值是 running,这意味着动画一开始就运行。JS代码共两行,第一行是获取当前的 --state 变量值,使用的是JS内置的API接口 window.getComputedStyle(元素),它会返回一系列的值,我们仅取其CSS属性值 getPropertyValue(属性),示例要操作的元素是 cDiv3,要获取的属性值是自定义CSS变量属性 --state;第二行,用 setProperty() 方法给 --state 变量赋值,赋值过程使用三元运算判断当前动画运行状态 currentState 的值,若为 running,则令其改为 paused,反之,令其改为 running,这样,单击元素就可以让div在动画运行状态与暂停状态间来回切换。

通过 window.getComputedStyle(元素).getPropertyValue(属性) 方法获得指定元素的指定属性的值是个聪明的做法,不过在音画帖中,我们通过音频基于JS的 paused 暂停属性来决定关键帧动画、视频等的播放或暂停,这在前面的章节中介绍过,这里再详细讲一讲。以下示例,在上一个示例的基础上,① 加入音频标签,并通过音频标签的 oncanplay 可以播放、onplaying 正在开始播放、onpause 暂停这三个事件一同运行一个预设的自定义函数,以此来管控CSS关键帧动画的运行与暂停所依托的CSS变量 --state 的属性值;② 以div元素的伪元素 ::before 模拟播放器,剥夺宿主元素的点击交互功能,将点击操作权限交由伪元素接管。试看代码和演示效果:

<style>
#cDiv4 {
	--state: running;
	margin: 30px;
	width: 400px;
	height: 200px;
	border: 1px solid gray;
	pointer-events: none; /* 禁用指针交互事件 */
	position: relative;
}
#cDiv4::before {
	content: '';
	position: absolute;
	left: 30px;
	top: 30px;
	width: 60px;
	height: 60px;
	background: olive;
	cursor: pointer; /* 鼠标指针 :手型 */
	pointer-events: auto; /* 接受指针交互事件 */
	animation: rot 6s linear infinite var(--state);
}
@keyframes rot { to { transform: rotate(360deg); } }
</style>

<div id="cDiv4" title="播放/暂停">
	<audio id="aud" src="https://music.163.com/song/media/outer/url?id=1446035057" autoplay loop></audio>
</div>

<script>
//联动控制函数 mState
mState = () => {
	//设置基于cDiv4的 --state 变量值 :如果音频暂停值为 'paused',反之值为 'running'
	cDiv4.style.setProperty('--state', aud.paused ? 'paused' : 'running');
	//设置cDiv4的弹出式标题文本 :用布尔变量变数字去读取数组,后续解释
	cDiv4.title = ['暂停','播放'][+aud.paused];
	//...这里可以加入对视频的控制
};

aud.oncanplay = () => mState(); //音频可以播放时运行联动函数
aud.onplaying = () => mState(); //音频正在开始播放时运行联动函数
aud.onpause = () => mState(); //音频暂停时运行联动函数

//以上三个监听事件可以和在一行写,如下:
//aud.oncanplay = aud.onplaying = aud.onpause = () => mState();

//cDiv4点击事件 :如果音频暂停则播放它,反之暂停它
cDiv4.onclick = () => aud.paused ? aud.play() : aud.pause();
</script>

代码解释:

(一)CSS代码里,pointer-events 属性是指针交互事件属性,值为 none 表示禁用、为 auto 表示可用,这样,宿主元素 cDiv4 不接受指针交互,其下子元素会继承这个属性设置,也都不接受指针交互,包括title、指针样式都会失效,因此,作为子元素的伪元素要设置为接受才具备接受点击等交互操作功能。

(二)JS代码中,伪元素的 title 属性值通过宿主元素 cDiv4 传递,尽管宿主元素因为指针交互功能受禁;CSS变量 --state 属性也是通过宿主元素传递。这里请特别注意,父元素的CSS变量可以传递给子元素,前提是子元素不要设置变量值、只能引用变量。上述CSS代码,伪元素的 animation 属性引用了 --state 变量,var(--state),但没有 --state: running/paused 这样的赋值,声明与赋值只能有父元素完成,否则就无法通过父元素给子元素传递变量值,JS对 --state 属性的操作就作用不到子元素。

(三)说一下数组在联动函数中的应用:cDiv4.title = ['暂停','播放'][+aud.paused]; 这一句,['暂停','播放']是一个数组,共两个数组元素,而 [+aud.paused] 是读取数组的下标,其值为 +aud.paused,aud.paused 是 audio 标签的暂停属性,暂停时为真否则为假,是布尔值,布尔值前面加一个加号 + 变为数值,true 等于1,false 等于0,刚好可以对应我们所设置的数组 ['暂停','播放'],因此弹出式显示出来的title文本符合我们的要求;该句代码也可以使用三元运算语句改写:cDiv4.title = aud.paused ? '播放' : '暂停';

作业:参照本讲最后一个示例,制作一个简单的帖子。要求:① 帖子有背景图、有视频,其中视频设置为圆形、不覆盖整个帖子;② 用伪元素 ::before 和 ::after 做两个音频播放控制器,各自有自己的背景图案,点击任意一个都可以联动控制音乐、CSS动画和视频。

返回目录

前一篇: 【黑师音画帖小白教程】第二十五讲:学一点点JS(五)JS操作CSS属性和HTML属性
下一篇: 【黑师音画帖小白教程】第二十七讲:在帖子中实现LRC歌词同步

发表评论:

       

评论列表 [0条]

Copyright © 2014 All Right Reserved 马黑PHP文章管理整站系统v1.8
联系我们: gxblk@163.com