fab-tool.vue 3.22 KB
<template>
  <view class="fab-tool">
    <view id="toolfab">
      <slot></slot>
    </view>
    <view class="fab-tool-content" :style="placementStyle" id="placementfab">
      <slot name="content" v-if="visible"></slot>
    </view>
  </view>
</template>

<script>
export default {
  props: {
    visible: {
      type: Boolean,
      default: false
    },
    placement: {
      type: String,
      default: 'auto' // 'auto' | 'top-start' | 'top-center' | 'top-end' | 'bottom-start' | 'bottom-center' | 'bottom-end'
    }
  },
  data() {
    return {
      placementHeight: '0',
      placementType: ''
    }
  },
  watch: {
    visible(newVal) {
      if (newVal) {
        const { screenWidth } = uni.getSystemInfoSync()

        this.$nextTick(() => {
          let placementWidth = 0
          uni
            .createSelectorQuery()
            .in(this)
            .select('#placementfab')
            .boundingClientRect((res) => {
              this.placementHeight = -res.height + 'px'
              placementWidth = res.width
            })
            .exec()
          // 开启自动模式后
          if (this.placement == 'auto') {
            uni
              .createSelectorQuery()
              .in(this)
              .select('#toolfab')
              .boundingClientRect((res) => {
                let leftRemain = res.left
                let rightRemain = screenWidth - leftRemain
                if (rightRemain > placementWidth) {
                  this.placementType = 'bottom-start'
                } else if (leftRemain > placementWidth) {
                  this.placementType = 'bottom-end'
                } else {
                  this.placementType = 'bottom-center'
                }
              })
              .exec()
          }
        })
      }
    }
  },
  mounted() {
    this.placementType = this.placement
  },
  computed: {
    placementStyle() {
      let position = {}
      switch (this.placementType) {
        case 'top-start':
          position = {
            top: this.placementHeight,
            left: 0
          }
          break
        case 'top-center':
          position = {
            top: this.placementHeight,
            left: '50%',
            transform: 'translateX(-50%)'
          }
          break
        case 'top-end':
          position = {
            top: this.placementHeight,
            right: 0
          }
          break
        case 'bottom-start':
          position = {
            bottom: this.placementHeight,
            left: 0
          }
          break
        case 'bottom-center':
          position = {
            bottom: this.placementHeight,
            left: '50%',
            transform: 'translateX(-50%)'
          }
          break
        case 'bottom-end':
          position = {
            bottom: this.placementHeight,
            right: 0
          }
          break
        default:
          break
      }
      return position
    }
  },
  methods: {
    //
  }
}
</script>

<style lang="scss">
.fab-tool {
  position: relative;

  .fab-tool-content {
    position: absolute;
    z-index: 999;

    background-color: #ffffff;
    box-shadow: -2px -2px 4px rgba(0, 0, 0, 0.05), 2px 2px 4px rgba(0, 0, 0, 0.05);
    border-radius: 12rpx;
    box-sizing: border-box;
  }
}
</style>