【黑师音画帖小白教程】第八讲:联动控制函数如何管理众多子元素的动态变化

位置: 首页 > 马黑教程
[发布: 2024.8.6  作者: 马黑黑  阅读: 114]

第八讲:联动控制函数如何管理众多子元素的动态变化

第七讲我们在JS代码中创建了一个联动控制函数 mState(),它能有效管理拥有id标识的子元素,使这些子元素的变化能与音频的播放&暂停同步。我们知道,同一个页面元素的id好比人的身份证,是唯一的,当需要控制的子元素非常多,我们一一给它们标注id然后去控制它们会很繁琐、代码也会很冗长。为此,我们需要更好的途径来处理这个问题,这里假设我们的帖子用到两个视频、两张图片做播放器、三张图片做飞鹰,HTML代码如下:

<!-- html 代码 -->
<div id="mydiv">
	<video class="vid" src="视频地址1" autoplay loop muted></vid>
	<video class="vid" src="视频地址1" autoplay loop muted></vid>
	<img class="player" src="图片地址1" alt="" />
	<img class="player" src="图片地址2" alt="" />
	<img class="bird" src="图片地址3" alt="" />
	<img class="bird" src="图片地址5" alt="" />
	<img class="bird" src="图片地址4" alt="" />
</div>

视频与图片标签都是用了class替代了id,共有三类,vid、player、bird,它们对标的CSS选择器大概如下:

/* CSS类选择器 */
.vid {
	/* 视频类选择器代码略 */
}
.player {
	/* 播放器类选择器代码略 */
}
.bird {
	/* 飞鹰类选择器代码略 */
}

CSS代码可能还会更多一些,比如使用伪类选择器 :nth-of-type(序号) 来额外定义个别元素的具体样式如位置、大小等。这不是我们控制众多子元素的重点,重头戏是JS如何拿到它们的操作标识并管控它们。JS有能力拿到任意一个页面中的元素,它内置了很多这类方法,我个人最喜欢的是 querySelectorAll(参数) 方法,它可以基于 document(文档),也可以基于元素(比如子元素的父元素),参数 则可以使用CSS类选择器的完整名称(如 .bird)。例如,针对前面的HTML代码,帖子容器元素 id="mydiv",那么我们可以基于 mydiv 分别查询并拿到到 class="vid/player/bird" 之类的子元素的操作标识:

//JS代码 :拿到拥有 class 属性的子元素的操作标识
var vids = mydiv.querySelectorAll('.vid');
var players = mydiv.querySelectorAll('.player');
var birds = mydiv.querySelectorAll('.bird');

var 是 JS 的声明关键字,var vids 声明一个变量 vids,vids 是我们定义的名字,用复数形式表示这是多个元素的集合,等号后面是给声明的变量 vids 赋值,取值方法是用基于父元素 mydivquerySelectorAll() 方法,参数是完整的元素对标的CSS选择器 .vid,因为这是一个字符串所以用引号包裹起来。其余两个声明与赋值道理与此同,无需赘述。

这样,以视频为例,vids 就是我们操纵所有视频子元素的依据。vids 是视频元素的集合,是多个的,它实际上是一个对象数组,数组就是一类东西的集合,我们要对这个集合进行操作,在JS里拥有多种方法,这里介绍最简洁的 数组.forEach() 方法,forEach() 说的是里面的每一个的意思:

	vids.forEach( vid => aud.paused ? vid.pause() : vid.play() );

vids.forEach( vid => ... ) 意思是,数组 vids(视频集合)里面的每一个 vid(视频个体)要咋样咋样,其中,vid 是我们自己命名的名称,该名称代表将要处理的元素个体标识。接着,我们用箭头函数符号 => 引出函数体,因为是单行所以不要花括号。函数体内容我们应该已经熟悉了,意思是,问:音频是不是处于暂停状态中?答,是的话,vid.pause(),意思是 vid 也暂停;不是的话,vid.play(),意思是,vid 播放。其他两个数组 players 和 birds 也是采用类似的处理方法,不同的是,要使用 setProperty() 方法动态设置CSS关键帧动画动画的运行与暂停状态,后面提供的实例代码会看到。

下面给一个帖子实例代码,按前面的预设,有两个播放器、两个视频、三只飞鹰,这些元素都在帖子中得到同步管控。代码可以在线运行。领会代码时,请特别留意一下伪类选择器 :nth-of-type 与相应HTML标签出现顺序的关系,它是基于 HTML 标签而非 CSS选择器:

<!-- 第一部分 :css代码 -->

<style>
/* 帖子容器id选择器 */
#mydiv {
	position: relative;
	margin: 20px auto;
	width: 800px;
	height: 450px;
	background: url('https://638183.freep.cn/638183/t22/webp/jyiu.webp') no-repeat center/cover;
	overflow: hidden;
}

/* 小播class选择器 */
.player {
	position: absolute;
	bottom: 40px;
	width: 120px;
	height: 120px;
	opacity: .7;
	cursor: pointer;
	animation: rot 8s linear infinite var(--state);
}
.player:nth-of-type(4) { left: 40px; } /* 对标的 img 标签排在帖子中第4位 */
.player:nth-of-type(5) { right: 40px; } /* 对标的 img 标签排在帖子中第5位 */

/* 飞鹰class选择器 */
.bird {
	position: absolute;
	left: -100px;
	top: 10px;
	animation: fly 6s linear infinite var(--state);
}
.bird:nth-of-type(2) { animation-delay: -2s; } /* 对标的 img 标签排在帖子中第2位 :提前2秒执行动画 */
.bird:nth-of-type(3) { animation-delay: -4s; } /* 对标的 img 标签排在帖子中第3位 :提前4秒执行动画 */

/* 视频class选择器 */
.vid {
	position: absolute;
	bottom: 0;
	width: 200px;
	height: 200px;
	object-fit: cover;
	border-radius: 50%;
	pointer-events: none;
	opacity: 1;
	mix-blend-mode: screen;
}
.vid:nth-of-type(1) { left: 0; } /* 对标的 video 标签排在帖子中第1位 */
.vid:nth-of-type(2) { right: 0; } /* 对标的 video 标签排在帖子中第2位 */

@keyframes rot { to { transform: rotate(360deg); } }
@keyframes fly { to { left: 800px; } }
</style>

<!-- 第二部分 :html代码 父元素带8个子元素 -->
<div id="mydiv">
	<audio id="aud" src="https://music.163.com/song/media/outer/url?id=1844994989" autoplay loop></audio>
	<video class="vid" src="https://img.tukuppt.com/video_show/2418175/00/02/20/5b51f631b0f2d.mp4" autoplay loop muted></video>
	<video class="vid" src="https://img.tukuppt.com/video_show/2418175/00/02/20/5b51f631b0f2d.mp4" autoplay loop muted></video>
	<img class="bird" alt="" src="https://638183.freep.cn/638183/t22/gif/ying1.gif" />
	<img class="bird" alt="" src="https://638183.freep.cn/638183/t22/gif/ying1.gif" />
	<img class="bird" alt="" src="https://638183.freep.cn/638183/t22/gif/ying1.gif" />
	<img class="player" alt="" src="https://638183.freep.cn/638183/small/4yc.png" title="播放/暂停" />
	<img class="player" alt="" src="https://638183.freep.cn/638183/small/4yc.png" title="播放/暂停" />
</div>

<!-- 第三部分 :JS代码 -->

<script>
//声明并获取待控制的元素集合变量 : vids 视频、players 小播、birds 飞鹰
var vids = mydiv.querySelectorAll('.vid'),
	players = mydiv.querySelectorAll('.player'),
	birds = mydiv.querySelectorAll('.bird');

//联动控制函数
var mState = () => {
	mydiv.style.setProperty('--state', aud.paused ? 'paused' : 'running');
	vids.forEach(vid => aud.paused ? vid.pause() : vid.play());
	players.forEach(player => player.title = aud.paused ? '播放' : '暂停');
};

//audio空间三个监听事件
aud.oncanplay = aud.onplaying = aud.onpause = () => mState();

//小播点击事件
players.forEach(player => player.onclick = () => aud.paused ? aud.play() : aud.pause());
</script>

帖子内容增多多代码量自然跟着增多,不过只要弄清代码结构、逻辑关系,理解起来不是太难的事情。帖子代码中出现的新知识点均有注释,应花点时间理解消化。帖子实例已属于复杂构成的帖子,但还不算特别复杂,试着想一想:如果需要添加成百上千的子元素,我们也得这样写CSS和HTML代码吗?

返回目录

前一篇: 【黑师音画帖小白教程】第七 讲:加入音、视频及CSS关键帧动画联动控制机制
下一篇: 【黑师音画帖小白教程】第九讲:在帖子中添加大批量的子元素

发表评论:

  
 

评论列表 [0条]

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