<template>
  <div
    :style="style"
    class="mm-affix">
    <div
      :style="wrapperStyle"
      class="mm-affix-wrapper">
      <slot></slot>
    </div>
  </div>
</template>

<script>
export default {
  name: "mm-affix",
  props: {
    fixedBottom: Number,
    fixedTop: Number,
    target: Function,
    zIndex: {
      type: Number,
    },
    position: {
      type: String,
      default: "fixed",
    },
  },
  data() {
    return {
      eventTarget: null,
      height: 0,
      width: 0,
      targetHeight: 0,
      clientHeight: 0,
      offsetTop: 0,
      scrollTop: 0,
      top: 0,
      bottom: 0,
    }
  },
  computed: {
    targetIsNotWindow() {
      return !this.$isServer && this.eventTarget !== window
    },
    topActive() {
      if (typeof this.fixedTop === "number") {
        if (this.targetIsNotWindow) {
          return this.offsetTop - this.scrollTop < this.fixedTop
        } else {
          return this.top <= this.fixedTop
        }
      } else {
        return false
      }
    },
    bottomActive() {
      if (typeof this.fixedBottom === "number") {
        if (this.targetIsNotWindow) {
          return this.scrollTop + this.targetHeight < this.offsetTop + this.clientHeight
        } else {
          return this.bottom > this.targetHeight
        }
      } else {
        return false
      }
    },
    style() {
      return {
        height: this.height ? `${this.height}px` : "auto",
        width: this.height ? `${this.width}px` : "auto",
        minWidth: this.height ? `${this.width}px` : "auto",
      }
    },
    wrapperStyle() {
      let result = {}

      if (this.zIndex) {
        result.zIndex = this.zIndex
      }

      if (this.topActive || this.bottomActive) {
        result.position = this.position
      }

      if (this.topActive) {
        result.top = `${this.targetIsNotWindow ? this.scrollTop + this.fixedTop : this.fixedTop}px`
      }

      if (this.bottomActive) {
        result.bottom = `${
          this.targetIsNotWindow ? -(this.scrollTop - this.fixedBottom) : this.fixedBottom
        }px`
      }

      return result
    },
  },
  mounted() {
    // 记录内容高度 防止切换为fixed会抖动
    this.height = this.$el.firstChild.offsetHeight
    this.width = this.$el.firstChild.offsetWidth

    !this.$isServer &&
      this.$nextTick(() => {
        this.eventTarget = this.target ? this.target() : window
        this.clientHeight = this.$el.clientHeight
        this.setData()
        this.setupListenter()
      })
  },
  beforeDestroy() {
    this.removeListener()
  },
  methods: {
    setData() {
      const { top, bottom } = this.$el.getBoundingClientRect()
      const target = this.eventTarget === window ? document.documentElement : this.eventTarget

      this.top = top
      this.bottom = bottom
      this.scrollTop = target.scrollTop
      this.targetHeight = target.clientHeight
      this.offsetTop = this.$el.offsetTop
    },
    setupListenter() {
      this.eventTarget.addEventListener("scroll", this.setData)
      this.eventTarget.addEventListener("resize", this.setData)
    },
    removeListener() {
      this.eventTarget.removeEventListener("scroll", this.setData)
      this.eventTarget.removeEventListener("resize", this.setData)
    },
  },
}
</script>
