需求场景
日常开发中,我们可能会需要实现类似这样的组件,组件带有弹框
一般实现
一般都是父盒子【position: relative;】弹框盒子相对父盒子【position: absolute;】 这种做法平时不会有什么问题,但是当有父盒子设置【overflow: hidden;】时,就会出现这种现象
是的,超出的部分已被隐藏了
学会观察
如果认真观察其他ui库的类似组件的话,你会发现它们都被挂载到body下面去了,所以该组件的父盒子影响不到弹窗的盒子
尝试实现
我们给弹框盒子加上一个ref属性
在点击事件里,我们使用this.$refs.downSelect获取该节点,并将其追加到body下
这里使用this.$nextTick(),是因为我控制弹框的显示是使用v-if,需要下次更新才能获取的到,好啦,我们看下效果
可以看到,已经挂载到body下了,不过你会发现,定位的位置好像不对呀!别急,下一步就是要计算弹框在body定位的位置了
思路讲解
我们原先相对于父盒子定位是没有问题的,现在相对于body,那么就需要计算出父盒子与body的距离
先给父盒子添加ref
点击事件获取pageChange,并且打印offsetTop属性
结果是
讲一下这个offsetTop: 通俗一点讲就是,获取距离最近设置position属性的父节点的顶部距离
来看下例子:
<div class="a">
<div class="b" style="position: relative;">
<div class="c"></div>
<div class="c2"></div>
</div>
<div class="b2"></div>
</div>
c2.offsetTop获取的就是c2顶部距离b顶部的距离
<div class="a" style="position: relative;">
<div class="b">
<div class="c"></div>
<div class="c2"></div>
</div>
<div class="b2"></div>
</div>
c2.offsetTop获取的就是c2顶部距离a顶部的距离
注:如果都没有设置position,那c2.offsetTop获取的就是距离body顶部的距离 同样的offsetLeft属性,对应的就是左边的距离
好啦,思路就是这样,我们来试下
继续尝试
我这个demo都没有设置position,我们直接把offsetTop和offsetLeft赋值给弹框的top、left
看下效果
嗯,效果还不错,不过还差一点,我们设置下transform: translate();
偏移量为pageChange的高度
最终效果如下
成功追加到body下了,并且位置也没问题
小小总结下
这篇文章只是讲解了如何将弹框添加到body下,并且获取定位的合适距离 这种情况只适合页面的滚动发生在body上 如果你有设置另外的滚动页面滚动盒子 例如:弹窗里面嵌套选择下拉框 这时就需要将【弹框】挂载到【弹窗】的滚动盒子下面 同样的定位也要相对弹窗的滚动盒子 如果你不确定挂载的父盒子的话,可能需要js查找符合条件的节点啦
我用的是向上递归查找,代码也放一下吧
function dfsOutScrollNode(node) {
const styles = getComputedStyle(node, null)
const overflow = styles['overflow']
const overflow_y = styles['overflow-y']
const overflow_x = styles['overflow-x']
let isScroll = ['auto', 'scroll'].indexOf(overflow)
isScroll += ['auto', 'scroll'].indexOf(overflow_y)
isScroll += ['auto', 'scroll'].indexOf(overflow_x)
if (isScroll !== -3 || node === document.body) {
return node
}
return this.dfsOutScrollNode(node.parentNode)
}
欢迎评论~