前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >动手练一练,做一个现代化、响应式的后台管理首页

动手练一练,做一个现代化、响应式的后台管理首页

原创
作者头像
前端达人
修改2020-03-02 07:24:16
1.1K0
修改2020-03-02 07:24:16
举报
文章被收录于专栏:前端达人前端达人

大家好,今天我们将一起从零开始纯手工建一个后台管理首页。关于后台管理模板,每个公司的要求都不一样,有的能用就行也丑不丑无所谓,或者用个开源模板凑合下就行啦。如果接到这样后台管理需求,我也是从网上下载改改而已,从没想过自己动手建一个。因为从零开始建一个漂亮完善的后台管理模板实在太费功夫了,交互样式的代码量不亚于业务代码的工作量。

曾几何时,我也想动手做一个属于自己的UI框架模板,看了手里现存的源码,最终还是放弃了,做好这个,除了代码量还要有产品化的思维,做好真心不容易。

今天浏览了一篇国外关于如何手工建立一个响应式的后台管理首页的入门文章,在这里分享给大家,本篇文章的例子我亲手实践了一遍,基于自己的理解进行的整理,并非完全直接翻译,希望大家通过这篇文章了解下纯手工建一个响应式后台模板的思路。

废话不多说了,我们开始动手实践吧!

一、 后台管理模板首页需求

1、屏幕宽度 >767px 时,模板如下图所示:

2、点击左下角箭头进行菜单的切换

3、当屏幕宽度 < 767px 时,模板如下图所示:

4、点击左上角的箭头,进行菜单的切换:

二、如何分解这个布局需求呢?

1、如下图所示将整个页面分为两大块,左边的 <header> 部分和右边的 <section> 部分:

2、 <header> 部分将拆分成 logo 部分和 菜单列表,由 <nav> 标签包裹

3、<section> 部分可以分为上下两块,如下图所示:

4、如何处理响应式,这里使用媒介查询属性,当屏幕宽度 >767px,左边的菜单固定在左边,左右布局;当屏幕宽度 < 767px 时,整个网页上下布局,菜单通过图标的形式进行切换显示。

5、关于菜单的折叠和切换,这里我们需要添加少许的JS。

三、首先建立基本HTML结构

1、分析完需求后,我们先建立基础的 HTML 结构,示例代码如下:

代码语言:javascript
复制
<svg style="display:none;">...</svg>
<header class="page-header">...</header>
<section class="page-content">...</section>

你可能注意到,我添加了 svg 部分,并且设置了隐藏,这里我们使用 SVG Sprites(雪碧图)技术,方便我们在菜单里添加菜单图标,这里我从 Envato 网站下载了后台管理相关的图标,如下图所示,喜欢的可以私信我进行获取

2、雪碧图示例代码如下:

代码语言:javascript
复制
<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,手机端设备将会显示这个按钮用于 打开/隐藏 菜单。

代码语言:javascript
复制
<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)的情况:

这部分的代码如下所示:

代码语言:javascript
复制
<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 代码结构如下所示:

代码语言:javascript
复制
<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 的自定义变量和常见的样式,示例代码如下:

代码语言:javascript
复制
: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%。包含以下三个对象,前面已经提及过,这里就不多说了,我们直接来看代码:

代码语言:javascript
复制
/*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;
}

上述代码,我们将菜单固定在左侧,如果你不习惯固定模式,希望其随内容滚动区域而滚动,你可以这么做:

代码语言:javascript
复制
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容器,布局方式为 行布局 ,示例代码如下:

代码语言:javascript
复制
/*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的宽度。这部分的样式代码如下所示:

代码语言:javascript
复制
/*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 布局,内容垂直居中,头像右上角的角标使用绝对定位进行处理。

基于以上说明,这部分的样式代码定义如下:

代码语言:javascript
复制
/*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,网格布局分为两列,除了第一行和最后一行跨列成行。

基于这些想法,我们的样式定义如下:

代码语言:javascript
复制
/*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度。

基于以上的说明,首先我们需要在折叠菜单上添加点击事件,控制菜单的显示与隐藏:

代码语言:javascript
复制
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);
});

对于菜单折叠的样式

代码语言:javascript
复制
/*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属性,让用户明白菜单的作用,用于显示菜单的文本信息,示例代码如下:

代码语言:javascript
复制
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代码如下所示:

代码语言:javascript
复制
@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 按钮则会展开下拉菜单:

完成这个需求比较简单,我们先添加一段脚本,用于定义按钮的点击事件:

代码语言:javascript
复制
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 属性如下:

代码语言:javascript
复制
.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;
}

九、最终完成的代码

好了,到这里代码部分已经完成,贴上完整的代码。

9.1、 CSS代码部分

代码语言:javascript
复制
@import url("https://fonts.googleapis.com/css?family=Lato:400,700&display=swap");
: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;
    -moz-border-radius: 4px;
    --box-shadows: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;
}

.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 .logo{
    display: block;
    max-width: 120px;
    margin: 0 15px;
}
.page-header .toggle-mob-menu{
    display: none;
    margin-left: 5px;
    padding: 4px;
    background-color: var(--page-content-blockColor);
    border-radius: var(--border-radius);
}
.page-header .toggle-mob-menu svg{
    fill: var(--black);
    transition: transform 0.2s;
}

.page-header .admin-menu{
    display: flex;
    flex-direction: column;
    flex-grow: 1;
    margin-top: 35px;
}

.page-header .admin-menu li:nth-last-child(2){
    margin-bottom: 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 .menu-heading h3{
    text-transform: uppercase;
    letter-spacing: 0.15em;
    font-size: 12px;
    margin-top: 12px;
    color: var(--page-header-headingColor);
}
.page-header .admin-menu svg{
    width: 20px;
    height: 20px;
    fill: var(--page-header-txtColor);
    margin-right: 10px;
    transition: fill 0.2s;
}

.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 a:hover,
.page-header .admin-menu a:focus,
.page-header .admin-menu button:hover,
.page-header .admin-menu button:focus{
    background: var(--page-header-bgColor-hover);
    color: var(--blue);
    outline: none;
}
.page-header .admin-menu a:hover svg,
.page-header .admin-menu a:hover svg,
.page-header .admin-menu button:hover svg,
.page-header .admin-menu button:focus svg{
    fill: var(--blue);
}

/* PAGE CONTENT STYLES
–––––––––––––––––––––––––––––––––––––––––––––––––– */
.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);
}

.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 input[type="search"]{
    width: 100%;
    height: 50px;
    font-size: 1.5rem;
    padding-left: 15px;
    background: var(--page-content-blockColor);
    color: var(--white);
    border-radius: var(--border-radius);
    box-shadow: var(--box-shadow);
}
.search-and-user ::placeholder{
    color: var(--page-content-txtColor);
}
.search-and-user form svg{
    width: 26px;
    height: 26px;
    fill: var(--page-content-txtColor);
}
.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 .greeting{
    margin: 0 10px 0 20px;
}
.search-and-user .admin-profile svg{
    width: 30px;
    height: 30px;
}
.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);
}
.page-content .gird{
    display: grid;
    grid-template-columns: repeat(2,1fr);
    grid-gap: 30px;
}
.page-content .gird>article {
    display: flex;
    height: 300px;
    background: var(--page-content-blockColor);
    border-radius: var(--border-radius);
    box-shadow: var(--box-shadows);
}

.page-content .gird > article:first-child,
.page-content .gird > article:last-child{
    grid-column: 1/-1;
}

/* MQ RULES
–––––––––––––––––––––––––––––––––––––––––––––––––– */
@media screen and (max-width: 767px){
   .page-header,
   .page-content{
       position: static;
       width: 100%;
   }
   .page-header {
       padding: 10px;
   }
   .page-header nav{
       flex-direction: row;
   }
   .page-header .logo{
       margin: 0;
       height: 35px;
   }
   .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:nth-last-child(2){
       margin-bottom: 12px;
   }
   .page-header .admin-menu li:last-child,
   .search-and-user .admin-profile .greeting{
       display: none;
   }
   .page-content{
       min-height: 0;
       padding: 10px;
   }
   .page-content .gird{
       grid-gap: 10px;
   }
   .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;
   }
   .search-and-user input[type="search"]{
       font-size: 1rem;
       height: 35px;
   }
   .search-and-user form svg{
       width: 18px;
       height: 18px;
   }
   .search-and-user .admin-profile svg{
       fill: var(--white);
   }
}

@media screen and (max-width: 400px) {
    .page-content .gird>article{
        grid-column: 1/-1;
    }
}

/* BODY CLASSES
–––––––––––––––––––––––––––––––––––––––––––––––––– */
.mob-menu-opened .toggle-mob-menu svg{
    transform: rotate(180deg);
}
.mob-menu-opened .page-header .admin-menu{
    transform:scale(1);
    visibility: visible;
    opacity: 1;
}

@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);
    }
}

/* FOOTER
–––––––––––––––––––––––––––––––––––––––––––––––––– */
.page-footer {
    font-size: 0.85rem;
    text-align: right;
    margin-top: 10px;
}

.page-footer span{
    color: var(--red);
}

9.2、js代码部分

代码语言:javascript
复制
const  body=document.body;
const menuLinks=document.querySelectorAll(".admin-menu a");
const collapseBtn=document.querySelector(".admin-menu .collapse-btn");
const toggleMobileMenu=document.querySelector(".toggle-mob-menu");
const collapsedClass="collapsed";

collapseBtn.addEventListener("click",function () {
    this.getAttribute("aria-expanded") === "true"
    ? this.setAttribute("aria-expend","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)
});

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

for(const link of menuLinks){
    link.addEventListener("mouseenter",function () {
        body.classList.contains(collapsedClass) &&
            window.matchMedia("(min-width:768px)").matches
            ? this.setAttribute("title",this.textContent.trim())
            : this.removeAttribute("title")
    })
}

小节

今天的内容有些多,感谢你能看到这里,可见做一个后台管理界面也不太轻松,主要细节问题比较多,因此针对这样的需求,动手之前一定要先规划清楚该怎么做,不要拿到一个需求没想清楚就做。今天的例子,还是建议大家自己亲手实践一遍,大家可以点击 以下网址在线体验,复制链接查看源码:

https://www.qianduandaren.com/demo/admindash/

如果你喜欢我的分享,麻烦给个关注、点赞加转发哦,你的支持,就是我分享的动力,后续会持续分享实践案例,欢迎持续关注。

文章来源: 作者:George Martsoukos 网站:tutsplus 非直译

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

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