持续创作,加快成长!这是我参加「日新计划 10 月更文挑战」的第N天,点击查看活动详情

一行指令完结大屏元素分辨率适配(Vue)

前言

跟着前端技能的不断发展、数据中心(中台)之类的概念的不断升级、物联网设备的更新和普及,越来越多的业主(项目)喜爱在系统中增加一个或许多个可视化大屏,用来会集的展现数据改变、方位改变等等,老板们也更喜爱称之为“态势”。

当然,作为程序员一般都不关心“老板们”的想法,只需完结项目即可。可是常常会有这样的问题:我有一个大屏的模板,可是用户的浏览器分辨率不够,或许有的有书签栏有的没有书签栏,更或许是有的全屏了有的仅仅小窗口,这样就有了代码对不同分辨率场景下的适配需求了。

1. 常见的适配计划

平时咱们使用的 web 端的适配计划,主要有以下几种:

  1. vw/vh 配合百分比完结,让元素依据窗口巨细进行自动调整
  2. fontSize 配合 rem 完结“单位宽度”的一致
  3. 依据不同的分辨率规模调整页面布局
  4. 版心布局,配合最小宽度

目前大多数屏幕适配计划的原理都是选用的以上的几种方法,可是这几种方法也有很大的坏处:浏览器文字有最小尺度!

在一般的 1080p 及以上的分辨率的屏幕中,大多数设计图的份额和显现效果都能完美复原。但假如某个系统的页面内容太多,或许浏览器部分使用的分辨率(不是物理分辨率)达不到完好显现的要求,选用上面的几种方法就有或许形成 文字的计算巨细小于浏览器的最小字体巨细,此刻就有或许由于文字宽度超出元素而导致页面款式崩溃。

版心布局配合最小宽度能够保证显现效果,可是不适合大屏项目。

2. CSS3 缩放计划

在上面的几种计划都不满意时,大家一般就会选用另外一种计划:CSS3 scale 缩放。

经过计算设计图尺度份额与实际的页面显现区域巨细,来动态调整元素的缩放份额。

个人认为这是针对小分辨率状况下保留显现内容及款式最好的一种处理方法。

当然,这种方法仍然有一些坏处:

  1. 缩放后或许会形成边际显现含糊
  2. 假如内部存在 canvas 元素,或许导致 canvas 内部的内容烘托失真
  3. 高德地图 1.x 会导致事情坐标偏移 (2.0 现已修正)

3. 封装一个缩放指令

这儿简略回忆一下 Vue 的自定义指令:经过装备自定义指令和绑定参数,在组件/元素加载、更新、毁掉等不同时期履行对应的处理逻辑。

Vue 的自定义指令包含一下几个钩子函数:

  • bind: 解析到指令绑守时履行,仅履行一次
  • inserted: 刺进父节点时履行
  • update:组件触发更新时履行
  • componentUpdated:所有组件更新完毕之后履行
  • unbind:元素解绑(毁掉)时履行,也只履行一次

这儿由于咱们只需求在初始化时绑定浏览器的 resize 事情来调整元素缩放,所以只需求装备 inserted 即可;当然,为了优化代码逻辑,削减资源耗费等状况,也需求在 unbind 阶段去撤销 resize 事情的一个回调函数。

代码如下:

// 缩放指令
import Vue from "vue";
function transformScale(el, options) {
  const { target = "width", origin = "top left" } = options;
  Vue.nextTick(() => {
    // 获取显现区域高宽
    const width = window.innerWidth;
    const height = window.innerHeight;
    el.style.transformOrigin = origin;
    if (target === "ratio") {
      const scaleX = width / CONF.width;
      const scaleY = height / CONF.height;
      el.style.transform = `scaleX(${scaleX}) scaleY(${scaleY})`;
    } else {
      let scaleProportion = 1;
      if (target === "width") {
        scaleProportion = width / CONF.width;
      }
      if (target === "height") {
        scaleProportion = height / CONF.height;
      }
      el.style.transform = `scale(${scaleProportion})`;
    }
  });
}
function inserted(el, binding) {
  const options = binding.options || { passive: true };
  const callback = () => transformScale(el, binding.value);
  window.addEventListener("resize", callback);
  callback();
  el._onResize = {
    callback,
    options
  };
}
function unbind(el) {
  if (!el._onResize) {
    return;
  }
  const { callback } = el._onResize;
  window.removeEventListener("resize", callback);
  delete el._onResize;
}
export const Scale = {
  inserted,
  unbind
};
export default Scale;

阐明:

  1. 指令接纳一个目标参数,用来指定份额计算方法和缩放定位
  2. 需求一个大局装备 CONF 目标,用来指定默许的页面尺度
  3. 为了保证页面现已加载完,能获取到 dom 元素,需求调用 Vue.nextTick
  4. 需求毁掉监听事情

整个代码其实很简略,便是经过监听 resize 事情去调整元素的缩放份额。

可是这儿我也做了一点小的装备,用来适应更多的状况:

  1. 接纳一个 target 装备,用来确认份额计算方法;能够以宽度或许高度作为一致的缩放规范,也能够分别计算
  2. 接纳 transform 的 origin 装备,保证不同方位的元素能够缩放到不同的方位,防止缩放偏移
  3. 不触及绑定元素的尺度,只需求默许尺度即可;写代码时能够直接依据设计图装备元素尺度

4. 后记

当然,这个指令不能说有多完美,仍然有许多有漏洞的当地,比方没有防抖、缩放不会改变css指定的尺度,容易出现滚动条等;并且由于之前的项目中还触及到许多图表、地图,也常常导致一些显现问题,所以后边有增加了一些新的指令,可是分辨率适配这个问题仍是要依据实际状况来确认具体的计划。