全屏组件FullScreenContainer目录结构
image.png

index.vue

<template>
  <div id="sp-full-screen-container" :ref="ref">
    <div id="sp-full-screen-container-content">
      <template v-if="ready">
        <slot></slot>
      </template>
    </div>
  </div>
</template>
<script>
import autoResize from "./mixin/autoResize.js";

export default {
  name: "FullScreenContainer",
  mixins: [autoResize],
  props: {
    //设计稿画布大小(单位:px)
    canvasWidth: {
      type: Number,
      default: 0,
    },
    canvasHeight: {
      type: Number,
      default: 0,
    },
  },
  data() {
    return {
      ref: "sp-full-screen-container",
      ready: false,
      scale: 1.0,
    };
  },
  methods: {
    afterAutoResizeMixinInit() {
      const { initConfig, setContainerScale } = this;

      initConfig();

      setContainerScale();

      this.ready = true;
    },
    initConfig() {
      const { dom, canvasWidth, canvasHeight } = this;
      // debugger;
      if (canvasWidth > 0 && canvasHeight > 0) {
        dom.style.cssText = `width: ${canvasWidth}px; height: ${canvasHeight}px;`;
      }
    },
    setContainerScale() {
      const { width, height, dom } = this;
      const { innerWidth, innerHeight } = window;

      let top = 0;
      let left = 0;
      let scale = 0;
      // 设置缩放率并居中
      if (innerWidth / innerHeight > width / height) {
        // 上下居中
        scale = innerHeight / height;
        left = (innerWidth - scale * 1920) / 2;
      } else {
        // 左右居中
        scale = innerWidth / width;
        // top = 0;
      }

      // 避免死循环
      if (this.scale == scale) {
        dom.style.left = `${left}px`;
        dom.style.top = `${top}px`;
        dom.style.transform = `scale(${scale})`;
        return;
      }
      this.scale = scale;

      if (width == 0 || height == 0) {
        dom.style.left = `${left}px`;
        dom.style.top = `${top}px`;
        dom.style.transform = `scale(${scale})`;
      } else {
        // 降低DOM操作次数
        dom.style.cssText = `width: ${width}px; height: ${height}px; left: ${left}px; top: ${top}px; transform: scale(${scale});`;
      }
    },
    onResize() {
      const { setContainerScale } = this;

      setContainerScale();
    },
  },
};
</script>

<style lang="less">
#sp-full-screen-container {
  position: fixed;
  top: 0px;
  left: 0px;
  overflow: visible;
  -webkit-transform-origin: left top;
  transform-origin: left top;
  z-index: 999;
  display: flex;
  justify-content: center;
  align-items: center;
}
</style>

autoResize.js

import { debounce, observerDomResize } from "../util/index";

export default {
  data() {
    return {
      dom: "",

      width: 0,
      height: 0,

      debounceInitWHFun: "",

      domObserver: "",
    };
  },
  methods: {
    async autoResizeMixinInit() {
      const {
        initWH,
        getDebounceInitWHFun,
        bindDomResizeCallback,
        afterAutoResizeMixinInit,
      } = this;

      await initWH(false);

      getDebounceInitWHFun();

      bindDomResizeCallback();

      if (typeof afterAutoResizeMixinInit === "function")
        afterAutoResizeMixinInit();
    },
    initWH(resize = true) {
      const { $nextTick, $refs, ref, onResize } = this;

      return new Promise((resolve) => {
        $nextTick(() => {
          const dom = (this.dom = $refs[ref]);

          this.width = dom.clientWidth;
          this.height = dom.clientHeight;

          if (typeof onResize === "function" && resize) onResize();

          resolve();
        });
      });
    },
    getDebounceInitWHFun() {
      const { initWH } = this;

      this.debounceInitWHFun = debounce(100, initWH);
    },
    bindDomResizeCallback() {
      const { dom, debounceInitWHFun } = this;

      this.domObserver = observerDomResize(dom, debounceInitWHFun);

      window.addEventListener("resize", debounceInitWHFun);
    },
    unbindDomResizeCallback() {
      let { domObserver, debounceInitWHFun } = this;

      domObserver.disconnect();
      domObserver.takeRecords();
      domObserver = null; // NOSONAR

      window.removeEventListener("resize", debounceInitWHFun);
    },
  },
  mounted() {
    const { autoResizeMixinInit } = this;

    autoResizeMixinInit();
  },
  onBeforeUnMount() {
    const { unbindDomResizeCallback } = this;

    unbindDomResizeCallback();
  },
};

util/index.js

export function randomExtend(minNum, maxNum) {
  if (arguments.length === 1) {
    return parseInt(Math.random() * minNum + 1, 10);
  } else {
    return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10);
  }
}

export function debounce(delay, callback) {
  let lastTime;

  return function () {
    clearTimeout(lastTime);

    const [that, args] = [this, arguments];

    lastTime = setTimeout(() => {
      callback.apply(that, args);
    }, delay);
  };
}

export function observerDomResize(dom, callback) {
  const MutationObserver =
    window.MutationObserver ||
    window.WebKitMutationObserver ||
    window.MozMutationObserver;

  const observer = new MutationObserver(callback);

  observer.observe(dom, {
    attributes: true,
    attributeFilter: ["style"],
    attributeOldValue: true,
  });

  return observer;
}

export function getPointDistance(pointOne, pointTwo) {
  const minusX = Math.abs(pointOne[0] - pointTwo[0]);

  const minusY = Math.abs(pointOne[1] - pointTwo[1]);

  return Math.sqrt(minusX * minusX + minusY * minusY);
}

dragonishare
157 声望3 粉丝