手摸手教你用vue3写可视化的屏幕适配容器组件

3,729 阅读2分钟

前言:

写可视化大屏项目难免会考虑到屏幕适配的难题,如果有一个适配各种屏幕的基础容器组件处理这个事情,组件插槽内我就安心写业务,岂不是很香,这篇文章手把手教你如何写一个vue3的大屏自适应容器组件.

这篇文章编写的组件可以用我上一篇写的文章手摸手教你用Vue3+Typescript+Rollup+Tailwinds打造插拔式的业务组件库来打包,这篇文章是写具体组件,相互独立~

效果展示: http://8.210.196.94:8082 中的自适应屏幕容器
ps:服务器略渣,请耐心等待~

组件特点

特点简述
1.自动监听浏览器窗口变化,动态计算出高宽比,无视页面放大缩小
2.适用于各种屏幕,常用作项目最外层基础容器
3.突破浏览器中font-size最小12px限制

话不多说直接上代码

注释写的很详细

// Conatiner.vue
<template>
  <div id="well-container" :ref="refName">
    <template v-if="ready">
      <slot></slot>
    </template>
  </div>
</template>

<script>
import {ref,  onMounted, onUnmounted, nextTick, defineComponent} from 'vue'
import {debounce} from '.utils'

export default defineComponent({
  name: 'WContainer',
  props: {
    options: Object
  },
  setup(ctx) {
    const refName = 'WellContainer'
    // 屏幕宽度
    const width = ref(0)
    // 屏幕高度
    const height = ref(0)
    // 原始屏幕宽度
    const originalWidth = ref(0)
    // 原始屏幕高度
    const originalHeight = ref(0)
    // 控制显示
    const ready = ref(false)
    /*
    * dom:well-container的dom
    * observer: window.MutationObserver(Bom实例)监听dom改变
    */
    let  dom, observer

    //设置初始值
    const initSize = () => {
      return new Promise((resolve) => {
        nextTick(() => {
          dom = document.getElementById('well-container')
          // 获取大屏的传入尺寸
          if (ctx.options && ctx.options.width && ctx.options.height) {
            //传入宽高
            width.value = ctx.options.width
            height.value = ctx.options.height
          } else {
            //可见宽高
            width.value = dom.clientWidth
            height.value = dom.clientHeight
          }
          // 获取画布尺寸
          if (!originalWidth.value || !originalHeight.value) {
            //屏幕分辨率宽高
            originalWidth.value = window.screen.width
            originalHeight.value = window.screen.height
          }
          resolve()
        })
      })
    }

    const updateSize = () => {
      if (width.value && height.value) {
        dom.style.width = `${width.value}px`
        dom.style.height = `${height.value}px`
      } else {
        dom.style.width = `${originalWidth.value}px`
        dom.style.height = `${originalHeight.value}px`
      }
    }

    const updateScale = () => {
      // 获取真实的视口尺寸
      const currentWidth = document.body.clientWidth
      const currentHeight = document.body.clientHeight
      // 获取大屏最终的宽高
      const realWidth = width.value || originalWidth.value
      const realHeight = height.value || originalHeight.value
      // console.log(currentWidth, currentHeight)
      // 缩放比例  = 分辨率宽高 / 传入宽高(可视宽高)
      const widthScale = currentWidth / realWidth
      const heightScale = currentHeight / realHeight
      //如果dom存在,就按照比例缩放
      dom && (dom.style.transform = `scale(${widthScale}, ${heightScale})`)
    }

    //重置缩放比例
    const onResize = async () => {
      await initSize()
      updateScale()
    }

    const initMutationObserver = () => {
      //监听元素属性变化
      const MutationObserver = window.MutationObserver
      //如果变化,就用onResize重置屏幕所缩放比例
      observer = new MutationObserver(onResize)
      observer.observe(dom, {
        attributes: true,
        attributeFilter: ['style'],
        attributeOldValue: true
      })
    }
    //移除监听属性
    const removeMutationObserver = () => {
      if (observer) {
        observer.disconnect()
        observer.takeRecords()
        observer = null
      }
    }
    //
    onMounted(async () => {
      ready.value = false

      await initSize()
      updateSize()
      updateScale()
      window.addEventListener('resize', debounce(100, onResize))
      initMutationObserver()
      ready.value = true
    })

    onUnmounted(() => {
      window.removeEventListener('resize', onResize)
      removeMutationObserver()
    })

    return {
      refName,
      ready
    }
  }
})
</script>

<style lang="scss">
#well-container {
  position: fixed;
  top: 0;
  left: 0;
  overflow: hidden;
  transform-origin: left top;
  z-index: 999;
}
</style>

依赖文件utils

重置缩放比例的节流防抖

    // 防抖截流
export function debounce(delay, callback) {
    let task;
    return function () {
        clearTimeout(task);
        task = setTimeout(() => {
            callback.apply(this, arguments);
        }, delay);
    };

}


大屏自适应的基础容器组件大功告成,下面就是使用我们组件

组件的使用

<w-container :options="{width:3840,height:2160}">
    <!--  编写具体的大屏项目就可以,子元素会更具缩放比例自动适配~~~-->
</w-container>

核心原理

    1.const widthScale = currentWidth / realWidth
    2.const heightScale = currentHeight / realHeight
    3.dom.style.transform = `scale(${widthScale}, ${heightScale})`

1.宽度度缩放比例(widthScale) = 分辨率宽高 / props传入宽高(可视宽高)
2.高度缩放比例(heightScale) = 分辨率高度 / props传入高度(可视高度)
3.通过transform的属性缩放容器的大小

最后

惊喜的一点是用手机阅览也不会错乱布局

如果这篇文章帮助到了你,请给点个赞或者评论哦

上一篇: 手摸手教你用Vue3+Typescript+Rollup+Tailwinds打造插拔式的业务组件库