大屏自适应方案

大屏自适应方案

整体缩放

利用已有的工具vue3-scal等对大屏进行整体缩放,该方案很好,但不适用带有地图的项目,缩放后地图点击事件获取的坐标等会因为缩放产生偏移

局部缩放

仅针对某个容器盒子进行缩放,使用自定义指令的方案,使用起来方便快捷

typescript 复制代码
import type { App, DirectiveBinding } from 'vue';

/**
 * 缩放指令(设计稿固定1920*1080)
 * @directive 根据1920*1080设计稿自动缩放(v-scale)
 * @directive 支持多种基准点配置和缩放模式
 * @directive 默认无参数设计稿缩放,左上角基准点 会有压缩变形
 * @directive 参数ratio 固定比例缩放  value 为缩放比例
 * @directive 参数origin 按照设计稿比例,以高度比例缩放或者以宽度比例缩放  value 为 'X' 'Y' 默认是 'Y', 例如,浏览器高度小于设计稿高度 value 为 'Y'
 *
 * 修饰符 top-right top-center bottom-left bottom-right bottom-center center ,用于缩放后的盒子固定到哪个位置显示
 *
 * @example
 * v-scale - 默认设计稿缩放,左上角基准点
 * v-scale.top-right - 设计稿缩放,右上角基准点
 * v-scale:ratio="0.5" - 固定比例缩放
 * v-scale:origin.top-right="'Y'" - 无压缩缩放
 */
export function scaleDirective(app: App) {
  // 设计稿尺寸常量
  const DESIGN_WIDTH = 1920;
  const DESIGN_HEIGHT = 1080;

  // 统一的缩放指令
  app.directive('scale', {
    mounted(el: HTMLElement, binding: DirectiveBinding) {
      // 获取基准点配置
      const origin = getOriginFromBinding(binding);
      // 根据参数判断缩放模式
      if (binding.arg === 'ratio') {
        // 固定比例缩放模式
        const ratio = binding.value || 1;
        el.style.transform = `scale(${ratio})`;
        el.style.transformOrigin = origin;
        el.style.willChange = 'transform';
      } else if (binding.arg === 'origin') {
        // 无压缩变形缩放模式
        const updateScale = () => {
          const { innerWidth: vw, innerHeight: vh } = window;
          // 计算缩放比例(固定1920*1080设计稿)
          const scaleX = vw / DESIGN_WIDTH;
          const scaleY = vh / DESIGN_HEIGHT;
          const ratio = binding?.value === 'X' ? scaleX : scaleY;
          el.style.transform = `scale(${ratio})`;
          el.style.transformOrigin = origin;
          el.style.willChange = 'transform';
        };
        // 初始缩放
        updateScale();

        // 监听窗口大小变化
        window.addEventListener('resize', updateScale);

        // 存储更新函数,便于卸载时移除监听器
        (el as any)._scaleUpdate = updateScale;
      } else {
        // 默认设计稿缩放模式
        const updateScale = () => {
          const { innerWidth: vw, innerHeight: vh } = window;

          // 计算缩放比例(固定1920*1080设计稿)
          const scaleX = vw / DESIGN_WIDTH;
          const scaleY = vh / DESIGN_HEIGHT;

          // 应用缩放和基准点
          el.style.transform = `scale(${scaleX}, ${scaleY})`; // 这种缩放可能会变形
          // el.style.transform = `scale(${scaleY})`;// 保持宽高比缩放
          el.style.transformOrigin = origin;
          el.style.willChange = 'transform';
        };

        // 初始缩放
        updateScale();

        // 监听窗口大小变化
        window.addEventListener('resize', updateScale);

        // 存储更新函数,便于卸载时移除监听器
        (el as any)._scaleUpdate = updateScale;
      }
    },
    beforeUnmount(el: HTMLElement) {
      // 清理事件监听器(仅设计稿缩放模式需要)
      if ((el as any)._scaleUpdate) {
        window.removeEventListener('resize', (el as any)._scaleUpdate);
      }
    }
  });
}

/**
 * 从绑定对象获取基准点配置
 */
function getOriginFromBinding(binding: DirectiveBinding): string {
  // 从修饰符获取
  const modifiers = binding.modifiers;

  if (modifiers.topLeft || modifiers['top-left']) return 'top left';
  if (modifiers.topRight || modifiers['top-right']) return 'top right';
  if (modifiers.topCenter || modifiers['top-center']) return 'top center';
  if (modifiers.bottomLeft || modifiers['bottom-left']) return 'bottom left';
  if (modifiers.bottomRight || modifiers['bottom-right']) return 'bottom right';
  if (modifiers.bottomCenter || modifiers['bottom-center']) return 'bottom center';
  if (modifiers.center) return 'center';

  // 默认左上角
  return 'top left';
}

使用方法

typescript 复制代码
<template>
  // 这个会变形 因为缩放分别取的是高度和宽度的缩放比例
  <div v-scale.top-left class="panel-left">
    <PanelLeft />
  </div>
  // 这个不会变形
  <div v-scale:origin.top-right class="panel-right">
    <PanelRight />
  </div>
</template>
相关推荐
dyb-dev2 小时前
我是如何学习 NestJS 的
前端·nestjs·全栈
kyriewen3 小时前
重排、重绘、合成:浏览器渲染的“三兄弟”,你惹不起也躲不过
前端·javascript·浏览器
NickJiangDev3 小时前
Elpis-Core 技术解析:从零构建一个基于 Koa 的企业级 Node.js 框架内核
前端
我要让全世界知道我很低调3 小时前
来聊聊 Codex 高效编程的正确姿势
前端·程序员
NickJiangDev3 小时前
Elpis Webpack 工程化实战:Vue 多页应用的构建体系搭建
前端
米饭同学i3 小时前
GitLab CI/CD + Vue 前端 完整方案
前端
yuki_uix3 小时前
遇到前端题目,我现在会先问自己这四个问题
前端·面试
Wect3 小时前
JS 手撕:对象创建、继承全解析
前端·javascript·面试
PeterMap3 小时前
Vue.js全面解析:从入门到上手,前端新手的首选框架
前端·vue.js