最近有收到一个需求,具体如下:
A组件订阅了消息,收到后端推送的消息时,要在B组件中找到对应元素并且弹窗显示详细信息
实现方案如下:
-
首先,A组件收到消息时,向B组件推送,通过
postMessage
、addEventListener
两个api可实现,其他文章中有提到,不赘述; -
然后,B组件收到消息时,找到对应的元素,并找到元素相对浏览器窗口的位置,确定弹窗的定位:
这里要使用到
getBoundingClientRect
这个api,它的作用是获取元素相对于浏览器窗口的位置以及元素的宽高 -
需要注意:
1. 要处理一下靠近页面边界的点位,如果不进行处理,弹窗会溢出,影响体验; 2. 不同屏幕适配,最好将px转化为百分比;
代码如下:
<template>
<div class="test">
<ul>
<li v-for="(item, index) in list" :key="index" :ref="'item-' + index" :style="{
left: item.left + 'px',
top: item.top + 'px'
}" @click="clickItem(index)"></li>
</ul>
<div v-show="show" ref="modal" class="box" :style="{
left: left + 'px',
top: top + 'px'
}"></div>
</div>
</template>
<script>
export default {
data() {
return {
show: false,
left: 0,
top: 0,
list: [
{
left: 20,
top: 20
},
{
left: 1880,
top: 20
},
{
left: 20,
top: 780
},
{
left: 1880,
top: 780
},
{
left: 950,
top: 400
}
]
};
},
mounted() {
// 用定时器模拟A组件的推送
setTimeout(() => {
this.clickItem(1);
}, 3000);
},
methods: {
clickItem(i) {
const rect = this.$refs['item-' + i][0].getBoundingClientRect();
const { x, y } = rect;
const navH = 120; // 导航栏高度
this.left = x + 20; // 相对元素偏移20px
this.top = y + 20 - navH;
// 处理边界周围的点
const dowWidth = this.$refs.modal.getBoundingClientRect().width;
const dowHeight = this.$refs.modal.getBoundingClientRect().height;
const clientW = document.body.clientWidth;
const clientH = document.body.clientHeight;
if (dowWidth + this.left > clientW) {
this.left = x - dowWidth;
}
if (dowHeight + this.top > clientH - navH) {
this.top = y - navH - dowHeight;
}
this.show = true;
}
}
};
</script>
<style lang="scss" scoped>
.test {
position: relative;
width: 100%;
height: 100%;
ul li {
width: 20px;
height: 20px;
background-color: #0A1748;
border-radius: 10px;
position: absolute;
}
.box {
width: 200px;
height: 200px;
border-radius: 10px;
background-color: #0D357D;
position: absolute;
}
}
</style>
效果: