创建TabPage组件,初始宽300px、高250px,相对父容器水平和垂直居中

This commit is contained in:
zqm
2025-11-05 08:55:44 +08:00
parent 10875fc886
commit c8cec393c2

View File

@@ -0,0 +1,160 @@
<template>
<div class="tab-page-wrapper" :style="wrapperStyle">
<div class="tab-page" :style="tabPageStyle">
<!-- Tab页内容区域 -->
<div class="tab-page-content">
<slot></slot>
</div>
</div>
</div>
</template>
<script setup>
import { defineProps, computed, ref, onMounted } from 'vue'
const props = defineProps({
id: { type: String, required: true },
title: { type: String, default: '标签页' },
// 默认尺寸
width: { type: Number, default: 300 },
height: { type: Number, default: 250 },
// 位置属性,可选
left: { type: Number, default: undefined },
top: { type: Number, default: undefined }
})
// 本地状态存储位置和大小
const position = ref({
width: props.width,
height: props.height,
left: props.left,
top: props.top
})
// 父容器引用
const parentContainer = ref(null)
// 计算wrapper样式 - 用于居中定位
const wrapperStyle = computed(() => {
// 当没有指定left或top时保持居中
if (position.value.left === undefined || position.value.top === undefined) {
return {
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
position: 'relative'
}
}
// 当指定了位置时,使用绝对定位
return {
position: 'relative',
width: '100%',
height: '100%'
}
})
// 计算tab page样式
const tabPageStyle = computed(() => {
const style = {
width: `${position.value.width}px`,
height: `${position.value.height}px`,
background: '#ffffff',
border: '1px solid #c7d2ea',
borderRadius: '4px',
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.1)'
}
// 如果有明确的位置,则使用指定位置
if (position.value.left !== undefined) {
style.position = 'absolute'
style.left = `${position.value.left}px`
}
if (position.value.top !== undefined) {
style.position = 'absolute'
style.top = `${position.value.top}px`
} else if (position.value.left === undefined) {
// 如果没有指定位置保持居中由wrapper处理
style.position = 'relative'
}
return style
})
// 组件挂载后获取父容器引用并初始化位置
onMounted(() => {
parentContainer.value = document.querySelector('.dock-layout') || window
// 如果没有指定left或top自动居中定位
if (position.value.left === undefined || position.value.top === undefined) {
let parentWidth, parentHeight
if (parentContainer.value === window) {
parentWidth = window.innerWidth
parentHeight = window.innerHeight
} else if (parentContainer.value) {
const parentRect = parentContainer.value.getBoundingClientRect()
parentWidth = parentRect.width
parentHeight = parentRect.height
} else {
// 默认值,防止出错
parentWidth = 800
parentHeight = 600
}
const tabWidth = position.value.width || 300
const tabHeight = position.value.height || 250
// 计算居中位置
position.value.left = Math.floor((parentWidth - tabWidth) / 2)
position.value.top = Math.floor((parentHeight - tabHeight) / 2)
}
})
</script>
<style scoped>
.tab-page-wrapper {
position: relative;
overflow: visible;
}
.tab-page {
display: flex;
flex-direction: column;
background: #ffffff;
border: 1px solid #c7d2ea;
border-radius: 4px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
.tab-page-content {
flex: 1;
padding: 16px;
overflow: auto;
}
/* 滚动条样式 */
.tab-page-content::-webkit-scrollbar {
width: 12px;
height: 12px;
}
.tab-page-content::-webkit-scrollbar-track {
background: #f5f7fb;
border-left: 1px solid #c7d2ea;
}
.tab-page-content::-webkit-scrollbar-thumb {
background: linear-gradient(to bottom, #d0d6ea, #c0c7e0);
border: 1px solid #b0b6d6;
border-radius: 6px;
}
.tab-page-content::-webkit-scrollbar-thumb:hover {
background: linear-gradient(to bottom, #c1c7e2, #b2b8d9);
}
</style>