效果图
代码
<template>
<div>
<ul class="info-wrap">
<li
v-for="(item, index) in list"
:key="item.id"
class="info-item"
>
<div
class="base-info"
@mouseenter="showDetailInfo($event, index)"
@mouseleave="closeDetailInfo(index)"
>基本信息</div>
<div
v-show="item.showDetail"
:class="[
'detail-info',
item.className
]"
>详细信息</div>
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
list: [
{ id: 1 },
{ id: 2 },
{ id: 3 },
{ id: 4 },
{ id: 5 },
{ id: 6 },
{ id: 7 },
{ id: 8 },
{ id: 9 },
{ id: 10 },
]
}
},
methods: {
showDetailInfo(event, index) {
// 总容器宽度,去掉滚动条、border
const {
clientWidth: containerWidth,
} = document.querySelector('.info-wrap');
// 目标容器
const targetDom = event.target.parentNode.getBoundingClientRect();
// 总容器
const containerDom = document.querySelector('.info-wrap').getBoundingClientRect();
// 可用宽度:因为有滚动条的存在
const availableWidth = containerWidth + containerDom.left - targetDom.right;
// 可用高度
const availableHeight = containerDom.bottom - targetDom.top;
console.log(`可用宽度:${availableWidth}`, `可用高度:${availableHeight}`)
// 详情信息 10为间距
const detailWidth = 300 + 10;
const detailHeight = 300 + 10;
let className = {}
if (availableWidth > detailWidth) {
className.right = true
} else {
className.left = true
}
if (availableHeight > detailHeight) {
className.top = true;
} else {
className.bottom = true;
}
this.list.splice(index, 1, {
...this.list[index],
showDetail: true,
className
})
},
closeDetailInfo(index) {
this.$set(this.list[index], 'showDetail', false)
}
}
}
</script>
<style scoped lang="less">
.info-wrap {
width: 1000px;
margin: 50px auto;
height: 400px;
overflow: auto;
display: flex;
flex-wrap: wrap;
}
.info-item {
width: 200px;
height: 200px;
background: #ccc;
margin-right: 10px;
margin-bottom: 10px;
position: relative;
}
.base-info {
width: 200px;
height: 200px;
line-height: 200px;
text-align: center;
}
.detail-info {
position: absolute;
z-index: 999;
width: 300px;
height: 300px;
background: skyblue;
line-height: 300px;
text-align: center;
&::after {
content: '';
width: 10px;
height: 10px;
background: skyblue;
position: absolute;
transform: rotate(45deg);
}
&.left {
right: 210px;
&::after {
right: -5px
}
}
&.right {
left: 210px;
&::after {
left: -5px;
}
}
&.top {
top: 0;
&::after {
top: 20px;
}
}
&.bottom {
bottom: 0;
&::after {
bottom: 20px;
}
}
}
</style>