【黑师音画帖小白教程】第八讲:联动控制函数如何管理众多子元素的动态变化
第八讲:联动控制函数如何管理众多子元素的动态变化
第七讲我们在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 赋值,取值方法是用基于父元素 mydiv 的 querySelectorAll() 方法,参数是完整的元素对标的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条]