Day 5 - Flex Panels Image Gallery

前言

JS 30 是由加拿大的全端工程师 Wes Bos 免费提供的 JavaScript 简单应用课程,课程主打 No FrameworksNo CompilersNo LibrariesNo Boilerplate 在30天的30部教学影片里,建立30个JavaScript的有趣小东西。

另外,Wes Bos 也很无私地在 Github 上公开了所有 JS 30 课程的程序码,有兴趣的话可以去 fork 或下载。


本日目标

利用 flexboxtransition 等 CSS 属性,搭配 JS 监听 transitionendclick 事件,最终实作出一个美观的 Image Gallery。


解析程序码

HTML 部分

由最外层的.panels包覆住内部的5个.panel所形成的一个巢状结构。

<div class="panels">
    <div class="panel panel1">
      <p>Hey</p>
      <p>Let's</p>
      <p>Dance</p>
    </div>
    <div class="panel panel2">
      <p>Give</p>
      <p>Take</p>
      <p>Receive</p>
    </div>
    <div class="panel panel3">
      <p>Experience</p>
      <p>It</p>
      <p>Today</p>
    </div>
    <div class="panel panel4">
      <p>Give</p>
      <p>All</p>
      <p>You can</p>
    </div>
    <div class="panel panel5">
      <p>Life</p>
      <p>In</p>
      <p>Motion</p>
    </div>
</div>

CSS 部分

(仅说明影片中更动的部分)

先将最外层的 .panels 显示类型设定为 flex,它同时也作为一个 flex-container 包覆住内部的五个 flex-items 也就是 .panel

.panels {
      /*其余略过*/
      display: flex;
}

flexflex-growflex-shrinkflex-basis 的简写,只有指定一个值给 flex 时,则代表设定的是 flex-grow,其余属性以预设值带入。

flex-grow 可以指定 flex-container 的剩余空间该如何分配,下面所有的 .panelflex-grow 都是 1,也就是均匀分配剩余空间。

接着,将每一个 .panel 的显示类型都设定为 flex (此时的.panel 对下面的<p></p>来说就是 flex-container) 并将其下的 flex-item 在水平、铅直方向都置中。

最後,设定 flex-directionflex-boxmain-axis 更改为直列。

.panel {
      flex: 1; /*将每个 flex-item 的大小都设为一样并填满*/
      display: flex;  
      justify-content: center; /*在水平方向置中*/
      align-items: center;/*在铅直方向置中*/
      flex-direction: column; 
}

.panel (flex-container)下的 <p></p> (flex-item) 的 flex 属性设定为 1、0、auto,也就是均匀分配 flex-container 的剩余空间、flex-item 长度超过 flex-container 时的收缩量设为 0、flex-itemflex container 的初始大小设为自动(auto)。

接着,也将<p></p>当作是一个 flex-container,设定显示类型为 flex。透过 justify-contentalign-items,将标签内的文字(flex-item) 水平、铅直置中排列。

.panel > * {
      /*其余省略*/
      flex: 1 0 auto;
      display: flex;
      justify-content: center;
      align-items: center;
}

初始状态,分别将在 .panel 上方和下方的 <p></p> 都各上移、下移 100% 以达到隐藏的效果。

.panel > *:first-child{
      transform: translateY(-100%);/*上移*/
}
.panel > *:last-child{
      transform: translateY(100%);/*下移*/
}

接着设定当.panel上有open-active这个 class 时,就将原本隐藏的文字分别下移和上移显示出来。

.panel.open-active > *:first-child{
      transform: translateY(0);
}
.panel.open-active > *:last-child{
      transform: translateY(0);
}

.panel开启时,将内部文字放大为 40px 并将 flex-container 剩余分配的位置变为原来的5倍。

.panel.open {
      font-size: 40px;
      flex: 5;
}
补充资料:

CSS flex 属性
图解 Flexbox 基本属性
FLEXBOX FROGGY-学习 flexbox 的小游戏

JS 部分

取得所有的.panel 并放到 NodeList 'panels' 中。

const panels = document.querySelectorAll('.panel');

panels 中的每一个.panel都注册两个事件监听器,当 clicktransitionend 事件发生时,就分别以 toggleOpentoggleActive 方法进行事件处理。

panels.forEach(panel => panel.addEventListener('click',toggleOpen));
panels.forEach(panel => panel.addEventListener('transitionend',toggleActive));

点击任意一个.paneltoggleOpen() 方法会替触发事件的.panel依照情况的不同,新增或是移除.open 这个 class,若是触发事件的.panel原本没有.open则新增,有的话则移除.open

transitionend 事件发生,toggleActive() 会作出如同 toggleOpen() 一样的判断,决定新增还是移除.open-active这个 class。因为同时会被触发的 transitionend 事件有很多个,我们决定在触发 transitionend 事件的 CSS 属性是 flex 时,才采取处理。为什麽不写 e.propertyName == 'flex-grow' 是因为在 Safari 显示的是 flex 而 Chrome、FireFox 显示的是 flex-grow,为避免这个差异导致错误,我们可以使用 include('flex'),当 propertyName 含有 flex 就进行事件处理。

function toggleOpen(){
    this.classList.toggle('open');
}

function toggleActive(e){
    if(e.propertyName.includes('flex')){
        this.classList.toggle('open-active');
    }
}
补充资料:

Element.classList
String.prototype.includes()

范例网页请按此


<<:  Day5 JavaScript 数据类型

>>:  Day 5 - 虚拟机配置&实体手机测试

[Day20]ISO 27001 附录 A.8 资产管理

好的!【足以维护资讯系统的人才】已经到位啦! 所以就就可以针对资讯资产来做管理! A.8 资产管理 ...

rsync异地备份+排程自动化

今天要接续昨天的排程备份来实作「异地备份」 读者们如果对rsync操作尚不熟悉,可到 昨天 复习喔 ...

成为工具人应有的工具包-19 ProduKey

ProduKey 既然 Forensics 分类的工具都看完了,接下来看看 System Tools...

[Day_12]资料储存容器 - 练习题

今天来为大家介绍资料储存容器的练习题, 过程跟解法可能跟大家不太一样还请大家见谅, 那就让我们开始吧...

day10_MacOs ARM 的软件开发之旅

Mac ARM 作为主要开发机是否可行? 对我来说,完全可以,我有在撰写的语言为 C#, JS, J...