大屏自适应方案

大屏自适应方案

整体缩放

利用已有的工具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>
相关推荐
陈随易5 小时前
有生之年系列,Nodejs进程管理pm2 v7.0发布
前端·后端·程序员
冰暮流星6 小时前
javascript之事件代理/事件委托
前端
@yanyu6667 小时前
登录注册功能-明文
vue.js·springboot
陈随易7 小时前
AI时代,你还在坚持手搓文章吗
前端·后端·程序员
里欧跑得慢9 小时前
17. Flutter Hero动画实现:让界面过渡更加优雅
前端·css·flutter·web
IT_陈寒9 小时前
Vue的这个响应式陷阱,我debug了一整天才爬出来
前端·人工智能·后端
kyriewen10 小时前
前端测试:别为了100%覆盖率而写测试,那是自欺欺人
前端·javascript·单元测试
去伪存真10 小时前
我自己写的第一个skills--project-core-standards
前端·agent
Data_Journal10 小时前
如何使用cURL更改User Agent
大数据·服务器·前端·javascript·数据库
竹林81810 小时前
wagmi v2 多链钱包切换:一个 Uniswap 仿盘项目让我踩了三天坑
前端·javascript