Compare commits

..

2 Commits

Author SHA1 Message Date
Zzc
b786647378 Merge branch 'dev' of http://222.212.85.86:8222/bdzl2/bxztApp into dev 2025-11-11 18:04:02 +08:00
Zzc
23ea3af0de feat(cockpit): 为可嵌入布局添加容器查询支持
增加对 CSS 容器查询的支持,从而在嵌入式场景中实现响应式缩放。
更新了 mixin,使其使用容器单位(cqw/cqh)并为不支持的浏览器提供视口回退。
修改了 CockpitLayout,使用 CSS 自定义属性实现灵活嵌入,包括窄容器的紧凑模式。
2025-11-11 18:03:50 +08:00
3 changed files with 107 additions and 20 deletions

View File

@ -1,5 +1,16 @@
@use './mixins.scss' as *; @use './mixins.scss' as *;
/**
* 全局 CSS 容器查询回退
*
* 这些根级别变量为不支持容器查询的浏览器提供默认的视口单位
* 设置了 container-type 的组件会在支持时覆盖这些值为容器单位cqw/cqh
*/
:root {
--cq-inline-100: 100vw;
--cq-block-100: 100vh;
}
* { * {
margin: 0; margin: 0;
padding: 0; padding: 0;

View File

@ -1,22 +1,40 @@
// 屏幕适配工具 // 屏幕适配工具支持容器查询
// 设计稿基准1920px () × 982px (不含头部) // 设计稿基准1920px () × 982px (不含头部)
//
// 容器查询支持
// 当组件嵌入到其他系统时会自动使用容器单位cqw/cqh而非视口单位vw/vh
// 这确保了子组件相对于父容器而非整个视口进行缩放
//
// 回退策略
// 使用 CSS 变量 --cq-inline-100 --cq-block-100 提供渐进增强
// 不支持容器查询的浏览器会回退到视口单位
// px 转换为 vw (基于设计稿宽度 1920px) $design-width: 1920;
$design-height: 982;
// px 转换为容器宽度单位基于设计稿宽度 1920px
// 在支持容器查询的浏览器中使用 cqw否则回退到 vw
@function vw($px) { @function vw($px) {
@return calc($px / 1920 * 100vw); @return calc($px / $design-width * var(--cq-inline-100, 100vw));
} }
// px 转换为 vh (基于设计稿内容区域高度 982px) // px 转换为容器高度单位基于设计稿内容区域高度 982px
// 在支持容器查询的浏览器中使用 cqh否则回退到 vh
@function vh($px) { @function vh($px) {
@return calc($px / 982 * 100vh); @return calc($px / $design-height * var(--cq-block-100, 100vh));
} }
// 字体大小转换 (使用 vw 确保响应式) // 字体大小转换使用容器宽度确保响应式
// 字体随容器宽度缩放保持与其他元素的比例关系
@function fs($px) { @function fs($px) {
@return calc($px / 1920 * 100vw); @return vw($px);
} }
// 使用示例 // 使用示例
// width: vw(580); // 580px vw // width: vw(580); // 580px cqw ( vw 作为 fallback)
// height: vh(400); // 400px vh // height: vh(400); // 400px cqh ( vh 作为 fallback)
// font-size: fs(16); // 16px vw // font-size: fs(16); // 16px cqw ( vw 作为 fallback)
//
// 注意这些函数需要父容器设置了 container-type: inline-size size
// 例如在 CockpitLayout.vue 中已经设置了相应的容器类型

View File

@ -29,32 +29,89 @@ import YearStatistics from './YearStatistics.vue'
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@use '@/styles/mixins.scss' as *; /**
* 驾驶舱布局 - 可嵌入组件
*
* 此组件设计为可嵌入到其他系统中iframe/组件
* 使用百分比和 rem 单位而非 vw/vh以适应父容器尺寸
*
* CSS 自定义属性可被父级覆盖
* - --cockpit-side-width: 侧边栏宽度默认minmax(15rem, 28%)
* - --cockpit-gap: 网格间距和面板间距默认1.25rem
* - --cockpit-padding-x: 水平内边距默认0.625rem
* - --cockpit-padding-top: 顶部内边距默认0
* - --cockpit-padding-bottom: 底部内边距默认0
* - --cockpit-min-height: 最小高度默认600px
*
* 父级使用方式<CockpitLayout style="--cockpit-gap: 2rem" />
* 窄容器嵌入<1100px 宽度添加 .is-compact 修饰符类
* <CockpitLayout class="is-compact" />
* 如需在滚动父容器中嵌入可覆盖 overflow: hidden
*
* 浏览器兼容性需要 CSS 自定义属性支持Chrome 49+, Safari 9.1+, Firefox 31+
* 未来计划支持容器查询以实现响应式窄屏布局
*
* 基于 1920px 设计稿根字体大小 16px
*/
.cockpit-layout { .cockpit-layout {
width: 100vw; /* 容器查询设置,用于嵌入场景的自适应缩放 */
height: 100vh; container-name: cockpit-layout;
container-type: size;
/* 为旧版浏览器提供视口单位回退 */
--cq-inline-100: 100vw;
--cq-block-100: 100vh;
/* 当支持容器单位时覆盖为容器单位 */
@supports (width: 1cqw) {
--cq-inline-100: 100cqw;
}
@supports (height: 1cqh) {
--cq-block-100: 100cqh;
}
/* 嵌入场景的 CSS 自定义属性 */
--cockpit-side-width: minmax(15rem, 28%);
--cockpit-gap: 1.25rem;
--cockpit-padding-x: 0.625rem;
--cockpit-padding-top: 0;
--cockpit-padding-bottom: 0;
--cockpit-min-height: 600px;
/* 使用 100% 填充父容器而非视口 */
width: 100%;
height: 100%;
min-height: var(--cockpit-min-height);
min-width: 0; /* 允许 flex 子元素收缩 */
background: url(../assets/img/cockpit-main-bg.png) no-repeat; background: url(../assets/img/cockpit-main-bg.png) no-repeat;
background-size: cover; background-size: cover;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
overflow: hidden; overflow: auto; /* 当宿主高度 < 最小高度时允许滚动 */
}
/* 窄容器嵌入的紧凑布局(<1100px 宽度)*/
.cockpit-layout.is-compact {
--cockpit-side-width: minmax(12rem, 24%);
--cockpit-gap: 1rem;
} }
.cockpit-main { .cockpit-main {
flex: 1; flex: 1;
min-height: 0; /* 允许网格在 flex 上下文中收缩 */
display: grid; display: grid;
grid-template-columns: vw(580) 1fr vw(580); grid-template-columns: var(--cockpit-side-width) 1fr var(--cockpit-side-width);
gap: vw(20); gap: var(--cockpit-gap);
padding: 0 vw(10); padding: var(--cockpit-padding-top) var(--cockpit-padding-x) var(--cockpit-padding-bottom);
// padding-top: 0;
} }
.left-panel, .left-panel,
.right-panel { .right-panel {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: vw(20); gap: var(--cockpit-gap);
min-width: 0; /* 防止在窄容器中溢出 */
} }
.center-panel { .center-panel {
@ -62,5 +119,6 @@ import YearStatistics from './YearStatistics.vue'
align-items: center; align-items: center;
justify-content: center; justify-content: center;
position: relative; position: relative;
min-width: 0; /* 确保地图可以在需要时收缩 */
} }
</style> </style>