首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >动手练一练,做一个响应式的后台管理面板

动手练一练,做一个响应式的后台管理面板

作者头像
前端达人
发布2020-03-16 18:47:19
1.2K0
发布2020-03-16 18:47:19
举报
文章被收录于专栏:前端达人前端达人

作为一名前端开发者,我们或多或少都会接触后台管理系统的制作,你是否会亲自纯手工制作做还是从网上找源码改一个呢?今天我们将从零开始纯手工制作一个后台管理面板的首页,通过这个案例你将会学习到如何制作一个响应式后台管理页面的思路,本篇文章内容比较长,请大家多多包涵,希望你能看下去,???。

这篇文章的内容是基于我阅读国外一篇博文内容的整理,并亲自实践无误,内容非完全直接翻译,由于水平有限,难免有些疏漏,欢迎大家指正

一、 首先明确下界面需求

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 非直译

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-03-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端达人 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、 首先明确下界面需求
  • 二、接下来思考一下,如何分解制作需求
  • 三、首先建立基本HTML结构
  • 四、编写基本的CSS样式
  • 五、定义面板内容样式
  • 六、处理左边菜单的折叠
  • 七、处理小屏幕响应式样式问题
  • 八、处理菜单打开的交互
  • 九、最终完成的代码
  • 小节
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档