一个vue2中大屏适配的组件

文章介绍了VScaleScreen组件,它用于封装公共屏幕组件,实现自适应屏幕大小、自动缩放以及利用mutationobserver处理屏幕尺寸变化。组件提供了宽度、高度、全屏模式等配置选项,并能动态调整布局以适应不同设备和窗口大小。
摘要由CSDN通过智能技术生成

1.封装公共组件 scale-screen

 


<template>
  <!-- <section class="screen-box" :style="boxStyle"> -->
  <div class="screen-wrapper" ref="screenWrapper" :style="wrapperStyle">
    <slot></slot>
  </div>
  <!-- </section> -->
</template>
  <script>
function debounce(fn, delay) {
  let timer = null;
  return function (...args) {
    timer = setTimeout(
      () => {
        typeof fn === "function" && fn.apply(null, args);
        clearTimeout(timer);
      },
      delay > 0 ? delay : 100
    );
  };
}

export default {
  name: "VScaleScreen",
  props: {
    width: {
      type: [String, Number],
      default: 1920,
    },
    height: {
      type: [String, Number],
      default: 1080,
    },
    fullScreen: {
      type: Boolean,
      default: false,
    },
    autoScale: {
      type: [Object, Boolean],
      default: true,
    },
    selfAdaption: {
      type: Boolean,
      default: true,
    },
    delay: {
      type: Number,
      default: 500,
    },
    boxStyle: {
      type: Object,
      default: () => ({}),
    },
    wrapperStyle: {
      type: Object,
      default: () => ({}),
    },
  },
  data() {
    return {
      currentWidth: 0,
      currentHeight: 0,
      originalWidth: 0,
      originalHeight: 0,
      onResize: null,
      observer: null,
    };
  },
  watch: {
    selfAdaption(val) {
      if (val) {
        this.resize();
        this.addListener();
      } else {
        this.clearListener();
        this.clearStyle();
      }
    },
  },
  computed: {
    screenWrapper() {
      return this.$refs["screenWrapper"];
    },
  },
  methods: {
    initSize() {
      return new Promise((resolve, reject) => {
        // console.log("初始化样式");
        //给父元素设置 overflow:hidden
        this.screenWrapper.parentNode.style.overflow = "hidden";
        this.screenWrapper.parentNode.scrollLeft = 0;
        this.screenWrapper.parentNode.scrollTop = 0;

        this.$nextTick(() => {
          // region 获取大屏真实尺寸
          if (this.width && this.height) {
            this.currentWidth = this.width;
            this.currentHeight = this.height;
          } else {
            this.currentWidth = this.screenWrapper.clientWidth;
            this.currentHeight = this.screenWrapper.clientHeight;
          }
          // endregion
          // region 获取画布尺寸
          if (!this.originalHeight || !this.originalWidth) {
            this.originalWidth = window.screen.width;
            this.originalHeight = window.screen.height;
          }
          // endregion
          resolve();
        });
      });
    },
    updateSize() {
      if (this.currentWidth && this.currentHeight) {
        this.screenWrapper.style.width = `${this.currentWidth}px`;
        this.screenWrapper.style.height = `${this.currentHeight}px`;
      } else {
        this.screenWrapper.style.width = `${this.originalWidth}px`;
        this.screenWrapper.style.height = `${this.originalHeight}px`;
      }
    },
    handleAutoScale(scale) {
      if (!this.autoScale) return;
      const screenWrapper = this.screenWrapper;
      const domWidth = screenWrapper.clientWidth;
      const domHeight = screenWrapper.clientHeight;
      const currentWidth = document.body.clientWidth;
      const currentHeight = document.body.clientHeight;
      screenWrapper.style.transform = `scale(${scale},${scale}) `;
      let mx = Math.max((currentWidth - domWidth * scale) / 2, 0);
      let my = Math.max((currentHeight - domHeight * scale) / 2, 0);
      if (typeof this.autoScale === "object") {
        // @ts-ignore
        !this.autoScale.x && (mx = 0);
        // @ts-ignore
        !this.autoScale.y && (my = 0);
      }
      this.screenWrapper.style.margin = `${my}px ${mx}px`;
    },
    updateScale() {
      const screenWrapper = this.screenWrapper;
      // 获取真实视口尺寸
      const currentWidth = document.body.clientWidth;
      const currentHeight = document.body.clientHeight;
      // 获取大屏最终的宽高onResize
      const realWidth = this.currentWidth || this.originalWidth;
      const realHeight = this.currentHeight || this.originalHeight;
      // 计算缩放比例
      const widthScale = currentWidth / realWidth;
      const heightScale = currentHeight / realHeight;
      // console.log({currentWidth, currentHeight,realWidth,realHeight});

      // 若要铺满全屏,则按照各自比例缩放
      if (this.fullScreen) {
        screenWrapper.style.transform = `scale(${widthScale},${heightScale})`;
        return false;
      }
      // 按照宽高最小比例进行缩放
      const scale = Math.min(widthScale, heightScale);
      this.handleAutoScale(scale);
    },
    initMutationObserver() {
      const screenWrapper = this.screenWrapper;
      const observer = (this.observer = new MutationObserver(() => {
        this.onResize();
      }));

      observer.observe(screenWrapper, {
        attributes: true,
        attributeFilter: ["style"],
        attributeOldValue: true,
      });
    },
    clearListener() {
      window.removeEventListener("resize", this.onResize);
    },
    addListener() {
      window.addEventListener("resize", this.onResize);
    },
    clearStyle() {
      // console.log("清除");
      const screenWrapper = this.screenWrapper;
      screenWrapper.parentNode.style.overflow = "auto";

      screenWrapper.style = "";
    },
    async resize() {
      if (!this.selfAdaption) {
        return;
      }
      await this.initSize();
      this.updateSize();
      this.updateScale();
    },
  },
  mounted() {
    this.onResize = debounce(() => {
      this.resize();
    }, this.delay);
    this.$nextTick(() => {
      if (this.selfAdaption) {
        this.resize();
        this.addListener();
      }
    });
  },
  beforeDestroy() {
    this.clearListener();
    // this.observer.disconnect()
  },
};
//
</script>
  
  <style scoped>
.screen-box {
  overflow: hidden;
  background-size: 100% 100%;
  background: #000;
  width: 100vw;
  height: 100vh;
}

.screen-wrapper {
  transition-property: all;
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
  transition-duration: 500ms;
  position: relative;
  overflow: hidden;
  z-index: 100;
  transform-origin: left top;
}
</style>
  

2.在需要用到的地方引入即可

 

 

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值