大屏适配

39 阅读2分钟

适配组件-RootContainer

该组件会根据当前配置(如全屏模式、自动拉伸等)调整根元素和子容器的样式。包括位置、大小以及缩放比例。主要用于响应式布局或全屏适配场景。

使用

应用页面

<template>
    <RootContainer>
      <!-- your components here -->
    </RootContainer>
</template>

<style>
.root-container {
    position: absolute;
    left: 0px;
    top: 0px;
    bottom: 0px;
    right: 0px;
    border: 0px !important;
    padding: 0px !important;
    margin: 0px !important;
}

.view-context-container {
    position: absolute;
    transform-origin: top left;
    overflow: hidden;
    border: 0px !important;
    padding: 0px !important;
    margin: 0px !important;
}
</style>

RootContainer.vue

<template>
    <div ref="rootElement" class="root-container">
        <div ref="subContainer" class="view-context-container">
            <slot></slot>
        </div>
    </div>
</template>

<script setup>
import { ref, onMounted, watch } from "vue";

const props = defineProps({
    width: { type: Number, default: 0 },
    height: { type: Number, default: 0 },
    isFull: { type: Boolean, default: false },
    fullScreen: { type: Boolean, default: true },
    autoStretch: { type: Boolean, default: true },
    autoDescale: { type: Boolean, default: false }    
});

const emit = defineEmits(['scales',])

const rootElement=ref(null)
const subContainer=ref(null)

watch(autoStretch,()=>{
    redraw()
})
watch(width,()=>{
    redraw()
})
watch(height,()=>{
    redraw()
})
watch(fullScreen,()=>{
    redraw()
})
watch(isFull,()=>{
    redraw()
})

function redraw(){
    if (!rootElement.value) return
    rootElement.value.style.position = props.fullScreen ? 'fixed' : 'absolute'
    //实际内容宽高screen.availWidth,screen.availHeight
    let width = props.width || (props.fullScreen ? screen.availWidth : rootElement.value.offsetWidth)
    let height = props.height || (props.fullScreen ? screen.availHeight : rootElement.value.offsetHeight)
    
    let w = props.fullScreen ? window.innerWidth : rootElement.value.offsetWidth,
        h = props.fullScreen ? window.innerHeight : rootElement.value.offsetHeight
        
    let rateW = w / width,
        rateH = h / height
    
    let rate = Math.min(rateW, rateH)
    let el = subContainer.value
    if (el) {
        let elW = rate < 1 || props.autoStretch ? width * rate : width,
            elH = rate < 1 || props.autoStretch ? height * rate : height
        el.style.width = width + 'px'
        el.style.height = height + 'px'
        if (rate < 1 || props.autoStretch) {
            if (props.isFull) {
                el.style.transform = `scale(${rateW}, ${rateH})`;
                emit('scales', w,height,rateW, rateH)
            }else{
                el.style.transform = 'scale(' + rate + ')'
                emit('scales', rate, rate)
            }
            traceScale({scale: rate,})
        }else{
            el.style.transform = ''
            traceScale({scale: 1,})
        }
        if (!props.isFull) {
            el.style.left = (w - elW) / 2 + 'px'
            el.style.top = (h - elH) / 2 + 'px'
        }
    }
}
function traceScale(s) {
    emit('scale', s);
    if (props.autoDescale) {
        const forEachChild = o => {
            if (o.descale && typeof o.descale === 'function') {
                o.descale(s.scale)
                return;
            } else if (o.$children) {
                o.$children.forEach(forEachChild)
            }
        }
        this.$children.forEach(forEachChild)
    }
}



onMounted(()=>{
   let bindedMethod = () => {
        redraw()
   }
   redraw()
   //window.addEventListener('resize', bindedMethod)
])

</script>

<style>
.root-container {
    position: absolute;
    left: 0px;
    top: 0px;
    bottom: 0px;
    right: 0px;
    border: 0px !important;
    padding: 0px !important;
    margin: 0px !important;
}

.view-context-container {
    position: absolute;
    transform-origin: top left;
    overflow: hidden;
    border: 0px !important;
    padding: 0px !important;
    margin: 0px !important;
}
</style>

属性

属性默认说明
fullScreentrue是否按全屏模式自动适配,默认为是,是则表示容器目标为全屏的 window,否则表示容器目标为此组件的父级 dom
width--设计的高度,默认为运行环境屏幕的高度或父级 dom 的内高
height--设计的高度,默认为运行环境屏幕的高度或父级 dom 的内高
autoStrechtrue当设计高宽小于容器目标高宽时,是否自动拉伸到
isFullfalse是否按比例让内容铺满

效果图

铺满整个屏幕。

image.png

留白边。

image.png

修改屏幕比例后。

image.png

autofit.js

这款自实用工具使用简单,并且会让页面内容始终占满整个屏幕,不留空白。

注意:当设置宽高度单位为 vw、vh 时可能会出现留白问题,在使用过程中应尽量避免使用该单位

npm安装

npm i autofit.js

应用页面

import autofit from "autofit.js";
import { onMounted, onBeforeUnmount } from "vue";

onMounted(() => {
  autofit.init({
    dh: 1080,
    dw: 1920,
    el: ".moduleNavigation",//自适应页面
    resize: true
  })
});

onBeforeUnmount(() => {
  autofit.off()
})