css

Tab导航动画

<template>
  <div class="nav-container">
    <div class="indicator" :style="indicatorStyle"></div>
    <div class="nav">
      <div
        v-for="(tab, index) in tabs"
        :key="index"
        class="nav-item"
        :class="{ active: activeTab === index }"
        @click="changeTab(index)"
      >
        <i :class="tab.icon"></i>
        <span>{{ tab.label }}</span>
      </div>
    </div>
  </div>
</template>

<script setup name="my">
const props = defineProps({
  tabs: {
    type: Array,
    validator: value => {
      return value.every(
        item => item.hasOwnProperty('icon') && item.hasOwnProperty('label')
      )
    },
    default: () => [
      { icon: 'icon-home', label: '首页' },
      { icon: 'icon-user', label: '我的' },
      { icon: 'icon-settings', label: '设置' }
    ]
  },
  initialTab: {
    type: Number,
    default: 0
  }
})
const activeTab = ref(props.initialTab)

const indicatorStyle = computed(() => ({
  left: `${activeTab.value * (100 / props.tabs.length)}%`,
  width: `${100 / props.tabs.length}%`
}))

const changeTab = index => {
  activeTab.value = index
}
</script>

<style scoped>
.nav-container {
  position: relative;
  width: 100%;
  height: 70px;
  background: #fff;
  border-radius: 35px;
  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08);
  overflow: hidden;
}

.nav {
  position: relative;
  display: flex;
  width: 100%;
  height: 100%;
  z-index: 1;
}

.nav-item {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  color: #555;
  font-size: 14px;
  font-weight: 500;
  text-decoration: none;
  transition: all 0.3s ease;
  cursor: pointer;
  z-index: 2;
}

.nav-item i {
  font-size: 22px;
  margin-bottom: 5px;
  transition: all 0.3s ease;
}

.nav-item.active {
  color: #fff;
}

.nav-item.active i {
  transform: translateY(-5px);
}

.indicator {
  position: absolute;
  top: 0;
  height: 100%;
  background: linear-gradient(45deg, #4facfe 0%, #00f2fe 100%);
  border-radius: 35px;
  transition: all 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55); /* 贝塞尔曲线动画 :1.先快速移动 2.稍微超过目标位置 3.再回弹到准确位置*/
  z-index: 0;
}

@media (max-width: 600px) {
  .nav-item {
    font-size: 12px;
  }

  .nav-item i {
    font-size: 18px;
  }
}
</style>
上次更新: