⭐️ 核心点
- 居中显示
- CSS 绝对定位:将目标元素的
position
设置为 absolute
,并依次设置 left: 50%
和 top: 50%
。这将把目标元素的左上角定位在父容器的中心。
transform: translate(-50%, -50%)
:由于仅通过 left
和 top
定位会使左上角对齐到中心,而不是元素自身居中,因此利用 transform: translate(-50%, -50%)
将元素从其中心点向左上角偏移自身宽高的 50%。这就使得元素的中心与父容器的中心完全重合,实现居中效果。
- 计算缩放比例
- 计算
scaleX
和 scaleY
:分别计算容器宽度与设计稿宽度之比(scaleX = containerWidth / dW
)和容器高度与设计稿高度之比(scaleY = containerHeight / dH
)。
- 选择缩放方式
- 如果希望保持设计稿的宽高比(
isRatio
为 true
),取 scaleX
和 scaleY
中的较小值作为统一的缩放比例,这样即使是非等比例的屏幕也能保持内容的完整性,防止内容溢出。
- 如果可以拉伸内容以完全填充容器(
isRatio
为 false
),则分别使用 scaleX
和 scaleY
进行宽高缩放。这样内容会被拉伸以适应容器的宽高。
- 监听尺寸变化
- 为了在窗口调整时保持适配效果,代码监听了
resize
事件:
- 监听
resize
事件:在 onMounted
生命周期中通过 window.addEventListener('resize', onResize)
添加 resize
事件监听器。每当窗口尺寸变化时都会触发 onResize
方法。
- 重新计算缩放比例:在
onResize
中调用 setScale
函数,实时重新计算并应用缩放比例,以确保窗口尺寸变化时内容始终保持适配效果。
- 清理监听器:在
onUnmounted
中移除 resize
监听器,防止内存泄漏。
hooks
import { ref, onMounted, onUnmounted, watch, Ref } from 'vue';
interface IOptions {
el: Ref<HTMLElement | null> | HTMLElement | string;
dW: number;
dH: number;
parentEl?: Ref<HTMLElement | null> | HTMLElement | string;
isRatio?: boolean;
}
export function useBigScreen({
el,
dW,
dH,
parentEl = document.body,
isRatio = true
}: IOptions) {
const scale = ref(1);
const getElement = (element: HTMLElement | Ref<HTMLElement | null> | string | null): HTMLElement | null => {
if (element instanceof HTMLElement) return element;
if (typeof element === 'string') return document.querySelector(element);
return element?.value ?? null;
}
const setTargetElementStyle = (element: HTMLElement) => {
element.style.position = 'absolute';
element.style.left = '50%';
element.style.top = '50%';
element.style.width = +dW + 'px';
element.style.height = +dH + 'px';
}
const setScale = () => {
const targetEl = getElement(el);
const containerEl = parentEl ? getElement(parentEl) : document.body;
if (!targetEl || !containerEl) {
console.log('目标元素或者目标元素的父元素没有找到.');
return;
}
setTargetElementStyle(targetEl);
const containerWidth = containerEl.clientWidth;
const containerHeight = containerEl.clientHeight;
let scaleX = containerWidth / dW;
let scaleY = containerHeight / dH;
if (isRatio) {
// 保持宽高比,按最长边进行缩放
const scaleValue = Math.min(scaleX, scaleY);
targetEl.style.transform = `translate(-50%, -50%) scale(${scaleValue})`;
} else {
// 不保持宽高比,分别按宽高拉伸
targetEl.style.transform = `translate(-50%, -50%) scale(${scaleX}, ${scaleY})`;
}
}
const onResize = () => {
setScale();
}
onMounted(() => {
setScale();
window.addEventListener('resize', onResize);
});
onUnmounted(() => {
window.removeEventListener('resize', onResize);
});
// 如果 el 或 parentEl 动态改变时重新计算
watch([() => el, () => parentEl], () => {
setScale();
});
return { scale };
}
使用
<template>
<div ref="myScreen" class="monitor-screen"></div>
</template>
<script setup lang="ts">
import { onMounted, reactive, ref } from "vue";
import { useBigScreen } from "../../hooks/useBigScreen";
const myScreen = ref<HTMLElement | null>(null);
useBigScreen({
el: myScreen, // 目标 DOM
dW: 1920, // 设计稿宽度
dH: 1080, // 设计稿高度
parentEl: undefined, // 默认基于 body 进行全屏适配
isRatio: true, // 保持设计稿宽高比
});
</script>
示例
big-screen