JavaScript 5/30:Flex Panel Gallery即FLEX佈局的圖片庫

ZoeeeZhang發表於2018-04-19

JavaScript30 為Wes Bos推出的一項為期30天的挑戰,旨在幫助人們用純JavaScript來實現效果,初學者若想在JS方面快速精進,不妨一試。本題為第五題。

實現效果

點選任意一張圖片,圖片放大X倍,同時圖片上下兩方飛入文字,再點選已經展開的圖片後,圖片被壓縮,同時頂端和底部的文字飛出。檢視我的程式碼demo

JavaScript 5/30:Flex Panel Gallery即FLEX佈局的圖片庫

頁面基礎佈局

觀察文件初始佈局:在類名為.panels的父元素div之下,有5個類名為.panel的子div,這5個div內均包含3個p標籤。文件內也已提供CSS樣式及動畫,做題者只需稍許補充並新增監聽事件即可。

  <div class="panels">
    <div class="panel panel1">
      <p>Hey</p>
      <p>Let's</p>
      <p>Dance</p>
    </div>
    ......
    <div class="panel panel5">
      <p>Life</p>
      <p>In</p>
      <p>Motion</p>
    </div>
  </div>
複製程式碼

解題思路

CSS部分:

在本章中,大量運用flex佈局知識,如需補課,推薦查閱阮一峰大神的部落格:

  1. 設定父元素也就是最大的容器.panelsdisplay:flex,預設專案沿主軸方向,從左到右排列;
  2. 設定每個子元素即容器成員.paneldisplay:flex,並設定屬性:
    • 設定flex: 1,flexflex-grow, flex-shrinkflex-basis的簡寫;
    • 設定justify-content: center,該屬性規定專案在主軸上的對齊方式,center即沿主軸居中排列。
    • 設定flex-direction: column,該屬性定義主軸的方向(即專案的排列方向),column表示主軸為垂直方向,起點在上沿;
    • 設定align-items: center,即專案在交叉軸上居中對齊。
  3. 設定點選圖片後,文字的移動樣式;
  4. 設定點選圖片後,圖片的flex值。

JS部分:

  1. 獲取所有類名為.panel的元素;
  2. 為其新增click監聽事件,觸發呼叫函式,新增或去除樣式,實現圖片拉伸或壓縮的效果;
  3. 為其新增transitionend監聽事件,觸發呼叫函式,新增或去除樣式,實現頂端及底部文字飛入或飛出效果。

CSS部分程式碼

    html {
      box-sizing: border-box;
      background: #ffc600;
      font-family: 'helvetica neue';
      font-size: 20px;
      font-weight: 200;
    }

    body {
      margin: 0;
    }

    *,
    *:before,
    *:after {
      box-sizing: inherit;
    }

    .panels {
      min-height: 100vh;
      overflow: hidden;/*內容溢位元素框時,內容會被修剪,並且其餘內容不可見 */
      display: flex;
    }

    .panel {
      background: #6B0F9C;
      box-shadow: inset 0 0 0 5px rgba(255, 255, 255, 0.1);
      color: white;
      text-align: center;
      align-items: center;
      /* Safari transitionend event.propertyName === flex */
      /* Chrome + FF transitionend event.propertyName === flex-grow */
      transition: font-size 0.7s cubic-bezier(0.61, -0.19, 0.7, -0.11),
      flex 0.7s cubic-bezier(0.61, -0.19, 0.7, -0.11),
      background 0.2s;
      font-size: 20px;
      background-size: cover;
      background-position: center;
      flex: 1;
      justify-content: center;
      display: flex;
      flex-direction: column;
    }


    .panel1 {background-image: url(https://source.unsplash.com/gYl-UtwNg_I/1500x1500);}
     ......
    .panel5 {background-image: url(https://source.unsplash.com/3MNzGlQM7qs/1500x1500);
    }

    /* Flex Items */

    .panel>* {
      margin: 0;
      width: 100%;
      transition: transform 0.5s;
      flex: 1 0 auto;
      display: flex;
      justify-content: center;
      align-items: center;
    }

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

    .panel p {
      text-transform: uppercase;
      font-family: 'Amatic SC', cursive;
      text-shadow: 0 0 4px rgba(0, 0, 0, 0.72), 0 0 14px rgba(0, 0, 0, 0.45);
      font-size: 2em;
    }

    .panel p:nth-child(2) {
      font-size: 4em;
    }

    .panel.open {
      flex: 5;
      font-size: 40px;
    }
複製程式碼

JavaScript完整程式碼:

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

    function clearOpen() {
      Panels.forEach(panel => panel.classList.remove('open'))
    }

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

    function toggleActive(e) {
      if (e.propertyName.includes('flex')) {
        this.classList.toggle('open-active')
      }
    }

    Panels.forEach(panel => panel.addEventListener('click', toggelOpen));
    Panels.forEach(panel => panel.addEventListener('transitionend', toggleActive));
複製程式碼

知識點

Flex佈局:

採用 Flex 佈局的元素,稱為 Flex 容器。它的所有子元素自動成為容器成員,稱為 Flex 專案。容器預設存在兩根軸:水平的主軸main axis和垂直的交叉軸cross axis

JavaScript 5/30:Flex Panel Gallery即FLEX佈局的圖片庫

Flex容器屬性:
  1. flex-direction屬性決定主軸的方向(即專案的排列方向);
  2. flex-wrap屬性定義,如果一條軸線排不下,如何換行;
  3. flex-flow屬性是flex-direction屬性和flex-wrap屬性的簡寫形式;
  4. justify-content屬性定義了專案在主軸上的對齊方式。
  5. align-items屬性定義專案在交叉軸上如何對齊。
  6. align-content屬性定義了多根軸線的對齊方式。如果專案只有一根軸線,該屬性不起作用。
Flex專案屬性:
  1. order屬性定義專案的排列順序。數值越小,排列越靠前,預設為0。
  2. flex-grow屬性定義專案的放大比例,預設為0,即如果存在剩餘空間,也不放大。
  3. flex-shrink屬性定義了專案的縮小比例,預設為1,即如果空間不足,該專案將縮小。
  4. flex-basis屬性定義了在分配多餘空間之前,專案佔據的主軸空間。
  5. flex屬性是flex-grow, flex-shrinkflex-basis的簡寫,預設值為0 1 auto
  6. align-self屬性允許單個專案有與其他專案不一樣的對齊方式,可覆蓋align-items屬性。
介紹完基礎知識再看本題就清晰很多了,本題巢狀了三個Flex容器,分別為:
  • .panels:使得子元素.panel橫向等分排列;
  • .panel:使得其中的<p>縱向等分排列;
  • p:使得其中的文字垂直水平居中分佈。 不過以上對Flex的介紹還不算詳細,若想深入瞭解,可查閱這裡

translateY

為實現頂端及底部文字飛入飛出的效果,題中使用了一個用法,即transform: translateY,可實現元素在Y軸方向上移動。