<template>
  <view
    class="jx-popup"
    v-show="hideen"
    :class="{ popupAnimation: isPopup }"
    @tap="maskClice"
    @touchmove.prevent
  >
    <!-- jx-popup 内容 -->
    <view class="popup-center" :class="[type, popupActive]" @tap.stop>
      <slot></slot>
    </view>
  </view>
</template>

<script lang="ts" setup>
/**
 * jx-popup 组件
 * @param (open)     打开popup
 * @param (close)   关闭popup
 * @emit (mask)     mask 触发事件
 * @param (isMask) 是否允许点击 mask 关闭
 * @param (type)   popup 打开方式
 */

import { ref, computed } from 'vue'

/**
 * props
 */
interface PropType {
  isMask?: boolean
  time?: number
  type: string
}
const props = withDefaults(defineProps<PropType>(), {
  isMask: false,
  time: 300,
})

/**
 * emit
 */
const emit = defineEmits<{
  (e: 'mask'): void
}>()

/**
 * 打开popup
 */
// mask 动画
const isPopup = ref<boolean>(false)
// 动画 class
const popupActive = ref<string>('')
// 使用 v-show 避免重新渲染组件
const hideen = ref<boolean>(false)
let openTimer: any = null
function open() {
  let ruler = ['top', 'right', 'bottom', 'left', 'center']
  if (!ruler.includes(props.type)) {
    return console.error(
      'this is param need is top or right or bottom or left or center'
    )
  }
  // 先显示了在执行动画
  hideen.value = true
  // 执行动画
  clearTimeout(openTimer)
  openTimer = setTimeout(() => {
    isPopup.value = true
    switch (props.type) {
      case 'top':
        popupActive.value = 'topAnimation'
        break
      case 'right':
        popupActive.value = 'rightAnimation'
        break
      case 'bottom':
        popupActive.value = 'bottomAnimation'
        break
      case 'left':
        popupActive.value = 'leftAnimation'
        break
      case 'center':
        popupActive.value = 'centerAnimation'
        break
    }
    // 20 兼容 app 渲染过快
  }, 20)
}

/**
 * 关闭popup
 */
let closeTimer: any = null
function close(fun?: Function) {
  isPopup.value = false
  popupActive.value = ''
  clearTimeout(closeTimer)
  closeTimer = setTimeout(() => {
    hideen.value = false
    fun && fun()
  }, props.time)
}

/**
 * 点击 mask 是否允许关闭
 */
let maskTimer: any = null
function maskClice() {
  if (props.isMask) return
  // 遮罩层事件
  emit('mask')
  isPopup.value = false
  popupActive.value = ''
  // 动画执行完了在隐藏
  clearTimeout(maskTimer)
  maskTimer = setTimeout(() => {
    hideen.value = false
  }, props.time)
}

/**
 * 暴露方法提供父组件调用
 */
defineExpose({
  open, // 打开 popup
  close, // 关闭 popup
})

const transitionTImer = computed(() => {
  return `${props.time / 1000}s`
})
</script>

<style lang="scss" scoped>
.jx-popup {
  position: fixed;
  top: 0;
  left: 0;
  height: 100%;
  width: 100%;
  background-color: rgba(0, 0, 0, 0.4);
  opacity: 0;
  transition: all v-bind(transitionTImer);
  .popup-center {
    transition: all v-bind(transitionTImer);
  }

  .top {
    position: absolute;
    top: 0;
    width: 100%;
    transform: translateY(-100%);
  }

  .right {
    position: absolute;
    right: 0;
    height: 100%;
    overflow: auto;
    transform: translateX(100%);
  }

  .bottom {
    position: absolute;
    bottom: 0;
    width: 100%;
    transform: translateY(100%);
  }

  .left {
    position: absolute;
    left: 0;
    height: 100%;
    overflow: auto;
    transform: translateX(-100%);
  }

  .center {
    position: absolute;
    width: auto;
    height: auto;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%) scale(0);
    animation: centerScale v-bind(transitionTImer);
  }
}

// mask 遮罩层
.popupAnimation {
  z-index: 999999999999;
  opacity: 1;
}

// top 顶部弹出
.topAnimation {
  transform: translateY(0%) !important;
}

// right 右侧弹出
.rightAnimation {
  transform: translateX(0%) !important;
}

// bottom 底部弹出
.bottomAnimation {
  transform: translateY(0%) !important;
}

// left 左侧弹出
.leftAnimation {
  transform: translateX(0%) !important;
}

// 居中弹出
.centerAnimation {
  transform: translate(-50%, -50%) scale(1) !important;
}

@keyframes centerScale {
  0% {
    transform: translate(-50%, -50%) scale(0);
  }
  85% {
    transform: translate(-50%, -50%) scale(1.02);
  }
  100% {
    transform: translate(-50%, -50%) scale(1);
  }
}
</style>