滚动列表展示跟随弹框效果
需求:
现在有一个滚动列表,当我点击电话图标的时候,就会在这一行的末尾展示一个弹窗,并且可以在各个分辨率下都能动态计算它的位置,当我滚动的时候这个弹框会自动关闭
效果:
先说我在编写时候的问题,因为这个页面中是用Grid布局编写的,因此同时还有其他的模块存在:
理想状态:
实际状态:
- 首先就是这个弹窗会被旁边的模块盖住,即使我设置了这个弹窗的z-index:200,比旁边的大,还是会。因此我在编写Grid布局的父容器,将当前这个模块的z-index设置为99(比弹窗的小就行,但要比旁边的大,根据实际情况定)。
- 再就是滚动列表中的表头不会随着滚动,设置了粘性定位,这就导致设置绝对定位的弹窗会被粘性定位的表头盖住,所以这里需要将弹窗写在最外层容器下,而不是表格中的数据行旁边,再给弹窗设置fixed定位,并且设置pointer-events: auto; 和 overflow: visible;
下面这个结构就是我在上述说的,不要把弹窗写在list结构中,而是写在最外层和list同级中,这样就可以避免被表头盖住
<div><div class="container">弹窗</div><div class="list">列表</div> </div>
- 最后就是弹窗的位置是通过js获取元素去计算的,就会有一些偏移,那我们就需要+或者-一些偏移量,那如果直接写以px为单位的值,就无法做到在各个分辨率下都能适应,这里需要换算成vw或者rem
代码示例:
<template><div class="online-num-container" ref="containerRef"><div class="infinite-list-container"><div class="fixed-header"><table class="data-table header-table"><thead><tr><th style="width: 40%">姓名</th><th style="width: 40%">账号</th><th style="width: 20%"></th></tr></thead></table></div><div class="scrollable-body" ref="scrollContainer"><table class="data-table body-table"><tbody><tr v-for="(item, index) in list" :key="index"><td style="width: 40%">张三</td><td style="width: 40%">张三的账号</td><td style="width: 20%;"><imgstyle="width: 0.8vw;height: 0.8vw;cursor: pointer;"src="..."@click="(e) => togglePhoneBox(index, e)"alt=""></td></tr></tbody></table><div class="loading-status" v-if="loading"><span>加载中...</span></div><div v-if="finished && !loading"></div></div></div><divv-show="activePhoneIndex !== null && phoneBoxPosition"class="phone-box global-phone-box":style="phoneBoxPosition"ref="phoneBoxRef"><imgclass="phone-box-close"src="..."alt=""@click="activePhoneIndex = null"/><div class="phone-box-name">姓名:张三</div><div class="phone-box-phone">电话:12345678900</div></div></div>
</template>
const activePhoneIndex = ref(null)
const phoneBoxPosition = ref(null)
const phoneBoxRef = ref(null)const togglePhoneBox = async (index, event) => {if (activePhoneIndex.value === index) {activePhoneIndex.value = nullphoneBoxPosition.value = null} else {activePhoneIndex.value = indexawait nextTick()const triggerRect = event.currentTarget.getBoundingClientRect()const vw = window.innerWidth / 100const vw20 = 20 / 1920 * 100const gapPx = vw20 * vwphoneBoxPosition.value = {position: 'fixed',top: `${triggerRect.top - gapPx}px`,left: `${triggerRect.right}px`,zIndex: 200}}
}
css只给出部分代码:
父容器的:
<cur-component style="z-index: 99;" />
给当前组件设置z-index高于旁边的优先级
弹窗的:
.phone-box {width: 9vw;aspect-ratio: 28 / 9;font-size: 0.6vw;color: #eab37a;overflow: visible;
}.global-phone-box {position: fixed;z-index: 200;pointer-events: auto;
}