autofit.jsopen in new window

autofit.js是一个可以让你的PC项目自适应屏幕的工具,其原理非常简单,即在scale等比缩放的基础上,向右或向下增加了宽度或高度,以达到充满全屏的效果,使用autofit.js不会挤压、拉伸元素,它只是单纯的设置了容器的宽高。

源码
let currRenderDom = null;
let currelRectification = ''
let currelRectificationLevel = ''
let resizeListener = null;
let timer = null
let currScale = 1
let isAutofitRunnig = false
let isElRectification = false
const autofit = {
  init(options = {}, isShowInitTip = true) {
    if (isShowInitTip) {
      console.log(`%c` + `autofit.js` + ` is running`, `font-weight: bold; color: #ffb712; background:linear-gradient(-45deg, #bd34fe 50%, #47caff 50% );background: -webkit-linear-gradient( 120deg, #bd34fe 30%, #41d1ff );background-clip: text;-webkit-background-clip: text; -webkit-text-fill-color:linear-gradient( -45deg, #bd34fe 50%, #47caff 50% ); padding: 8px 12px; border-radius: 4px;`);
    }
    const {
      designWidth = 1920,
      dw = 1920,
      designHeight = 929,
      dh = 929,
      renderDom = typeof options === 'string' ? options : "#app",
      el = typeof options === 'string' ? options : "#app",
      resize = true,
      ignore = [],
      transition = 'none',
      delay = 0
    } = options;
    currRenderDom = el || renderDom;
    let dom = document.querySelector(el)
    if (!dom) {
      console.error(`autofit: '${el}' is not exist`);
      return
    }
    const style = document.createElement('style');
    const ignoreStyle = document.createElement('style');
    style.lang = 'text/css';
    ignoreStyle.lang = 'text/css';
    style.id = 'autofit-style';
    ignoreStyle.id = 'ignoreStyle';
    style.innerHTML = `
      body {
        overflow: hidden;
      }
    `;
    dom.appendChild(style);
    dom.appendChild(ignoreStyle);
    dom.style.height = `${dh || designHeight}px`;
    dom.style.width = `${dw || designWidth}px`;
    dom.style.transformOrigin = `0 0`;
    keepFit(dw || designWidth, dh || designHeight, dom, ignore);
    resizeListener = () => {
      clearTimeout(timer)
      if (delay != 0)
        timer = setTimeout(() => {
          keepFit(dw || designWidth, dh || designHeight, dom, ignore);
          isElRectification && elRectification(currelRectification, currelRectificationLevel)
        }, delay)
      else {
        keepFit(dw || designWidth, dh || designHeight, dom, ignore);
        isElRectification && elRectification(currelRectification, currelRectificationLevel)
      }
    }
    resize && window.addEventListener('resize', resizeListener)
    isAutofitRunnig = true
    setTimeout(() => {
      dom.style.transition = `${transition}s`
    });
  },
  off(el = "#app") {
    try {
      isElRectification = false
      window.removeEventListener("resize", resizeListener);
      document.querySelector('#autofit-style').remove();
      document.querySelector(currRenderDom ? currRenderDom : el).style = '';
      for (let item of document.querySelectorAll(currelRectification)) {
        item.style.width = ``
        item.style.height = ``
        item.style.transform = ``
      }
    } catch (error) {
      console.error(`autofit: Failed to remove normally`, error);
      isAutofitRunnig = false
    }
    isAutofitRunnig && console.log(`%c` + `autofit.js` + ` is off`, `font-weight: bold;color: #707070; background: #c9c9c9; padding: 8px 12px; border-radius: 4px;`);
  },

}
function elRectification(el, level = 1) {
  if (!isAutofitRunnig) {
    console.error("autofit.js:autofit has not been initialized yet")
  }
  !el && console.error(`autofit.js:bad selector: ${el}`)
  currelRectification = el
  currelRectificationLevel = level
  const currEl = document.querySelectorAll(el)
  if (currEl.length == 0) {
    console.error("autofit.js:elRectification found no element")
    return
  }
  for (let item of currEl) {
    if (!isElRectification) {
      item.originalWidth = item.clientWidth
      item.originalHeight = item.clientHeight
    }
    let rectification = currScale == 1 ? 1 : currScale * level
    item.style.width = `${item.originalWidth * rectification}px`
    item.style.height = `${item.originalHeight * rectification}px`
    item.style.transform = `scale(${1 / currScale})`
    item.style.transformOrigin = `0 0`
  }
  isElRectification = true
}
function keepFit(dw, dh, dom, ignore) {
  let clientHeight = document.documentElement.clientHeight;
  let clientWidth = document.documentElement.clientWidth;
  currScale = (clientWidth / clientHeight < dw / dh) ? (clientWidth / dw) : (clientHeight / dh)
  dom.style.height = `${clientHeight / currScale}px`;
  dom.style.width = `${clientWidth / currScale}px`;
  dom.style.transform = `scale(${currScale})`
  for (let item of ignore) {
    let itemEl = item.el || item.dom
    if (!itemEl) {
      console.error(`autofit: bad selector: ${itemEl}`)
      continue
    }
    let realScale = (item.scale ? item.scale : 1 / currScale)
    let realFontSize = realScale != currScale ? item.fontSize : 'autofit'
    let realWidth = realScale != currScale ? item.width : 'autofit'
    let realHeight = realScale != currScale ? item.height : 'autofit'
    let regex = new RegExp(`${itemEl}(\x20|{)`, 'gm')
    let isIgnored = regex.test(document.querySelector('#ignoreStyle').innerHTML);
    if (isIgnored) {
      continue
    }
    document.querySelector('#ignoreStyle').innerHTML += `\n${itemEl} {
      transform: scale(${realScale})!important;
      transform-origin: 0 0;
      width: ${realWidth}px!important;
      height: ${realHeight}px!important;
    }`;
    document.querySelector('#ignoreStyle').innerHTML += `\n${itemEl} div ,${itemEl} span,${itemEl} a,${itemEl} * {
    font-size: ${realFontSize}px;
    }`;
  }
}
export {
  elRectification
}
export default autofit;
类型
declare interface autofit {
  /**
   * 参数列表
   * 对象:
   *
   * @param {Object|String} options
   * - 传入对象,对象中的属性如下:
   * - el(可选):渲染的元素,默认是 "#app"
   * - dw(可选):设计稿的宽度,默认是 1920
   * - dh(可选):设计稿的高度,默认是 929 ,如果项目以全屏展示,则可以设置为1080
   * - resize(可选):是否监听resize事件,默认是 true
   * - ignore(可选):忽略缩放的元素(该元素将反向缩放),参数见readme.md
   * - transition(可选):过渡时间,默认是 0
   * - delay(可选):延迟,默认是 0
  */
  init(options: { el: String, dw: Number, dh: Number, resize: Boolean, ignore: Array<Object>, transition: Number, delay: Number } | String): void;
  /**
   * @param {String} id
   * 关闭autofit.js造成的影响
   *
  */
  off(id: String): void;
}
declare const autofit: autofit;

export default autofit;

使用

export default {
  mounted() {
	autofit.init({
        dh: 1080,
        dw: 1920,
        el:"#app",
        resize: true
    },false) // 可关闭控制台运行提示输出
  },
}
  • 以上使用的是默认参数,可根据实际情况调整,可选参数有
    • el:渲染的dom,默认是 "#app",必须使用id选择器
    • dw:设计稿的宽度,默认是 1920
    • dh:设计稿的高度,默认是 929 ,如果项目以全屏展示,则可以设置为1080
    • resize:是否监听resize事件,默认是 true
    • ignore:忽略缩放的元素(该元素将反向缩放),参数见readme.md
    • transition:过渡时间,默认是 0.6
    • delay:默认是 1000

忽略某些元素

autofit.init({
  ignore: [
     { 
      dom: ".gaodeMap",
     },
  ]
})

传入 ignore 以使元素不被缩放

更个性化的设置:

autofit.init({
  ignore: [
    {
      dom: ".gaodeMap", //必填
      height: 300,//可选,写数字即可(px)
      width: 300,//可选,写数字即可(px)
      scale:1.2, //可选:回放程度,基于主元素缩放后的大小
      fontSize:26 //可选,如果自定义缩放后文字大小不合适,可以在这里设置文字大小
    },
    {
        //...
    }
  ]
})

如果反向缩放后的元素大小使结构发生变化,你还可以手动传入宽高、回放程度。

elRectification

一些canvas渲染的图表也会有事件偏移,而图表不同于地图,当使用ignore时,过大的图表可能会显示不全,因此可以使用elRectification (性能上不如ignore)

如果ignore无法满足需求,可以使用 autofit.elRectification(".classNameOrId")

import { elRectification } from 'autofit.js'
<div class="G2plot"></div>
<div class="G2plot"></div>
<div class="G2plot"></div>
onMounted(() => {
  elRectification(".G2plot")
})

使用 elRectification 时,需要被矫正的元素已经挂载

关闭 autofit.js造成的影响

autofit.off()
贡献者: mankueng