動手練一練,做一個響應式的後台管理面板

  • 2020 年 3 月 16 日
  • 筆記

作為一名前端開發者,我們或多或少都會接觸後台管理系統的製作,你是否會親自純手工製作做還是從網上找源碼改一個呢?今天我們將從零開始純手工製作一個後台管理面板的首頁,通過這個案例你將會學習到如何製作一個響應式後台管理頁面的思路,本篇文章內容比較長,請大家多多包涵,希望你能看下去,???。

這篇文章的內容是基於我閱讀國外一篇博文內容的整理,並親自實踐無誤,內容非完全直接翻譯,由於水平有限,難免有些疏漏,歡迎大家指正

一、 首先明確下介面需求

1、螢幕寬度 >767px 時,介面交互如下影片所示:

http://mpvideo.qpic.cn/0bf2rmaaqaaahmaacfdbkrpfbc6dbcfqacaa.f10002.mp4?dis_k=cc244950af075578f6af33e81dde703b&dis_t=1584355558

介面的菜單可以通過點擊左下角的按鈕進行摺疊,右邊的空白內容,用來示意需要填充的內容。

2、當螢幕寬度 < 767px 時,介面交互如下影片所示:

http://mpvideo.qpic.cn/0bf2yqaaqaaa3aaaec3bknpfbrgdbdcaacaa.f10002.mp4?dis_k=caa21dac873cb664cfc68349062383a0&dis_t=1584355558

由於螢幕寬度有限,菜單被隱藏,通過點擊按鈕展開或隱藏菜單。

二、接下來思考一下,如何分解製作需求

  1. 響應式布局需要用到哪些知識點。
  2. 如何解決菜單左右摺疊的問題。
  3. 如何處理菜單在小屏設備的展示問題。
  4. 如何規劃頁面的布局,建議現在紙上畫出來。

關於響應式需要用到 flexbox 拿到介面需求後,我們做的第一件事,並不是趕緊寫程式碼,而是需要靜下心來分解需求,完成這個需求你需要考慮:flex布局、 grid 布局,rem單位、vw和vh視口單位、媒介查詢等響應式相關的知識點;菜單摺疊的問題,這裡需要通過JS腳本來觸髮菜單文本和logo的隱藏;小屏設備菜單的按鈕,我們默認隱藏在左邊的菜單里,通過媒介查詢器觸發顯示,並需要在按鈕上添加JS事件,觸髮菜單的打開與隱藏。

需求分解完後,我們開始動手製作吧!

三、首先建立基本HTML結構

1、分析完需求後,我們先建立基礎的 HTML 結構,整個頁面布局分為了左右兩大塊,示例程式碼如下:

<svg style="display:none;">...</svg>  <header class="page-header">...</header>  <section class="page-content">...</section>

你可能注意到,我添加了 svg 部分,並且設置了隱藏,這裡我們使用 SVG Sprites(雪碧圖)技術,方便我們在菜單里添加菜單圖標,這裡我從 Envato 網站下載了後台管理相關的圖標,如下圖所示,喜歡的可以在文章下方留言索取。

2、雪碧圖示例程式碼如下,就是一堆SVG圖標的集合,並確保 id 屬性的唯一性,方便後面的程式碼調用:

<svg style="display:none;">    <symbol id="down" viewBox="0 0 16 16">      <polygon points="3.81 4.38 8 8.57 12.19 4.38 13.71 5.91 8 11.62 2.29 5.91 3.81 4.38" />    </symbol>    <symbol id="users" viewBox="0 0 16 16">      <path d="M8,0a8,8,0,1,0,8,8A8,8,0,0,0,8,0ZM8,15a7,7,0,0,1-5.19-2.32,2.71,2.71,0,0,1,1.7-1,13.11,13.11,0,0,0,1.29-.28,2.32,2.32,0,0,0,.94-.34,1.17,1.17,0,0,0-.27-.7h0A3.61,3.61,0,0,1,5.15,7.49,3.18,3.18,0,0,1,8,4.07a3.18,3.18,0,0,1,2.86,3.42,3.6,3.6,0,0,1-1.32,2.88h0a1.13,1.13,0,0,0-.27.69,2.68,2.68,0,0,0,.93.31,10.81,10.81,0,0,0,1.28.23,2.63,2.63,0,0,1,1.78,1A7,7,0,0,1,8,15Z" />    </symbol>      <!-- more symbols here -->  </svg>

3、 Header 部分的程式碼

Header部分程式碼,我們用 nav 標籤包裹 logo 部分、 菜單鏈接部分、同時添加了一個隱藏的菜單按鈕 .toggle-mob-menu(小屏設備才會顯示),手機端設備將會顯示這個按鈕用於 打開/隱藏 菜單。

<header class="page-header">    <nav>      <a href="#0">        <img class="logo" src="logo.svg" alt="forecastr logo">      </a>      <button class="toggle-mob-menu" aria-expanded="false" aria-label="open menu">        <svg width="20" height="20" aria-hidden="true">          <use xlink:href="#down"></use>        </svg>      </button>      <ul class="admin-menu">        <li class="menu-heading">          <h3>Admin</h3>        </li>        <li>          <a href="#0">            <svg>              <use xlink:href="#pages"></use>            </svg>            <span>Pages</span>          </a>        </li>          <!-- more list items here -->          <li>          <button class="collapse-btn" aria-expanded="true" aria-label="collapse menu">            <svg aria-hidden="true">              <use xlink:href="#collapse"></use>            </svg>            <span>Collapse</span>          </button>        </li>      </ul>    </nav>  </header>

上述程式碼有兩點需要注意:

  • 這裡我們使用 use 語法,獲取 svg 雪碧圖上對應的圖標。
  • ARIA 屬性,是網頁無障訪問的屬性,方便讀屏設備理解其用途。

4、接下來編寫 Section 的 HTML 結構

這裡包含兩個Section區域

Section #1

這部分包含兩塊,一個 搜索區域的表單 和 管理員頭像 部分,下圖為 screens (>767px)的情況:

這部分的程式碼如下所示:

<section class="search-and-user">    <form>      <input type="search" placeholder="Search Pages...">      <button type="submit" aria-label="submit form">        <svg aria-hidden="true">          <use xlink:href="#search"></use>        </svg>      </button>    </form>    <div class="admin-profile">      <span class="greeting">...</span>      <div class="notifications">        <span class="badge">...</span>        <svg>          <use xlink:href="#users"></use>        </svg>      </div>    </div>  </section>

Section #2

這部分是首頁的內容部分,主要用來展示一些網頁小部件,這裡用空白的方塊來示意,如下圖所示:

這部分的 HTML 程式碼結構如下所示:

<section class="page-content">    <section class="grid">      <article></article>      <article></article>      <article></article>      <article></article>      <article></article>      <article></article>      <article></article>      <article></article>    </section>  </section>

四、編寫基本的CSS樣式

準備完 HTML 結構後,我們開始創建一些 CSS 的自定義變數和常見的樣式,示例程式碼如下:

:root {    --page-header-bgColor: #242e42;    --page-header-bgColor-hover: #1d2636;    --page-header-txtColor: #dde9f8;    --page-header-headingColor: #7889a4;    --page-header-width: 220px;    --page-content-bgColor: #f0f1f6;    --page-content-txtColor: #171616;    --page-content-blockColor: #fff;    --white: #fff;    --black: #333;    --blue: #00b9eb;    --red: #ec1848;    --border-radius: 4px;    --box-shadow: 0 0 10px -2px rgba(0, 0, 0, 0.075);  }    * {    padding: 0;    margin: 0;    box-sizing: border-box;  }    ul {    list-style: none;  }    a,  button {    color: inherit;  }    a {    text-decoration: none;  }    button {    background: none;    cursor: pointer;  }    input {    -webkit-appearance: none;  }    button,  input {    border: none;  }    svg {    display: block;  }    body {    font: 16px/1.5 "Lato", sans-serif;  }

這裡只粘貼了最基礎的程式碼,大家可以在點擊 閱讀原文 鏈接查看示例和源碼

五、定義面板內容樣式

完成基礎樣式的定以後,我們進入最關鍵的部分,定義面板的樣式 。

1、Header 相關樣式

Headr 部分在大屏設備的情況下,寬度為220px,其高度等於整個視口的高度,如果其內容超過視口的高度,將會出現一個垂直的滾動條。

nav 元素則為 flex 容器,其高度為100%。包含以下三個對象,前面已經提及過,這裡就不多說了,我們直接來看程式碼:

/*CUSTOM VARIABLES HERE*/    .page-header {    position: fixed;    top: 0;    left: 0;    right: 0;    bottom: 0;    overflow: auto;    padding-top: 20px;    width: var(--page-header-width);    color: var(--page-header-txtColor);    background: var(--page-header-bgColor);  }    .page-header nav {    display: flex;    flex-direction: column;    min-height: 100%;  }    .page-header .toggle-mob-menu {    display: none;  }

上述程式碼,我們將菜單固定在左側,如果你不習慣固定模式,希望其隨內容滾動區域而滾動,你可以這麼做:

body {    position: relative;  }    .page-header {    position: absolute;    top: 0;    left: 0;    height: 100%;      /*Comment these styles*/    /*position: fixed;    top: 0;    left: 0;    right: 0;    bottom: 0;    overflow: auto;*/  }

2、菜單鏈接樣式

菜單 <ul> 將會作為 flex容器,以 列布局 的方式進行展示;鏈接 <a> 標籤包含了圖標和菜單文本,這裡將 <a> 標籤作為flex容器,布局方式為 行布局 ,示例程式碼如下:

/*CUSTOM VARIABLES HERE*/    .page-header .admin-menu {    display: flex;    flex-direction: column;    flex-grow: 1;    margin-top: 35px;  }    .page-header .admin-menu li:last-child {    margin-top: auto;    margin-bottom: 20px;  }    .page-header .admin-menu li > * {    width: 100%;    padding: 12px 15px;  }    .page-header .admin-menu a,  .page-header .admin-menu button {    display: flex;    align-items: center;    font-size: 0.9rem;    transition: background 0.2s, color 0.2s;  }    .page-header .admin-menu .menu-heading h3 {    text-transform: uppercase;    letter-spacing: 0.15em;    font-size: 12px;    margin-top: 12px;    color: var(--page-header-headingColor);  }

3、右邊Section區域

上面提及到了面板 .page-content 區域包含了兩個Section—— .search-and-user 和 grid 內容 。這塊區域距離左邊220px,這裡我們使用 width: calc(100% – 220px) 方式進行計算,這裡的220PX的寬度則為左邊菜單header的寬度。這部分的樣式程式碼如下所示:

/*CUSTOM VARIABLES HERE*/    page-content {    position: relative;    left: var(--page-header-width);    width: calc(100% - var(--page-header-width));    min-height: 100vh;    padding: 30px;    color: var(--page-content-txtColor);    background: var(--page-content-bgColor);  }

3.1、定義 .search-and-user 區域的樣式

在 .search-and-user 這個 section 區域里我們包含了 表單搜索 及 .admin-profile 兩部分內容, 這裡我們用了網格布局,表單搜索區域將會佔滿整個剩餘空間,網格之間的距離為50px,元素之間垂直對齊。

表單搜索圖標按則鈕使用絕對定位的方式定位在搜索框的右邊內。

.admin-profile 區域使用 flex 布局,內容垂直居中,頭像右上角的角標使用絕對定位進行處理。

基於以上說明,這部分的樣式程式碼定義如下:

/*CUSTOM VARIABLES HERE*/    .search-and-user {    display: grid;    grid-template-columns: 1fr auto;    grid-column-gap: 50px;    align-items: center;    background: var(--page-content-bgColor);    margin-bottom: 30px;  }    .search-and-user form {    position: relative;  }    .search-and-user form button {    position: absolute;    top: 50%;    right: 15px;    transform: translateY(-50%);  }    .search-and-user .admin-profile {    display: flex;    align-items: center;  }    .search-and-user .admin-profile .notifications {    position: relative;  }    .search-and-user .admin-profile .badge {    display: flex;    align-items: center;    justify-content: center;    position: absolute;    top: -10px;    right: -3px;    width: 18px;    height: 18px;    border-radius: 50%;    font-size: 10px;    color: var(--white);    background: var(--red);  }

3.2、定義 Grid 控制面板的內容區域

這裡我們使用網格布局,每一網格固定高度300PX,網格布局分為兩列,除了第一行和最後一行單獨成行。

基於這些想法,我們的樣式定義如下:

/*CUSTOM VARIABLES HERE*/    .page-content .grid {    display: grid;    grid-template-columns: repeat(2, 1fr);    grid-gap: 30px;  }    .page-content .grid > article {    display: flex;    height: 300px;    background: var(--page-content-blockColor);    border-radius: var(--border-radius);    box-shadow: var(--box-shadow);  }    .page-content .grid > article:first-child,  .page-content .grid > article:last-child {    grid-column: 1 / -1;  }

六、處理左邊菜單的摺疊

當我們每次點擊菜單的 摺疊/展開 按鈕時,菜單將會摺疊, 如下圖所示:

這個介面只會在大屏的狀態下可見,當菜單摺疊時,菜單的寬度將由 220px 變成 40px,菜單的名稱將會隱藏,右邊的 .page-content 區域面積將會變大,我們將其寬度變成 calc(100% – 40px) 即可。這裡需要注意菜單摺疊按鈕的變化,點擊按鈕時將會旋轉180度。

基於以上的說明,首先我們需要在摺疊菜單上添加點擊事件,控制菜單的顯示與隱藏,帶 aria 的屬性主要是為了網頁無障礙屬性使用,最關鍵的程式碼還是toggle方法:

const body = document.body;  const collapseBtn = document.querySelector(".admin-menu button");  const collapsedClass = "collapsed";    collapseBtn.addEventListener("click", function() {    this.getAttribute("aria-expanded") == "true"      ? this.setAttribute("aria-expanded", "false")      : this.setAttribute("aria-expanded", "true");    this.getAttribute("aria-label") == "collapse menu"      ? this.setAttribute("aria-label", "expand menu")      : this.setAttribute("aria-label", "collapse menu");    body.classList.toggle(collapsedClass);  });

關於菜單摺疊的樣式

/*CUSTOM VARIABLES HERE*/    @media screen and (min-width: 768px) {    .collapsed .page-header {      width: 40px;    }      .collapsed .page-header .admin-menu li > * {      padding: 10px;    }      .collapsed .page-header .logo,    .collapsed .page-header .admin-menu span,    .collapsed .page-header .admin-menu .menu-heading {      display: none;    }      .collapsed .page-header .admin-menu svg {      margin-right: 0;    }      .collapsed .page-header .collapse-btn svg {      transform: rotate(180deg);    }      .collapsed .page-content {      left: 40px;      width: calc(100% - 40px);    }  }

處理完摺疊後,由於圖標上的文字被隱藏,我們需要添加一個滑鼠經過事件,在鏈接里添加個title屬性,讓用戶明白菜單的作用,用於顯示菜單的文本資訊,示例程式碼如下:

const body = document.body;  const menuLinks = document.querySelectorAll(".admin-menu a");  const collapsedClass = "collapsed";    for (const link of menuLinks) {    link.addEventListener("mouseenter", function() {      body.classList.contains(collapsedClass) &&      window.matchMedia("(min-width: 768px)").matches        ? this.setAttribute("title", this.textContent)        : this.removeAttribute("title");    });  }

七、處理小螢幕響應式樣式問題

當螢幕< 767px 是,左邊的菜單會隱藏,如下圖所示,通過點擊按鈕的形式打開菜單:

針對這個介面我們需要添加媒介屬性單獨定義相關樣式進行處理:

  • header 和 .page-content 區域設置 position: static 和 width: 100%。
  • 將 nav flex容器的列布局更改為行布局
  • 將一開始出於隱藏狀態的 mobile 菜單按鈕設置成顯示狀態
  • 將導航菜單的位置定位在 mobile 菜單之下,默認設置為隱藏狀態
  • 最下方的摺疊菜單和.greeting元素則設置成隱藏狀態
  • .search-and-user 搜索表單和用戶頭像區域則使用絕對定位的方式放置在 mobile 菜單按鈕的右側

相關的CSS程式碼如下所示:

@media screen and (max-width: 767px) {    .page-header,    .page-content {      position: static;      width: 100%;    }      .page-header nav {      flex-direction: row;    }      .page-header .toggle-mob-menu {      display: block;    }      .page-header .admin-menu {      position: absolute;      left: 98px;      top: 57px;      margin-top: 0;      z-index: 2;      border-radius: var(--border-radius);      background: var(--page-header-bgColor);      visibility: hidden;      opacity: 0;      transform: scale(0.95);      transition: all 0.2s;    }      .page-header .admin-menu li:last-child,    .search-and-user .admin-profile .greeting {      display: none;    }      .search-and-user {      position: absolute;      left: 131px;      top: 10px;      padding: 0;      grid-column-gap: 5px;      width: calc(100% - 141px);      border-radius: var(--border-radius);      background: transparent;    }  }

八、處理菜單打開的交互

如下圖所示,點擊 mobile 按鈕則會展開下拉菜單:

完成這個需求比較簡單,我們先添加一段腳本,用於定義按鈕的點擊事件:

const body = document.body;  const toggleMobileMenu = document.querySelector(".toggle-mob-menu");    toggleMobileMenu.addEventListener("click", function() {    this.getAttribute("aria-expanded") == "true"      ? this.setAttribute("aria-expanded", "false")      : this.setAttribute("aria-expanded", "true");    this.getAttribute("aria-label") == "open menu"      ? this.setAttribute("aria-label", "close menu")      : this.setAttribute("aria-label", "open menu");    body.classList.toggle("mob-menu-opened");  });

aria 屬性則為了方便讀屏設備,屬於網頁無障礙訪問的內容部分

對應相關的 CSS 程式碼如下:

.page-header .toggle-mob-menu svg {    transition: transform 0.2s;  }    .page-header .admin-menu {    transition: all 0.2s;  }    .mob-menu-opened .toggle-mob-menu svg {    transform: rotate(180deg);  }    .mob-menu-opened .page-header .admin-menu {    transform: scale(1);    visibility: visible;    opacity: 1;  }

九、最終完成的程式碼

好了,到這裡程式碼部分已經完成,由於文章篇幅有限,這裡就不貼程式碼了,大家可以點擊 閱讀原文 鏈接在線體驗和查看源碼。

小節

今天的內容有些多,感謝你能耐心看到這裡,可見做一個後台管理介面也不太輕鬆,主要細節問題比較多,因此針對這樣的需求,動手之前一定要先規劃清楚該怎麼做,有哪些細節問題需要處理,不要拿到一個需求沒想清楚就做。今天的例子,還是建議大家自己親手實踐一遍,大家可以點擊 閱讀原文 在線體驗,複製鏈接查看源碼。

如果你喜歡我的分享,麻煩給個關注、點贊加轉發哦,你的支援,就是我分享的動力,後續會持續分享實踐案例,歡迎持續關注。

文章來源: 作者:George Martsoukos 網站:tutsplus 非直譯