目录:
- 5、左侧边栏(难度:3.5颗星)
- 5.1、原型分析
- 套路5:当高度/宽度为动态获取,且相邻联动的两个区域
- 5.2、左边栏上下区域划分
- 套路6:无痕滚动
- 5.3、按钮的 CSS
- 5.4、历史记录
- 5.5、总结
5、左侧边栏(难度:3.5颗星)
前文参照:
第一节:https://blog.csdn.net/qq20004604/article/details/98748220
5.1、原型分析
我们先看原型图:
分析:
- 整体结构为上下两部分;
- 上方由不定数量的单行按钮组成,从上到下延伸(因此需要考虑如果数量比较多,超出显示区域怎么办);
- 下方由不定数量个历史操作组成;
总体考虑,我认为,这个布局有两种方法。
第一种(简单版):
- 上下期中一个高度是固定的,另一个自适应(通常来说,下最大高度不高,所以下应是固定的,上自适应);
- 自适应部分
overflow-y: auto
;
第二种(困难版):
- 上不定高;
- 下不定高但有最大高度限制;
- 上的最大高度根据下的最大高度变化;
- 上超出最大高度时,出现滚动条(或可以拖动滑动);
- 下超出最大高度时,只显示最新的;
我们采用第二种方式进行开发(第一种太简单)。
第二种情况,纯css通常是无法解决的,因此我们需要js介入。
注:虽说flex可以,flex在某些老版本浏览器(非IE678)或者手机浏览器,比如IOS10以前,是可能出现bug的。我之前在阿里时,接到过来自客户反馈。因此不采用flex。
下方历史记录的代码思路:
- 历史记录整体为绝对定位,
bottom: 0; width: 100%
; - 设置下方的最大高度,最大高度为
h_max = history的高度 + 单行历史记录的高度 * 最大显示历史记录的个数
; - 下方理论高度为
h_count = history的高度 + 单行历史记录的高度 * 历史数目个数
; - 实际高度为
h = h_count > h_max ? h_max : h_count
; - 下方默认有一条,当实际没有的时候,显示为【无】(占位使用);
上方按钮的代码思路:
- 绝对定位,
top: 0
; - 拿到下方的实际高度 h, 设置自己的 bottom 的值为 h;
- 设置
overflow-y: auto
;
套路5:当高度/宽度为动态获取,且相邻联动的两个区域
这是一个常见场景,通常见于其中一个区域数据来自于后端,另外一个区域填充以配合前者。
场景:
- 父容器不定宽不定高(但确定可以容纳两个子元素);
- 两个子元素共同填满父容器,且左右/上下相邻(为了方便分析,这里假设其上下相邻);
- 【假设上下相邻】;
- 两个子元素都不定高,但其中一个有最大高度(主次之分);
- 有最大高度的子元素,其高度是动态获取的;
解决思路:
方法一(简单,但在极少数情况下会出现兼容性问题):
- 假设两个子元素上下相邻,高度弹性;
- 采用弹性布局: flex;
- 配置子元素的弹性方向: flex-direction;
- 两个子元素都不设置高度,但宽度为100%;
- 设置有最大高度限制的子元素,其最大高度:max-height;
- 设置无最大高度限制的子元素(即另一个子元素),获得全部的剩余弹性空间分配: flex-grow;
- 于是受高度限制的子元素,其高度被填充内容的高度撑开;
- 而剩下的区域,被另外一个子元素拿走;
方法二(复杂,可靠,可配置性强):
- 假设两个子元素上下相邻,高度弹性;
- 父容器不定宽高,因此子容器需要写为绝对定位,位置通过 left, top, bottom, right 来实现;
- 两个子元素设置宽度为100%;
- 受限制一方的高度,通过js计算得出,然后写在标签的 style 属性的 height 值;
- 另一方的高度,其不设置 height 的值,而是通过设置 bottom 的值等于 style 属性的 height 值;
- 此时,两个元素的位置和高度,都已经被设置完毕了;
5.2、左边栏上下区域划分
参考【套路5、当高度/宽度为动态获取,且相邻联动的两个区域】的方法二的思想。
HTML代码很简单,整体来看是两层DOM结构,代码如下:
<div className="aside">
<div className='aside-nav'
style={navStyle}>
</div>
<div className='aside-history'
style={historyStyle}>
</div>
</div>
上下两部分的样式也很简单,标准的位置固定但高度不固定(注意,下面代码,我没有写两个子元素的高度)
.aside-nav {
position: absolute;
top: 0;
left: 0;
width: 100%;
// 测试用,查看显示效果是否正常
//background-color: red;
}
.aside-history {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
// 测试用,查看显示效果是否正常
//background-color: green;
}
现在,核心问题在于如何配置其高度,方法如下(见注释和上面的分析):
// 历史记录的数量,最小为1(为0时,该位置为占位符)
let historyLength = asideData.asideHistory.length < 1 ? 1 : asideData.asideHistory.length
// 最大只允许显示【10】行
const MAXHISTORYCOUNT = 10;
if (historyLength > MAXHISTORYCOUNT) {
historyLength = MAXHISTORYCOUNT
}
// 历史记录的高度 = history的高度34px(24px字体+5*2px上下部分行间距)
// + 历史记录单行高度22px(12px字体高度+5*2上下行间距)
// + 最下方留白5px
const historyHeight = 34 + 22 * historyLength + 5;
const navStyle = {
bottom: `${historyHeight}px`
}
const historyStyle = {
height: `${historyHeight}px`
}
此时我们已经配置好了两个子元素的高度,并且是动态生成的。
于是,给出 asideData.asideHistory 的模拟数据:
asideHistory: [
{
// 跳转url
url: '#01',
// 历史文字显示
text: 'gfdsbfdsbdfsb'
},
{
url: '#02',
text: 'hrtnhr12'
},
{
url: '#03',
text: 'mythn13rfe'
}
]
此时,我们更改 asideHistory 的元素个数,会发现 history 区域的高度发生变化。
【缺点】
该方案是没问题的,硬要说缺点的话,就是上方区域按钮比较多的时候,默认出现滚动条比较丑。
解决方案也不难,提供几个参考:
- 考虑手写一个滚动条,样式和整体风格保持一致;
- 不显示滚动条,但提供拖拽功能(即类似触摸屏的操作方式),然后给是否达到最上、最小的提示;
- 隐藏滚动条,但依然可以使用滚动功能(即按钮和上分栏之间插入一层父级div,该级div比显示区域更宽,滚动条即位于这更宽的区域之内,但受到其父级div overflow:hidden的约束,无法显示);
我这里采用第三种解决方案,方法参考【套路6:无痕滚动】
套路6:无痕滚动
场景描述:
- 假如父容器只有 100px 高,每个元素高 30px,可能有超过 3 个元素,但不允许超出父容器范围;
- 因此一般情况下,设置父容器 overflow:auto; 显示滚动条;
- 默认滚动条太难看,但不需要写自定义滚动条;
- 因此需要支持鼠标滚动,但不显示鼠标滚动;
解决思路:
- 父容器和子元素之间加一层 div#box;
- 假设父容器和子元素的宽度为 100px, 默认滚动条宽度为 25px;
- div#box 的高度设为 100%(同父容器),宽度设为 125px(100+25)。假如元素过多,则 div#box 出现滚动条;
- 父容器设置 overflow:hidden,那么 div#box 出现滚动条的时候,将在父容器显示范围之外;
- 子元素设置 max-width:100px,确保无论是否有滚动条,子元素的显示效果都是一致的。
5.3、按钮的 CSS
这个太简单了,无非就是按钮里面一图标一文字,就只说一下思路吧。
- 按钮的大小是固定的(不固定也无所谓,肯定有参考位置),添加定位属性,比如相对定位 relative;
- 图标设置为绝对定位,上下居中(参考【套路2:定高不定宽,内有居中和相对最右侧的元素】),然后再设置相对左侧距离(left属性);
- 文字同样绝对定位,上下居中,通过 left 相对左侧的距离。唯一区别是,需要通过 right 属性设置最右侧的宽度,防止文字超出其应该显示的区域;
需要注意的是:
- 这个样式按钮hover状态是 45px 高,因此认为一个按钮的高度为45px;
- 但通过PS量实际两个按钮实际间距是50px(醉了!+1),无视,认为是原型图的问题,认为按钮与按钮的实际间距是45px(即按钮是连续的,不存在额外的间距);
- 但又发现第一个按钮的高度是65px(醉了+2,这种设计很奇怪);
- 推定按钮的父容器有额外
padding-top: 20px;
;
代码参照:
src/components/aside/index.jsx
src/components/aside/style.less
5.4、历史记录
解决了高度问题后,这个就更简单了。
- History 文字所在 div 宽度 100%,
- 每个历史记录 div 宽度 100%,高度、行高等于实际高度;
- 父级 div 设置 padding-bottom 下方留出应有的空隙;
完事。
5.5、总结
此时效果图如下:(假设按钮比较多的极端情况效果图)
此时代码参考分支:
https://github.com/qq20004604/tell-you-write-manage-page/tree/0.0.2-左边栏done
- 源代码:https://github.com/qq20004604/tell-you-write-manage-page
- 作者微信:qq20004604
- 讨论(QQ群):387017550