在维护旧项目时,使用了我认为是“上古年代”的 layui组件
。
大概在这样的场景:在一个有最大高度限制的容器里有很多表单项,表单项中使用了 layui 的 表单select下拉框(表单自动初始化)。
问题来了
问题来了,点击下拉框出现时,选择项下拉框居然被覆盖在下方,观察到右侧出现滚动条。
大概分析了一下原因,下拉框元素是绝对定位于其下拉框包裹器父元素的;但是由于最外层的容易设置了最大高度滚动,因此下拉框的整体高度依然会被动态计算。下方的高度不够,就会导致整体被撑开;虽然并不影响功能,但是却会对用户体验和产品质量造成较大影响。
解决思路
按照 Ant Design of Vue - Select选择器 的设计思路,下拉框根据底部可视距离,自动调整位置。
Antd的选择器组件默认挂在在 document.body 上,可以根据需要调整。官方的描述是 菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位
。
回到 layui 中,包括其他组件库的选择器组件,比较少有自定义挂载节点的选项,如果手动修改节点的挂载位置,很可能会造成意想不到的bug。比如与原有的处理判断逻辑冲突,而且操作重新构造DOM相对繁琐。故考虑调整下拉框显示位置,个人觉得这种设计也比较合理和人性化。
代码示例
<div style="width: 400px">
<form class="layui-form" action="" lay-filter="form-custom">
<div class="scroll-div" style="max-height: 100px">
<div class="layui-form-item">
<label class="layui-form-label">水果名称</label>
<div class="layui-input-block">
<select name="fruit" lay-filter="fruit">
<option value="">请选择</option>
<option value="1">苹果</option>
<option value="2">香蕉</option>
<option value="3">草莓</option>
</select>
</div>
</div>
</div>
</form>
</div>
$('.scroll-div .layui-form-select').on('click',function (e) {
// 获取点击元素
const current = e.currentTarget
// 获取滚动 wrapper
const wrapper = document.querySelector('.scroll-div')
// 判断处于选中状态
if (current.classList.contains('layui-form-selected')){
// 获取下拉列表元素
const selectList = current.children[1]
// 获取下拉列表元素高度
const selectHeight = selectList.getBoundingClientRect().height
// 获取各自与可视距离底部的距离
const select_bottom = current.getBoundingClientRect().bottom
const scroll_bottom = wrapper.getBoundingClientRect().bottom
// 判断距离差是否可以容纳下下拉菜单元素,如果不能就置于选择框顶部;如果可以放置于原位(假设下拉框高度为42px)
if (scroll_bottom - select_bottom < selectHeight){
selectList.style.top = - selectHeight + 'px'
}else{
selectList.style.top = '42px'
}
}
})
附: