<!--
 * @Author: wei
 * @description: 大屏自适应容器组件
 * @LastEditTime: 2022-09-09 16:42:40
-->
<template>
  <!-- <section class="screen-box" :style="boxStyle"> -->
  <div class="screen-wrapper" ref="screenWrapper" :style="wrapperStyle">
    <slot></slot>
  </div>
  <!-- </section> -->
</template>
<script setup>
  import { nextTick } from 'process';
  import { computed, onBeforeUnmount, onMounted, reactive, ref, defineProps, watch, inject } from 'vue';

  /**
   * 防抖函数
   * @param {T} fn
   * @param {number} delay
   * @return
   */
  // -- 1、封装防抖函数
  function debounce(fn, delay) {
    // -- 创建一个标记用来存放定时器的返回值
    let timer = null;
    // -- args为屏幕大小变化监听到的内容
    return function (...args) {
      timer = setTimeout(
        () => {
          // -- 进行防抖的内容 -->apply和call都是用来改变this的指向的。（null这个对象代替function类里this对象；args这是个数组，作为参数传给function(args-->arguments)）
          typeof fn === "function" && fn.apply(null, args);
          // -- 每当用户触发。。事件，把前一个setTimeout清除掉
          clearTimeout(timer);
        },
        delay > 0 ? delay : 100
      );
    };
  }

  // 父传子。子组件接收
  const props = defineProps({
    // name:{
    //   type:String,
    //   default:'VScaleScreen'
    // },
    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: () => ({}),
    }
  })

  const data = reactive({
    currentWidth: 0,
    currentHeight: 0,
    originalWidth: 0,
    originalHeight: 0,
    onResize: null,
    observer: null,
  })


  const screenWrapper = ref()

  // const screenWrapper = computed(() => {
  //   return  this.$refs.screenWrapper;
  // })

  const initSize = (() => {
    return new Promise((resolve, reject) => {
      // console.log("初始化样式");
      //给父元素设置 overflow:hidden
      screenWrapper.value.style.overflow = "hidden";
      screenWrapper.value.scrollLeft = 0;
      screenWrapper.value.scrollTop = 0;

      nextTick(() => {
        // region 获取大屏真实尺寸
        // *** width和height 是子组件传过来的高宽。 ***
        if (props.width && props.height) {
          data.currentWidth = props.width;
          data.currentHeight = props.height;
        } else {
          data.currentWidth = screenWrapper.clientWidth;
          data.currentHeight = screenWrapper.clientHeight;
        }
        // endregion
        // region 获取画布尺寸
        if (!data.originalHeight || !data.originalWidth) {
          data.originalWidth = window.screen.width;
          data.originalHeight = window.screen.height;
        }
        // endregion
        resolve();
      });
    });
  })

  const updateSize = (() => {
    if (data.currentWidth && data.currentHeight) {
      screenWrapper.value.style.width = `${data.currentWidth}px`;
      screenWrapper.value.style.height = `${data.currentHeight}px`;
    } else {
      screenWrapper.value.style.width = `${data.originalWidth}px`;
      screenWrapper.value.style.height = `${data.originalHeight}px`;
    }
  })

  const handleAutoScale = ((scale) => {
    if (!props.autoScale) return;
    const domWidth = screenWrapper.value.clientWidth;
    const domHeight = screenWrapper.value.clientHeight;
    const currentWidth = document.body.clientWidth;
    const currentHeight = document.body.clientHeight;
    screenWrapper.value.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 props.autoScale === "object") {
      // @ts-ignore
      !props.autoScale.x && (mx = 0);
      // @ts-ignore
      !props.autoScale.y && (my = 0);
    }
    // console.log({
    //   mx,
    //   my,
    //   currentWidth,
    //   currentHeight,
    //   domWidth,
    //   domHeight,
    //   scale,
    // });
    screenWrapper.value.style.margin = `${my}px ${mx}px`;
  })


  // -- scalewidth是内部的宽度
  const updateScale = (() => {
    // 获取真实视口尺寸
    const currentWidth = document.body.clientWidth;
    const currentHeight = document.body.clientHeight;
    // 获取大屏最终的宽高onResize
    const realWidth = data.currentWidth || data.originalWidth;
    const realHeight = data.currentHeight || data.originalHeight;
    // 计算缩放比例
    const widthScale = currentWidth / realWidth;
    const heightScale = currentHeight / realHeight;
    // console.log({currentWidth, currentHeight,realWidth,realHeight});

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

  const initMutationObserver = (() => {
    const observer = (data.observer = new MutationObserver(() => {
      onResize();
    }));

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

  // -- vue中使用防抖，需要在组件销毁的钩子中去除监听事件，不然会产生意想不到的bug
  const clearListener = (() => {
    window.removeEventListener("resize", data.onResize);
  })

  // -- 添加监听事件。给window绑定resize事件，调用封装防抖函数（resize是在浏览器窗口大小发生变化时触发，利用该事件可以跟踪窗口大小的变化来动态控制调整页面的元素显示）
  const addListener = (() => {
    window.addEventListener("resize", data.onResize);
  })

  const clearStyle = (() => {
    // console.log("清除");
    screenWrapper.value.parentNode.style.overflow = "auto";
    screenWrapper.value.style = "";
  })

  const resize = async () => {
    if (!props.selfAdaption) {
      return;
    }
    await initSize();
    // -- 获取窗口高宽
    updateSize();
    updateScale();
  }

  onMounted(() => {
    data.onResize = debounce(() => {
      resize();
    }, props.delay);
    nextTick(() => {
      if (props.selfAdaption) {
        // -- 监听浏览器窗口变化，实时获取窗口的高宽
        resize();
        // -- 防抖，避免触发方法多次时，重复获取浏览器高宽
        addListener();
      }
    });
  })

  onBeforeUnmount(() => {
    // -- 组件销毁的钩子函数中，移除监听事件。
    clearListener();
    // this.observer.disconnect()
  })




  // ****** 此处出现问题 ******
  // watch(props.selfAdaption, (val) => {
  //   if (val) {
  //     resize();
  //     addListener();
  //   } else {
  //     clearListener();
  //     clearStyle();
  //   }
  // })
</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>