⭐️ 核心点

  1. 居中显示
  2. 计算缩放比例
  3. 监听尺寸变化

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