前端大屏项目适配:等比例缩放并居中方案(不改变中心点)

1,303 阅读2分钟

前端大屏项目等比例适配方案

最近正在完成一个大屏项目,按照设计图的尺寸,使用固定px完成了页面的整体设计,但是由于现实等多方面因素,需要放在不同的大屏上进行展示,因此采用了transform方案进行整体缩放,但是遇到不在可视屏幕居中的问题,下面就是介绍解决方案

1. 借鉴方案

image.png

点击跳转=》方案链接

采用此方案可以实现对设计稿的缩放剧中显示,但是由于大屏中有 地图模块,此方案中transform-origin: left top; 改变了地图的缩放中心,使之处于左上角,并不是在地图模块的中心进行缩放,所以此方案并不适用于我,于是我进行了改进

1.1 实现原理

  • html模块
// html结构
<div id="index" ref="appRef">
</div>

//css
#index {
  color: #d3d6dd;
  //此处的宽高就是你设计稿的尺寸
  width: 1920px;
  height: 1080px;
  //绝对定位 脱离标准流
  position: absolute;
  //分别将 div容器向左 和 向下 移动50%
  top: 50%;
  left: 50%;
  // 设置以容器左上角为中心,进行缩放移动
  transform-origin: left top;
  //再将容易往反方向分别移动50%,这样div容器 一直处于可视窗口中心
  transform: translate(-50%, -50%);
  //超出部位隐藏
  overflow: hidden;
}
  • 缩放函数
// 屏幕适配 mixin 函数

// * 默认缩放值
const scale = {
  width: '1',
  height: '1',
}

// * 设计稿尺寸(px)
const baseWidth = 1920
const baseHeight = 1080

// * 需保持的比例(默认1.77778)
const baseProportion = parseFloat((baseWidth / baseHeight).toFixed(5))

export default {
  data() {
    return {
      // * 定时函数
      drawTiming: null
    }
  },
  mounted () {
    //进入触发
    this.calcRate()
    window.addEventListener('resize', this.resize)
  },
  beforeDestroy () {
    window.removeEventListener('resize', this.resize)
  },
  methods: {
    calcRate () {
      //拿到整个页面元素
      const appRef = this.$refs["appRef"]
      //如果没有值就结束
      if (!appRef) return 
      // 当前宽高比
      const currentRate = parseFloat((window.innerWidth / window.innerHeight).toFixed(5))
      //判断:如果有值代表页面变化了
      if (appRef) {
        //判断当前宽高比例是否大于默认比例
        if (currentRate > baseProportion) {
          // 如果大于代表更宽了,就是放大了
          //那么把默认缩放的宽高改为:同比例放大
          scale.width = ((window.innerHeight * baseProportion) / baseWidth).toFixed(5)
          scale.height = (window.innerHeight / baseHeight).toFixed(5)
          console.log(scale.width,scale.height,'放大');
          //整个页面的元素样式,缩放宽高用当前同比例放大的宽高
          appRef.style.transform = `scale(${scale.width}, ${scale.height}) translate(-50%, -50%)`
        } else {
          // 如果不大于默认比例代表缩小了。
          //那么把默认缩放的宽高改为:同比例缩小
          scale.height = ((window.innerWidth / baseProportion) / baseHeight).toFixed(5)
          scale.width = (window.innerWidth / baseWidth).toFixed(5)
          console.log(scale.width,scale.height,'缩小');
          //整个页面的元素样式,缩放宽高用当前同比例放大的宽高
          appRef.style.transform = `scale(${scale.width}, ${scale.height}) translate(-50%, -50%)`
        }
      }
    },
    resize () {
      clearTimeout(this.drawTiming)
      this.drawTiming = setTimeout(() => {
        this.calcRate()
      }, 200)
    }
  },
}

2. 改进方案

  • 此方案采用计算方式,使div容器在可视窗口内剧中显示,并且并不影响视图操作中心

  • html模块

// html结构
<div id="index" ref="appRef">
</div>

//css
#index {
  text-align: left;
  color: #4449a3;
  //设计稿大小
  height: 2270px;
  width: 6720px;
  padding: 0;
  //将容器设置为 绝对定位,脱离标准流
  position: absolute;
  overflow: hidden;
}
  • 缩放函数
// 屏幕适配 mixin 函数

// * 默认缩放值
const scale = {
  width: '1',
  height: '1',
}

// * 设计稿尺寸(px)
const baseWidth = 1920
const baseHeight = 1080

// * 需保持的比例(默认1.77778)
const baseProportion = parseFloat((baseWidth / baseHeight).toFixed(5))

export default {
  data() {
    return {
      // * 定时函数
      drawTiming: null
    }
  },
  mounted () {
    //进入触发
    this.calcRate()
    window.addEventListener('resize', this.resize)
  },
  beforeDestroy () {
    window.removeEventListener('resize', this.resize)
  },
  methods: {
    calcRate() {
      //拿到整个页面元素
      const appRef = this.$refs["appRef"]
      //如果没有值就结束
      if (!appRef) return
      // 当前宽高比
      const currentRate = parseFloat((window.innerWidth / window.innerHeight).toFixed(5))
      //判断:如果有值代表页面变化了
      if (appRef) {
        //判断当前宽高比例是否大于默认比例
        if (currentRate > baseProportion) {
          // 如果大于代表更宽了,就是放大了
          //那么把默认缩放的宽高改为:同比例放大
          scale.width = ((window.innerHeight * baseProportion) / baseWidth).toFixed(5)
          scale.height = (window.innerHeight / baseHeight).toFixed(5)
          console.log(scale.width, scale.height, '放大');
          //整个页面的元素样式,缩放宽高用当前同比例放大的宽高
          appRef.style.transform = `scale(${scale.width}, ${scale.height})`
          
        } else {
          // 如果不大于默认比例代表缩小了。
          //那么把默认缩放的宽高改为:同比例缩小
          scale.height = ((window.innerWidth / baseProportion) / baseHeight).toFixed(5)
          scale.width = (window.innerWidth / baseWidth).toFixed(5)
          console.log(scale.width, scale.height, '缩小');
          //整个页面的元素样式,缩放宽高用当前同比例放大的宽高
          appRef.style.transform = `scale(${scale.width}, ${scale.height})`
        }
        //等dom节点加载完后执行
        this.$nextTick(() => {
          //appRef.getBoundingClientRect() 为获取当前div容器距离windows视图的上边距与左边距
          let appRefBoundingClientRect = appRef.getBoundingClientRect()
          // 第一种方式
          // let finallyTop = this.prevAppRefBoundingClientRect.top === 0 ? -appRefBoundingClientRect.top : (this.prevAppRefBoundingClientRect.top - appRefBoundingClientRect.top)
          // let finallyLeft = this.prevAppRefBoundingClientRect.left === 0 ? -appRefBoundingClientRect.left : (this.prevAppRefBoundingClientRect.left - appRefBoundingClientRect.left)
          // appRef.style.top = `${finallyTop}px`
          // appRef.style.left = `${finallyLeft}px`
          // this.prevAppRefBoundingClientRect.top = finallyTop
          // this.prevAppRefBoundingClientRect.left = finallyLeft
          // 第二种方式
          let finallyTop = 0;
          let finallyLeft = 0;
          if (this.isFirst) {
            // 第一次缩放偏移量
            finallyTop = appRefBoundingClientRect.top
            finallyLeft = appRefBoundingClientRect.left
            this.isFirst = false;
          } else {
            // 第二次变化后的缩放偏移量
            finallyTop = this.prevAppRefBoundingClientRect.top * (1 - scale.height) / (1 - this.scalePrev)
            finallyLeft = this.prevAppRefBoundingClientRect.left * (1 - scale.height) / (1 - this.scalePrev)
          }
          // 设置缩放元素偏移量
          appRef.style.top = `${-finallyTop}px`;
          appRef.style.left = `${-finallyLeft}px`;
          this.scalePrev = scale.width;
          this.prevAppRefBoundingClientRect.top = finallyTop
          this.prevAppRefBoundingClientRect.left = finallyLeft
        });
      }

    },
    resize () {
      clearTimeout(this.drawTiming)
      this.drawTiming = setTimeout(() => {
        this.calcRate()
      }, 200)
    }
  },
}