Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

后台系统 Layout 实现总结 #6

Open
ryancui92 opened this issue Jul 19, 2017 · 0 comments
Open

后台系统 Layout 实现总结 #6

ryancui92 opened this issue Jul 19, 2017 · 0 comments

Comments

@ryancui92
Copy link
Owner

ryancui92 commented Jul 19, 2017

自己写布局

最近要用 Angular 搞一个后台系统的框架,就遇到了这个问题,在 Github 上搜到的解决方案基本都集成了自己的一套 UI Component,但我特么只想要个 Layout 啊!组件我不用你的啊,我用 PrimeNG 啊!能不能不要搞个 CSS Confliction 啊!由于这些方案都太大太杂(而且不想再依赖 jQuery 了),所以还是自己写一个。

  • 包含 Header、Footer、Sidebar、Content 四部分的布局
  • 四部分自适应浏览器宽高,不考虑移动端,不搞响应式
  • Sidebar 固定宽度,Content 自适应
  • Header 有 Dropdown Menu,可以在那里做退出等操作
  • Sidebar 包含一个侧边栏菜单,菜单要有下滑动画
  • 使用原生 JavaScript 实现,不依赖任何 JS 库、组件
  • 不依赖任何 CSS 框架

需求其实不是很复杂,而且我也找了几个网站来参考,包括 AdminLTE 和阿里云的后台,主要参考阿里云的后台。

问题总结

position: absolute? fixed?

全部用 absolute 布局,对 absolute 的布局原点要清楚,否则 top/bottom 就会搞错

absolute 的参考原点是有 absolute/fixed 布局的最近父元素
fixed 的参考原点是浏览器

mouseover or mouseenter

在实现 Header Dropdown Menu 的时候,需要 hover 到 btn 就 display 菜单,并且在移进 menu panel 的时候维持这个 display. 一开始用了 mouseovermouseout,在 btn 和 panel 都做两次检测。

$dropdownBtns[i].addEventListener('mouseover', function (evt) {
  var ele = evt.target
  var panel = ele.nextElementSibling
  panel.style.visibility = 'visible'
})

$dropdownBtns[i].addEventListener('mouseout', function (evt) {
  var ele = evt.target
  var panel = ele.nextElementSibling
  panel.style.visibility = 'hidden'
})

$dropdownPanels[i].addEventListener('mouseover', function (evt) {
  var ele = evt.target
  ele.style.visibility = 'visible'
})

$dropdownPanels[i].addEventListener('mouseout', function (evt) {
  var ele = evt.target
  ele.style.visibility = 'hidden'
})

当我的 menu 还是一个 div 的时候,一切都很完美。Nice!

当在这个 div 内部填东西的时候就懵逼了,在里面随便动动里面的内容就会突然消失。。

不论鼠标指针穿过被选元素或其子元素,都会触发 mouseover 事件。对应 mouseout
只有在鼠标指针穿过被选元素时,才会触发 mouseenter 事件。对应 mouseleave

overflow: visible

在实现侧边栏菜单的时候,一开始想要实现像 AdminLTE 那样的悬浮菜单

image

自然的想法是跟 dropdown menu 一个道理,只是 dropdown panel 不定位在下面了,定在右边,于是大概就是这样

<div class="menu">
  <div class="btn">Menu</div>
  <div class="panel">Panel</div>
</div>
.menu {
  position: relative;
  width: 100px;
  height: 200px;
}

.btn {
  position: relative;
  width: 100px;
  height: 20px;
}

.panel {
  position: absolute;
  top: 0;
  left: 100px;
}

没有问题,布局是正确的。panel 的确出现在了右边,加上一些 js 就搞定了!但既然这是个 menu,那应该会有很多个 item 吧,那我加个 overflow 吧

.menu {
  overflow: auto;
}

What the fvck! 怎么 x 也有个滚动条,我要你这个 panel 突出去啊,改一下

.menu {
  overflow-y: auto;
}

还是不行,查了下,貌似有个 visible 属性,允许子元素显示在容器外面,很好!

.menu {
  overflow-y: auto;
  overflow-x: visible;
}

这个滚动条还在,嗯。

原来这个 visible 是没用的!如果对 x 或 y 单独使用 visible,另外一个轴没有设置 visible,这个设置成 visible 的轴会自动转成 auto

给个大牛李猜猜的 CodePen 看看:

李猜猜的 CodePen

transition height/max-height

到了实现侧边栏动态伸缩的时候,第一时间写下了这样的 transition

.sidebar {
  transition: width 0.5s ease-out;
}

绑定一下 button 的 click 事件,把 style 的 width 改一下,效果就出来了,很好。

那就再把下拉菜单的动画效果也做了吧

.submenu-box {
  transition: height 0.5s ease-out;
}

果不其然,这样又 fail 了,要换成 max-height 才行。

看这里 how-can-i-transition-height-0-to-height-auto-using-css

多级菜单

只要解决几个问题就行了

  1. 下拉菜单 expand 时,正确计算需要的 max-height 值(下拉菜单里面可能还有下拉菜单)
  2. 下拉菜单 expand 时,要把同级的其他菜单 collapse 掉
  3. 每下降一个 level,padding 要增加,显示缩进的效果

对于第三点,Less 的循环就能很好的解决了,参考官网的例子,生成 6 层,每层 padding 递增 10px

.generate-menu-item(6);
.generate-menu-item(@n, @i: 1) when (@i =< @n) {
  .menu-item-@{i} {
    padding-left: 10px * @i;
  }
  .generate-menu-item(@n, (@i + 1));
}

第二点折衷成只在第一层菜单做 single expand,下面的层就不管了,爱 expand 多少就 expand 多少,这样考虑的话,每次处理 expand/collapse 事件时,只需要处理其他的 top menu 就可以了。

计算后代节点有多少个 menu-item 就更简单了,直接在菜单中 getElementsByClassName 就行了,每个菜单项都有一个固定的 menu-item class,就能直接算出来了。

总结

作为一名前端小白,做这样一个布局都踩到不少基础的坑,包括事件代理这里面也还没实现,但不得不说,StackOverFlow 简直是神器!

最后附上项目地址:admin-layout

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant