Front-end large screen adaptation solution

Screen Adaptation Size:

① Indoor P1.5 full-color screen: size 3.84 * 2.5 = 9.6 square meters; resolution 2064 * 1290
② Display size 98inch, resolution 3840 * 2160, display ratio 16: 9

Adaptation by 16:9

1. Convert px to rem:

Use the unified conversion plugin flexible.js

(function(win, lib) {
  let doc = win.document
  let docEl = doc.documentElement
  let metaEl = doc.querySelector('meta[name="viewport"]')
  let flexibleEl = doc.querySelector('meta[name="flexible"]')
  let dpr = 0
  let scale = 0
  let tid
  let flexible = lib.flexible || (lib.flexible = {})

  if (metaEl) {
    console.warn('将根据已有的meta标签来设置缩放比例')
    let match = metaEl.getAttribute('content').match(/initial\-scale=([\d\.]+)/)
    if (match) {
      scale = parseFloat(match[1])
      dpr = parseInt(1 / scale)
    }
  } else if (flexibleEl) {
    let content = flexibleEl.getAttribute('content')
    if (content) {
      let initialDpr = content.match(/initial\-dpr=([\d\.]+)/)
      let maximumDpr = content.match(/maximum\-dpr=([\d\.]+)/)
      if (initialDpr) {
        dpr = parseFloat(initialDpr[1])
        scale = parseFloat((1 / dpr).toFixed(2))
      }
      if (maximumDpr) {
        dpr = parseFloat(maximumDpr[1])
        scale = parseFloat((1 / dpr).toFixed(2))
      }
    }
  }

  if (!dpr && !scale) {
    let isAndroid = win.navigator.appVersion.match(/android/gi)
    let isIPhone = win.navigator.appVersion.match(/iphone/gi)
    let devicePixelRatio = win.devicePixelRatio
    if (isIPhone) {
      // iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
      if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
        dpr = 3
      } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)) {
        dpr = 2
      } else {
        dpr = 1
      }
    } else {
      // 其他设备下,仍旧使用1倍的方案
      dpr = 1
    }
    scale = 1 / dpr
  }

  docEl.setAttribute('data-dpr', dpr)
  if (!metaEl) {
    metaEl = doc.createElement('meta')
    metaEl.setAttribute('name', 'viewport')
    metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no')
    if (docEl.firstElementChild) {
      docEl.firstElementChild.appendChild(metaEl)
    } else {
      let wrap = doc.createElement('div')
      wrap.appendChild(metaEl)
      doc.write(wrap.innerHTML)
    }
  }

  function refreshRem() {
    let width = docEl.getBoundingClientRect().width
    if (width / dpr > 540) {
      width = width * dpr
    }
    let rem = width / 10
    docEl.style.fontSize = rem + 'px'
    flexible.rem = win.rem = rem
  }

  win.addEventListener('resize', function() {
    clearTimeout(tid)
    tid = setTimeout(refreshRem, 300)
  }, false)
  win.addEventListener('pageshow', function(e) {
    if (e.persisted) {
      clearTimeout(tid)
      tid = setTimeout(refreshRem, 300)
    }
  }, false)

  if (doc.readyState === 'complete') {
    doc.body.style.fontSize = 12 * dpr + 'px'
  } else {
    doc.addEventListener('DOMContentLoaded', function(e) {
      doc.body.style.fontSize = 12 * dpr + 'px'
    }, false)
  }


  refreshRem()

  flexible.dpr = win.dpr = dpr
  flexible.refreshRem = refreshRem
  flexible.rem2px = function(d) {
    let val = parseFloat(d) * this.rem
    if (typeof d === 'string' && d.match(/rem$/)) {
      val += 'px'
    }
    return val
  }
  flexible.px2rem = function(d) {
    let val = parseFloat(d) / this.rem
    if (typeof d === 'string' && d.match(/px$/)) {
      val += 'rem'
    }
    return val
  }

})(window, window['lib'] || (window['lib'] = {}))

Install px2rem-loader

npm install px2rem-loader --save-dev

Configure px2rem-loader

vue-cli 2.x
is in build/utils.js, find exports.cssLoaders

const px2remLoader = {
    loader: 'px2rem-loader',
    options: {
       // 以设计稿1920为例, 1920 / 10 = 192.0
      remUnit: 192.0
    }
  }
继续找到generateLoaders中的loaders配置,作出如下配置:
// 注释掉这一行
// const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]
// 修改为
    const loaders = options.usePostCSS ? [cssLoader, postcssLoader,px2remLoader] : [cssLoader,px2remLoader]

vue-cli 3.x
vue.config.js

module.exports = {
    css: {
        loaderOptions: {
            css: {},
            postcss: {
                plugins: [
                    require('postcss-px2rem')({
                        // 以设计稿1920为例, 1920 / 10 = 192.0
                        remUnit: 192.0
                    }),
                ]
            }
        }
    },
}

Note:
1. The style of px cannot be written inline style (style), only class
2. The width and height of the outermost layer can be 100vw, 100vh. The internal module depends on the situation (percentage or px can be used), it is recommended to use vh highly.
3. The premise of adaptive screen needs to ensure that the final large screen size is completely adapted, and it is compatible with other device screens.
4. The size of the text and the size of the picture cannot be adapted by default. You must set the width, height, and text size, otherwise the rem cannot be converted. Switching the large screen size will not change the size.

2. Echarts adaptation scheme:

1. The size of the canvas can be set as a percentage, so that the canvas changes with the parent view, and px can also be set.
2. Echarts text size and layout position can be converted by function (echartsSize).

/* Echarts图表字体、间距自适应  */
// 以设计稿1920为例
export const echartsSize = (size, defalteWidth = 1920) => {
  let clientWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth
  if (!clientWidth) return size
  let scale = (clientWidth / defalteWidth)
  return Number((size * scale).toFixed(3))
}
// 将其挂载到原型链上,方便全局可使用
Vue.prototype.echartsSize = echartsSize

使用说明:
fontSize: this.echartsSize(12),
radius: [this.echartsSize(30), this.echartsSize(140)],

3. px to vh vw

Use @mixin @include

$defalteWidth: 1920;  // 设计尺寸
$defalteHeight: 1080;
$widthScale: 100/$defalteWidth;
$heightScale: 100/$defalteHeight;
@mixin height($radius) {
    height:($radius*heightScale)*1vh;
  }
  @mixin line-height($radius) {
    // line-height: $radius;
    line-height:($radius*heightScale)*1vh;
  }
  @mixin width($radius) {
    // width: $radius;
    width:($radius*defalteWidth)*1vw;
  }
  @mixin p-l($radius) {
    // padding-left: $radius;
    padding-left:($radius*defalteWidth)*1vw;
  }
  @mixin p-r($radius) {
    // padding-right: $radius;
    padding-right:($radius*defalteWidth)*1vw;
  }
  @mixin p-t($radius) {
    // padding-top: $radius;
    padding-top:($radius*defalteWidth)*1vh;
  }
  @mixin p-b($radius) {
    // padding-bottom: $radius;
    padding-bottom:($radius*defalteWidth)*1vh;
  }
  @mixin m-l($radius) {
    // margin-left: $radius;
     margin-left:($radius*defalteWidth)*1vw;
  }
  @mixin m-r($radius) {
    // margin-right: $radius;
    margin-right:($radius*defalteWidth)*1vw;
  }
  @mixin m-t($radius) {
    // margin-top: $radius;
    margin-top:($radius*defalteWidth)*1vh;
  }
  @mixin m-b($radius) {
    // margin-bottom: $radius;
    margin-bottom:($radius*defalteWidth)*1vh;
  }
  @mixin top($radius) {
    // margin-bottom: $radius;
    top:($radius*defalteWidth)*1vh;
  }
  @mixin bottom($radius) {
    // margin-bottom: $radius;
    bottom:($radius*defalteWidth)*1vh;
  }
  @mixin right($radius) {
    // margin-bottom: $radius;
    right:($radius*defalteWidth)*1vh;
  }
  @mixin left($radius) {
    // margin-bottom: $radius;
    left:($radius*defalteWidth)*1vh;
  }
 // 自行添加需要的属性

@include height(240px);

Suggestions for use
vw/vh can be used for width and height, but the minimum width and height need to be set to avoid small screen compression and scheduling misalignment.
Use rem
Echarts icon size to convert using echartsSize

Guess you like

Origin blog.csdn.net/wang15180138572/article/details/128815868