同事说大屏适配方案能用就行,我偏不!

2,742 阅读4分钟

前言

做了好几个可视化大屏的项目,可惜在适配方案上一直没能有一个良好的开发体验和统一的书写规范,期间也尝试过很多的大屏可视化方案, 简单说下目前所用过的方案吧:

历史方案

最简单的css媒体查询

就是写起来比较累, 改起来更累

@media only screen and (max-width: 1000px) { .box { width: 720px; } }

使用 scss 等预处理语言, 通过 function 计算。

  • 能针对性适配设备,但是很难设备通用。
$vw_base: 3840;
$vh_base: 2160;

// 计算视口宽度,vw()中的参数,直接传像素值
@function vw($px) {
    @return ($px / $vw_base) * 100vw;
}
// 例子
.box{
    height: vw(100)
}

postcss + rem/vw

这两种方案好处是开发时比较自然,做好基础配置后直接写px就行。

  • 生成的最终代码是以rem或vw为单位的,不方便调试。

通过scale 计算

主要就是利用 css3 的 scale 对元素做等比缩放达到适配的目的。

  • 暴力整体缩放会出现留白的情况,除非F11全屏查看
  • 单个 div 需要手动去设置 transform-origin, 且位置不好控制

这些方案都可以达到目的,但我觉得只是能用,应该有更好的方式。

碰到的一些痛点

  • 设计稿屏幕分辨率非常大,通过chrome模拟之后100%缩放模式下只能看到左上角一部分的内容,开发右侧时就需要通过一些迂回的方式。
  • 无法自由放大查看细节,无法确定是否足够还原。

要不要尝试下新的方案

为了解决这些问题,我写了一款大屏适配插件:

通过 vue 指令的方式为元素添加屏幕自适应功能。

特点

  • 使用简单,一行指令即可满足基本功能。
  • 支持整屏自由拖拽、缩放,帮助开发者查看细节和死角。
  • 支持出场入场动画,切换时过渡更自然。
  • 支持 zoom 模式和 scale 两种模式。
  • 对布局无侵入,不破坏原始 dom 结构。

预览

安装

使用您选择的包管理器进行安装。

#yarn
yarn add vue-fit-next

#npm
npm install vue-fit-next

#pnpm
pnpm add vue-fit-next

基本使用

// main.ts
import Fit from 'vue-fit-next'

app
  .use(
    Fit({
      width: 3840, // 设计稿宽度
      height: 2160, // 设计稿高度
      mode: 'scale' // 可选, 支持 scale 和 zoom 两种方案,默认为 scale
    })
  )
  .mount('#app')
<div v-fit>
  添加 `v-fit` 指令的元素会根据屏幕尺寸和预设的设计稿尺寸进行缩放
</div>

使用 zoom 模式

zoom 模式采用浏览器非标准属性进行缩放。

缺点:

  1. FireFox 不支持! (不过大屏展示大多数不用考虑浏览器环境,可以直接上chrome)
  2. 渲染的性能存在差异,zoom会引起一整个页面的重新渲染。 (个人觉得大屏几乎是一次性渲染做展示,倒也不用顾虑太多)

优点:

配合 v-fit 食用更简单,完全不用考虑 v-fit 定义的布局概念,直接使用 css 就能完成你想要的布局和适配。

使用 scale 模式

scale 模式是采用的 css 的 scale 属性进行缩放。

scale 模式配合 v-fit 使用前需要了解一些 v-fit 对布局增加的属性概念:

布局方式
  • 可通过给指令添加参数来调整元素的缩放中心,

      <div v-fit:left>leftTop 的简写, 左上角</div>
      <div v-fit:center>centerTop 的简写, 顶部位置且水平居中</div>
      <div v-fit:right>rightTop 的简写, 右上角</div>
    
      大多数场景用上面3个布局属性就够用了。当然我们也提供了其他几个位置的属性:
    
      <div v-fit:leftCenter>靠左,垂直居中</div>
      <div v-fit:centerCenter>水平垂直居中</div>
      <div v-fit:rightCenter>靠右,垂直居中</div>
    
      <div v-fit:leftBottom>左下角</div>
      <div v-fit:centerBottom>底部位置且水平居中</div>
      <div v-fit:rightBottom>右下角</div>
    
    如果把一个屏幕划分成9个小区域的话,那么 1-9 对应的关系如下:
    
           -----------------------------------------
          |            |              |             |
          |    left    |    center    |    right    |
          |            |              |             |
           -----------------------------------------
          |            |              |             |
          | leftCenter | centerCenter | rightCenter |
          |            |              |             |
           -----------------------------------------
          |            |              |             |
          | leftBottom | centerBottom | rightBottom |
          |            |               |            |
           -----------------------------------------
    

    再配合 css 的 top、right、bottom、left 等可以进行更细微的位置偏移

  • 使用 origin 属性代替上面:left的写法

<div v-fit="{origin: 'left'}"></div>

拖拽和缩放

  • 按住空格键的同时鼠标点击界面即可进行拖动。
  • 按住 ctrl 键的同时滚动鼠标,实现整体缩放及位置偏移。
  • 双击 space 键进行位置复原。

入场和出场动画

动画列表

目前内置了以下几种出/入动画

  • slideInLeft | slideInRight
  • slideOutLeft | slideOutRight
  • slideInUp | slideInDown
  • slideOutUp | slideOutDown

使用方式

  1. 全局配置(可选)
// main.ts
import Fit from 'vue-fit-next'
app
  .use(
    Fit({
      width: 3840, // 设计稿宽度
      height: 2160, // 设计稿高度
      animate: {
        enter: { // 入场
          duration: 600, // 过渡时长
          delay: 0 // 动画延迟
        },
        leave: {
          duration: 600, // 过渡时长
          delay: 0 // 动画延迟
        },
      },
    })
  )
  .mount('#app')

全局默认值:

const animate = {
  enter: {
    name: null,
    duration: 500,
    delay: 0,
  },
  leave: {
    name: null,
    duration: 500,
    delay: 0,
  },
}
  1. 单个组件指令
<div
  v-fit="{
    origin: 'left',
    animate: {
      enter: {
        name: 'slideInLeft',
        duration: 800,
      },
      leave: 'slideOutLeft',   // 也可以直接提供动画名称的方式简写
    },
  }"
>
</div>

enterleave 可以直接简写成动画名称,durationdelay则从全局继承,也可以单个组件覆盖全局。

注意:

如果需要出场动画,需按要求给根元素添加Transition组件

第一步:

import { leave } from 'vue-fit-next'

第二步:

Transition 包裹组件即可

<Transition mode="out-in" @leave="leave">
  <div v-if="show" class="box">
    <div
      v-fit="{
        origin: 'left',
        animate: {
          enter: 'slideInLeft',
          leave: 'slideOutLeft',
        },
      }"
    >
      left-1
    </div>

    <div
      v-fit:right="{
        animate: {
          enter: 'slideInRight',
          leave: 'slideOutRight',
        },
      }"
    >
      right-1
    </div>
  </div>
</Transition>