indexNav.vue 2.99 KB
<template>
  <view class="index-nav" :class="[`is-${position}`]">
    <view
      class="nav-logo is-home"
      :class="{ 'is-active': active === 'home' }"
      @tap="() => on_select('home')"
    >
      <view class="nav-icon-wrap">
        <image class="nav-icon" :src="icons?.home" mode="aspectFit" />
      </view>
      <text class="nav-text">首页</text>
    </view>

    <view
      class="nav-logo is-code"
      :class="[
        { 'is-active': active === 'code' },
        { 'is-center-raised': center_variant === 'raised' }
      ]"
      @tap="() => on_select('code')"
    >
      <view class="nav-icon-wrap">
        <image
          class="nav-icon"
          :class="{ 'nav-icon--raised': center_variant === 'raised' }"
          :src="icons?.code"
          mode="aspectFit"
        />
      </view>
      <text class="nav-text">预约码</text>
    </view>

    <view
      class="nav-logo is-me"
      :class="{ 'is-active': active === 'me' }"
      @tap="() => on_select('me')"
    >
      <view class="nav-icon-wrap">
        <image class="nav-icon" :src="icons?.me" mode="aspectFit" />
      </view>
      <text class="nav-text">我的</text>
    </view>
  </view>
</template>

<script setup>
const props = defineProps({
  icons: {
    type: Object,
    default: () => ({})
  },
  active: {
    type: String,
    default: ''
  },
  position: {
    type: String,
    default: 'fixed'
  },
  center_variant: {
    type: String,
    default: 'normal'
  },
  allow_active_tap: {
    type: Boolean,
    default: false
  }
})

const emit = defineEmits(['select'])

const on_select = key => {
  if (!props.allow_active_tap && props.active && key === props.active) {
    return
  }
  emit('select', key)
}
</script>

<style lang="less">
.index-nav {
  left: 0;
  bottom: 0;
  width: 750rpx;
  height: calc(134rpx + constant(safe-area-inset-bottom));
  height: calc(134rpx + env(safe-area-inset-bottom));
  padding-bottom: calc(0rpx + constant(safe-area-inset-bottom));
  padding-bottom: calc(0rpx + env(safe-area-inset-bottom));
  box-sizing: border-box;
  background: #ffffff;
  box-shadow: 0 -8rpx 8rpx 0 rgba(0, 0, 0, 0.1);
  display: flex;
  align-items: flex-end;
  justify-content: space-around;
  color: #a67939;
  z-index: 99;

  &.is-fixed {
    position: fixed;
  }

  &.is-absolute {
    position: absolute;
  }

  .nav-logo {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
  }

  .nav-icon-wrap {
    position: relative;
    width: 56rpx;
    height: 56rpx;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  .nav-icon {
    width: 56rpx;
    height: 56rpx;
    display: block;

    &.nav-icon--raised {
      width: 140rpx;
      height: 140rpx;
      position: absolute;
      top: -100rpx;
      left: 50%;
      transform: translateX(-50%);
    }
  }

  .nav-logo.is-home,
  .nav-logo.is-me {
    .nav-icon {
      width: 56rpx;
      height: 56rpx;
    }
  }

  .nav-text {
    font-size: 26rpx;
    margin-top: 12rpx;
    line-height: 1;
  }
}
</style>