Files
lingji-work-fe/src/views/components/layout/index.vue

409 lines
16 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="page-container" ref="container">
<div class="layout-buttons">
<button @click="switchLayout('strategy1')">默认布局</button>
<button @click="switchLayout('strategy2')">策略2布局</button>
<button @click="switchLayout('strategy3')">策略3布局</button>
</div>
<div>屏幕宽度{{ screenWidth }}px</div>
<div class="components-container">
<component
v-for="component in components"
:is="component.comp"
:key="component.id"
class="component"
:style="getComponentStyle(component)"
></component>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import Comp1 from './comp1.vue';
import Comp2 from './comp2.vue';
import Comp3 from './comp3.vue';
import Comp4 from './comp4.vue';
interface ComponentState {
id: string;
comp: ReturnType<typeof defineComponent>;
x: number | string;
y: number | string;
width?: number | string;
minWidth?: number | string;
maxWidth?: number | string;
height: number;
zIndex?: number | string;
background?: string;
}
const components = ref<ComponentState[]>([]);
const container = ref<HTMLElement | null>(null);
const screenWidth = ref(0);
const screenHeight = ref(0);
const layoutComp1 = shallowRef(Comp1);
const layoutComp2 = shallowRef(Comp2);
const layoutComp3 = shallowRef(Comp3);
const layoutComp4 = shallowRef(Comp4);
const layoutCompMap = {
comp1: layoutComp1,
comp2: layoutComp2,
comp3: layoutComp3,
comp4: layoutComp4,
};
const containerWidth = ref(0);
const containerHeight = ref(0);
const currentLayoutStrategy = ref<LayoutStrategy>('strategy1');
onMounted(() => {
const observedElement = document.querySelector('#app');
if (observedElement) {
const resizeObserver = new ResizeObserver((entries) => {
const entry = entries[0];
const { width, height } = entry.contentRect;
screenWidth.value = width;
screenHeight.value = height;
console.log('screenWidth', width);
const compStyles = loadComponentWidthRange(currentLayoutStrategy.value, width);
if (compStyles) {
setComponentStyleByStrategy(compStyles);
}
// const screenResolution = getComponentWidthRange(width);
// if (screenResolution) {
// setComponentStyleByStrategy(screenResolution.compStyles);
// }
});
resizeObserver.observe(observedElement);
}
});
type Coordinate = number | [number, number];
type ComponentWidthRange = {
width: [number, number];
height: number;
compName: string;
background?: string;
x: Coordinate;
y: Coordinate;
};
type ScreenResolutionMap = {
[resolutionRange: string]: {
layoutStrategy: string;
compStyles: ComponentWidthRange[];
};
};
type LayoutStrategy = 'strategy1' | 'strategy2' | 'strategy3';
type Resolution = {
[resolutionRange: string]: ComponentWidthRange[];
};
type ScreenResolutionMap1 = {
layoutStrategy: LayoutStrategy;
resolution: Resolution;
};
const screenResolutionMap1: ScreenResolutionMap1[] = [
{
layoutStrategy: 'strategy1',
resolution: {
'[0, 768]': [
{ width: [498, 498], compName: 'comp1', height: 550, background: 'red', x: 266, y: 0 },
{ width: [498, 498], compName: 'comp2', height: 304, background: '#ccdc', x: [266, 266], y: 550 },
{ width: [266, 266], compName: 'comp3', height: 856, background: '#5E6673', x: 0, y: 0 },
{ width: [768, 768], compName: 'comp4', height: 304, background: 'blue', x: 0, y: 856 },
],
'[769, 1280]': [
{ width: [498, 836], compName: 'comp1', height: 610, background: 'red', x: 0, y: 0 },
{ width: [135, 222], compName: 'comp2', height: 610, background: '#ccdc', x: [498, 836], y: 0 },
{ width: [135, 222], compName: 'comp3', height: 908, background: '#5E6673', x: [768, 1012], y: 0 },
{ width: [768, 1012], compName: 'comp4', height: 356, background: 'blue', x: 0, y: 610 },
],
'[1281, 1440]': [
{ width: [836, 836], compName: 'comp1', height: 610, background: 'red', x: 0, y: 0 },
{ width: [222, 302], compName: 'comp2', height: 610, background: '#ccdc', x: 836, y: 0 },
{ width: [222, 302], compName: 'comp3', height: 908, background: '#5E6673', x: [1058, 1138], y: 0 },
{ width: [1012, 1138], compName: 'comp4', height: 410, background: 'blue', x: 0, y: 610 },
],
'[1441, 1920]': [
{ width: [836, 1196], compName: 'comp1', height: 610, background: 'red', x: 0, y: 0 },
{ width: [302, 362], compName: 'comp2', height: 610, background: '#ccdc', x: [836, 1196], y: 0 },
{ width: [302, 362], compName: 'comp3', height: 908, background: '#5E6673', x: [1138, 1158], y: 0 },
{ width: [1138, 1558], compName: 'comp4', height: 410, background: 'blue', x: 0, y: 610 },
],
'[1921, 3860]': [
{ width: [1196, 1696], compName: 'comp1', height: 610, background: 'red', x: 0, y: 0 },
{ width: [362, 432], compName: 'comp2', height: 610, background: '#ccdc', x: [1196, 1696], y: 0 },
{ width: [362, 432], compName: 'comp3', height: 908, background: '#5E6673', x: [1558, 2128], y: 0 },
{ width: [1558, 2128], compName: 'comp4', height: 356, background: 'blue', x: 0, y: 610 },
],
},
},
{
layoutStrategy: 'strategy2',
resolution: {
'[0, 768]': [
{ width: [200, 300], compName: 'comp1', height: 500, background: 'red', x: 0, y: 0 },
{ width: [300, 400], compName: 'comp2', height: 500, background: '#ccdc', x: [200, 300], y: 0 },
{ width: [300, 400], compName: 'comp3', height: 970, background: '#5E6673', x: [500, 700], y: 0 },
{ width: [300, 400], compName: 'comp4', height: 410, background: 'blue', x: 0, y: 500 },
],
'[769, 1280]': [
{ width: [200, 300], compName: 'comp1', height: 500, background: 'red', x: 0, y: 0 },
{ width: [300, 400], compName: 'comp2', height: 500, background: '#ccdc', x: [200, 300], y: 0 },
{ width: [300, 400], compName: 'comp3', height: 970, background: '#5E6673', x: [500, 700], y: 0 },
{ width: [300, 400], compName: 'comp4', height: 410, background: 'blue', x: 0, y: 500 },
],
'[1281, 1440]': [
{ width: [280, 400], compName: 'comp1', height: 600, background: 'red', x: 0, y: 0 },
{ width: [350, 450], compName: 'comp2', height: 500, background: '#ccdc', x: [280, 400], y: 0 },
{ width: [350, 450], compName: 'comp3', height: 970, background: '#5E6673', x: [630, 850], y: 0 },
{ width: [350, 450], compName: 'comp4', height: 410, background: 'blue', x: 0, y: 600 },
],
'[1441, 1920]': [
{ width: [320, 420], compName: 'comp1', height: 500, background: 'red', x: 0, y: 0 },
{ width: [400, 500], compName: 'comp2', height: 500, background: '#ccdc', x: [320, 420], y: 0 },
{ width: [400, 500], compName: 'comp3', height: 970, background: '#5E6673', x: [720, 920], y: 0 },
{ width: [400, 500], compName: 'comp4', height: 410, background: 'blue', x: 0, y: 500 },
],
'[1921, 3860]': [
{ width: [800, 1000], compName: 'comp1', height: 600, background: 'red', x: 0, y: 0 },
{ width: [500, 600], compName: 'comp2', height: 600, background: '#ccdc', x: [800, 1000], y: 0 },
{ width: [500, 600], compName: 'comp3', height: 1070, background: '#5E6673', x: [1300, 1600], y: 0 },
{ width: [500, 600], compName: 'comp4', height: 510, background: 'blue', x: 0, y: 600 },
],
},
},
{
layoutStrategy: 'strategy3',
resolution: {
'[0, 768]': [
{ width: [200, 300], compName: 'comp1', height: 500, background: 'red', x: 0, y: 0 },
{ width: [300, 400], compName: 'comp2', height: 500, background: '#ccdc', x: [200, 300], y: 0 },
{ width: [300, 400], compName: 'comp3', height: 970, background: '#5E6673', x: [500, 700], y: 0 },
{ width: [300, 400], compName: 'comp4', height: 410, background: 'blue', x: 0, y: 500 },
],
'[769, 1280]': [
{ width: [200, 300], compName: 'comp1', height: 500, background: 'red', x: 0, y: 0 },
{ width: [300, 400], compName: 'comp2', height: 500, background: '#ccdc', x: [200, 300], y: 0 },
{ width: [300, 400], compName: 'comp3', height: 970, background: '#5E6673', x: [500, 700], y: 0 },
{ width: [300, 400], compName: 'comp4', height: 410, background: 'blue', x: 0, y: 500 },
],
'[1281, 1440]': [
{ width: [280, 400], compName: 'comp1', height: 600, background: 'red', x: 0, y: 0 },
{ width: [350, 450], compName: 'comp2', height: 500, background: '#ccdc', x: [280, 400], y: 0 },
{ width: [350, 450], compName: 'comp3', height: 970, background: '#5E6673', x: [630, 850], y: 0 },
{ width: [350, 450], compName: 'comp4', height: 410, background: 'blue', x: 0, y: 600 },
],
'[1441, 1920]': [
{ width: [320, 420], compName: 'comp1', height: 500, background: 'red', x: 0, y: 0 },
{ width: [400, 500], compName: 'comp2', height: 500, background: '#ccdc', x: [320, 420], y: 0 },
{ width: [400, 500], compName: 'comp3', height: 970, background: '#5E6673', x: [720, 920], y: 0 },
{ width: [400, 500], compName: 'comp4', height: 410, background: 'blue', x: 0, y: 500 },
],
'[1921, 3860]': [
{ width: [800, 1000], compName: 'comp1', height: 600, background: 'red', x: 0, y: 0 },
{ width: [500, 600], compName: 'comp2', height: 600, background: '#ccdc', x: [800, 1000], y: 0 },
{ width: [500, 600], compName: 'comp3', height: 1070, background: '#5E6673', x: [1300, 1600], y: 0 },
{ width: [500, 600], compName: 'comp4', height: 510, background: 'blue', x: 0, y: 600 },
],
},
},
];
// 创建屏幕分辨率宽度到组件宽度区间的映射表
const screenResolutionMap: ScreenResolutionMap = {
'[1024, 1280]': {
layoutStrategy: 'strategy1',
compStyles: [
{ width: [200, 300], compName: 'comp1', height: 500, background: 'red', x: 0, y: 0 },
{ width: [300, 400], compName: 'comp2', height: 500, background: '#ccdc', x: [200, 300], y: 0 },
{ width: [300, 400], compName: 'comp3', height: 970, background: '#5E6673', x: [500, 700], y: 0 },
{ width: [300, 400], compName: 'comp4', height: 410, background: 'blue', x: 0, y: 500 },
],
},
'[1281, 1440]': {
layoutStrategy: 'strategy2',
compStyles: [
{ width: [280, 400], compName: 'comp1', height: 600, background: 'red', x: 0, y: 0 },
{ width: [350, 450], compName: 'comp2', height: 500, background: '#ccdc', x: [280, 400], y: 0 },
{ width: [350, 450], compName: 'comp3', height: 970, background: '#5E6673', x: [630, 850], y: 0 },
{ width: [350, 450], compName: 'comp4', height: 410, background: 'blue', x: 0, y: 600 },
],
},
'[1441, 1920]': {
layoutStrategy: 'strategy3',
compStyles: [
{ width: [320, 420], compName: 'comp1', height: 500, background: 'red', x: [400, 500], y: 0 },
{ width: [400, 500], compName: 'comp2', height: 500, background: '#ccdc', x: 0, y: 0 },
{ width: [400, 500], compName: 'comp3', height: 970, background: '#5E6673', x: [720, 920], y: 0 },
{ width: [400, 500], compName: 'comp4', height: 410, background: 'blue', x: 0, y: 500 },
],
},
'[1921, 3860]': {
layoutStrategy: 'strategy4',
compStyles: [
{ width: [800, 1000], compName: 'comp1', height: 600, background: 'red', x: 0, y: 0 },
{ width: [500, 600], compName: 'comp2', height: 600, background: '#ccdc', x: [800, 1000], y: 0 },
{ width: [500, 600], compName: 'comp3', height: 1070, background: '#5E6673', x: [1300, 1600], y: 0 },
{ width: [500, 600], compName: 'comp4', height: 510, background: 'blue', x: 0, y: 600 },
],
},
};
function getComponentWidthRange(screenWidth: number): ScreenResolutionMap | null {
for (const resolutionRange in screenResolutionMap) {
const [minWidth, maxWidth] = JSON.parse(resolutionRange.replace('[', '[').replace(']', ']'));
if (screenWidth >= minWidth && screenWidth <= maxWidth) {
return screenResolutionMap[resolutionRange];
}
}
return null; // 如果没有找到对应的分辨率范围则返回null
}
const getComponentWidthRange1 = (screenWidth: number, resolution: Resolution): ComponentWidthRange[] | null => {
for (const resolutionRange in resolution) {
const [minWidth, maxWidth] = JSON.parse(resolutionRange.replace('[', '[').replace(']', ']'));
if (screenWidth >= minWidth && screenWidth <= maxWidth) {
return resolution[resolutionRange];
}
}
return null; // 如果没有找到对应的分辨率范围则返回null
};
const loadComponentWidthRange = (layoutStrategy: LayoutStrategy, screenWidth: number): ComponentWidthRange[] => {
let layoutStyles: ComponentWidthRange[] | null = [];
for (let item of screenResolutionMap1) {
console.log('layoutStrategy', item.layoutStrategy);
if (item.layoutStrategy === layoutStrategy) {
layoutStyles = getComponentWidthRange1(screenWidth, item.resolution);
break;
}
}
if (!layoutStyles || layoutStyles.length === 0) {
layoutStyles = getComponentWidthRange1(screenWidth, screenResolutionMap1[0].resolution) as ComponentWidthRange[];
}
return layoutStyles;
};
const setComponentStyleByStrategy = (compStyles: ComponentWidthRange[]) => {
components.value = compStyles.map((item) => {
const compPosition = getRelativePosition(item, screenWidth.value);
return {
id: item.compName,
comp: layoutCompMap[item.compName],
x: compPosition.x,
y: item.y,
width: compPosition.width,
height: item.height,
zIndex: 1,
background: item.background,
};
});
};
/**
* 计算组件相对位置和大小的函数
* @param compStyles - 组件的样式信息
* @param screenWidth - 屏幕宽度
* @returns 组件的计算位置和大小
*/
function getRelativePosition(compStyles: ComponentWidthRange, screenWidth: number): { x: string; width: string } {
const { x, width } = compStyles;
// 解析区间值
const parseRange = (value: Coordinate): { min: number; max: number } => {
if (Array.isArray(value)) {
const [min, max] = value;
return { min, max };
}
return { min: value, max: value };
};
// 转换为基于屏幕宽度的百分比
const toPercentage = (
range: { min: number; max: number },
screenWidth: number,
): { minPercentage: number; maxPercentage: number } => {
const minPercentage = (range.min / screenWidth) * 100;
const maxPercentage = (range.max / screenWidth) * 100;
return { minPercentage, maxPercentage };
};
// 解析并计算宽度和x值
const widthRange = parseRange(width);
const xRange = parseRange(x);
const widthPercentage = toPercentage(widthRange, screenWidth);
const xPercentage = toPercentage(xRange, screenWidth);
// 假设我们取区间的中间值作为最终值
const finalWidth = ((widthPercentage.minPercentage + widthPercentage.maxPercentage) / 2).toFixed(2);
const finalX = ((xPercentage.minPercentage + xPercentage.maxPercentage) / 2).toFixed(2);
return {
x: finalX,
width: finalWidth,
};
}
onMounted(async () => {
if (container.value) {
containerWidth.value = container.value.clientWidth;
containerHeight.value = container.value.clientHeight;
}
});
const switchLayout = (layoutStrategy: LayoutStrategy) => {};
function getComponentStyle(component: ComponentState) {
return {
position: 'absolute',
left: `${component.x}%`,
top: `${component.y}px`,
width: `${component.width}%`,
height: `${component.height}px`,
zIndex: component.zIndex,
background: component.background,
transition: 'all 0.25s ease',
};
}
</script>
<style lang="scss" scoped>
.page-container {
width: 100%;
height: 100%;
position: relative;
.layout-buttons {
width: 100%;
height: 5%;
}
.components-container {
position: relative;
width: 100%;
height: 95%;
border: 1px solid #ccc;
overflow: hidden;
.component {
background-color: lightgray;
border: 1px solid #ccc;
box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.1);
transition: all 0.25s ease;
font-size: 24px;
color: #fff;
}
}
}
</style>