Prechádzať zdrojové kódy

fix: header group timeline mobile 样式优化

Lee 4 dní pred
rodič
commit
03203dd9a1

+ 103 - 47
app/components/Header.vue

@@ -2,7 +2,7 @@
  * @Author: LiZhiWei
  * @Date: 2026-01-13 15:41:49
  * @LastEditors: LiZhiWei
- * @LastEditTime: 2026-01-20 11:42:37
+ * @LastEditTime: 2026-01-20 14:00:24
  * @Description: 
 -->
 <!--
@@ -16,9 +16,7 @@
     >
       <i class="i-custom-logo w-160px h-32px lt-sm:w-213px lt-sm:h-64px"></i>
 
-      <nav
-        class="hidden sm:flex items-center gap-20px xl:gap-52px text-16px xl:text-16px text-#334155 h-full"
-      >
+      <nav class="hidden sm:flex items-center gap-52px text-16px text-#334155 h-full">
         <NuxtLink to="/" class="nav-link flex items-center">首页</NuxtLink>
         <NuxtLink to="/" class="nav-link flex items-center">产品中心</NuxtLink>
         <div class="group h-full flex items-center">
@@ -105,56 +103,90 @@
   <!-- Mobile Menu Overlay -->
   <div
     v-if="isMobileMenuOpen"
-    class="fixed inset-0 top-80px lt-sm:top-128px bg-white z-90 sm:hidden flex flex-col p-20px animate-fade-in-down"
+    class="fixed inset-0 top-80px lt-sm:top-128px bg-white z-90 sm:hidden flex flex-col animate-fade-in-down overflow-hidden"
   >
-    <nav class="flex flex-col gap-20px text-16px text-#334155 font-500">
-      <NuxtLink to="/" class="py-10px border-b border-gray-100" @click="isMobileMenuOpen = false">
-        首页
-      </NuxtLink>
-      <NuxtLink to="/" class="py-10px border-b border-gray-100" @click="isMobileMenuOpen = false">
-        产品中心
-      </NuxtLink>
-      <div class="py-10px border-b border-gray-100">
-        <div class="mb-10px">解决方案</div>
-        <div class="pl-16px flex flex-col gap-10px text-14px text-gray-500">
-          <div v-for="(cat, idx) in solutionCategories" :key="idx">
-            <div class="font-600 text-gray-700 mb-4px">{{ cat.name }}</div>
-            <div class="pl-8px flex flex-col gap-6px">
-              <div v-for="(item, i) in cat.items" :key="i" class="py-2px">
-                {{ item.title }}
+    <nav class="flex-1 overflow-y-auto py-20px px-24px">
+      <div class="flex flex-col gap-8px text-16px text-#334155 font-500">
+        <NuxtLink
+          to="/"
+          class="mobile-nav-item flex items-center justify-between group"
+          @click="isMobileMenuOpen = false"
+        >
+          <span>首页</span>
+        </NuxtLink>
+        <NuxtLink
+          to="/"
+          class="mobile-nav-item flex items-center justify-between group"
+          @click="isMobileMenuOpen = false"
+        >
+          <span>产品中心</span>
+          <i class="i-ep-arrow-right text-gray-300 text-12px group-active:text-#0F67F8"></i>
+        </NuxtLink>
+
+        <!-- Solutions Section -->
+        <div class="border-b border-gray-100">
+          <div
+            class="mobile-nav-item flex items-center justify-between !border-none cursor-pointer"
+            :class="{ 'text-#0F67F8': isMobileSolutionsOpen }"
+            @click="isMobileSolutionsOpen = !isMobileSolutionsOpen"
+          >
+            <span>解决方案</span>
+            <i
+              class="i-ep-arrow-down transition-transform duration-300 text-gray-300"
+              :class="{
+                'rotate-180': isMobileSolutionsOpen,
+                'text-#0F67F8': isMobileSolutionsOpen,
+              }"
+            ></i>
+          </div>
+
+          <div
+            v-show="isMobileSolutionsOpen"
+            class="pl-12px pb-16px flex flex-col gap-24px animate-fade-in"
+          >
+            <div v-for="(cat, idx) in solutionCategories" :key="idx">
+              <div
+                class="font-600 text-15px text-#1e293b mb-12px pl-10px border-l-3 border-#0F67F8 flex items-center h-16px"
+              >
+                {{ cat.name }}
+              </div>
+              <div class="pl-4px grid grid-cols-2 gap-x-10px gap-y-10px">
+                <div
+                  v-for="(item, i) in cat.items"
+                  :key="i"
+                  class="text-13px text-#475569 bg-gray-50/80 border border-gray-100 rounded-8px py-10px px-8px flex items-center justify-center text-center active:bg-blue-50 active:border-blue-200 active:text-blue-600 transition-all duration-200"
+                >
+                  {{ item.title }}
+                </div>
               </div>
             </div>
           </div>
         </div>
-      </div>
-      <NuxtLink to="/" class="py-10px border-b border-gray-100" @click="isMobileMenuOpen = false">
-        客户案例
-      </NuxtLink>
-      <NuxtLink to="/" class="py-10px border-b border-gray-100" @click="isMobileMenuOpen = false">
-        关于绘家
-      </NuxtLink>
-      <NuxtLink to="/" class="py-10px border-b border-gray-100" @click="isMobileMenuOpen = false">
-        联系合作
-      </NuxtLink>
-    </nav>
 
-    <div class="mt-auto pt-20px border-t border-gray-100">
-      <div class="flex items-center gap-10px mb-20px justify-center">
-        <i class="i-custom-telephone wh-24px"></i>
-        <span class="font-s-20px font-bold text-#28292E">400-600-7709</span>
+        <NuxtLink
+          to="/"
+          class="mobile-nav-item flex items-center justify-between group"
+          @click="isMobileMenuOpen = false"
+        >
+          <span>客户案例</span>
+          <i class="i-ep-arrow-right text-gray-300 text-12px group-active:text-#0F67F8"></i>
+        </NuxtLink>
+        <NuxtLink
+          to="/"
+          class="mobile-nav-item flex items-center justify-between group"
+          @click="isMobileMenuOpen = false"
+        >
+          <span>关于绘家</span>
+        </NuxtLink>
+        <NuxtLink
+          to="/"
+          class="mobile-nav-item flex items-center justify-between group"
+          @click="isMobileMenuOpen = false"
+        >
+          <span>联系合作</span>
+        </NuxtLink>
       </div>
-      <button
-        class="btn-primary text-white font-medium w-full h-44px rounded-8px text-16px"
-        @click="
-          () => {
-            openConsultation()
-            isMobileMenuOpen = false
-          }
-        "
-      >
-        申请试用
-      </button>
-    </div>
+    </nav>
   </div>
 </template>
 
@@ -163,6 +195,7 @@
   const { y } = useWindowScroll()
 
   const isMobileMenuOpen = ref(false)
+  const isMobileSolutionsOpen = ref(false)
 
   const activeCategory = ref(0)
 
@@ -278,6 +311,21 @@
     }
   }
 
+  @keyframes fadeIn {
+    from {
+      opacity: 0;
+      transform: translateY(-5px);
+    }
+    to {
+      opacity: 1;
+      transform: translateY(0);
+    }
+  }
+
+  .animate-fade-in {
+    animation: fadeIn 0.3s ease-out forwards;
+  }
+
   .animate-fade-in-down {
     animation: fadeInDown 0.2s ease-out forwards;
 
@@ -286,4 +334,12 @@
       @apply absolute -top-10px left-0 w-full h-10px;
     }
   }
+
+  .mobile-nav-item {
+    @apply py-16px border-b border-gray-100 text-#334155 active:text-#0F67F8 transition-colors;
+  }
+
+  .safe-area-bottom {
+    padding-bottom: calc(24px + env(safe-area-inset-bottom));
+  }
 </style>

+ 55 - 4
app/pages/index/components/HistorySection.vue

@@ -99,10 +99,14 @@
 
         <div class="history-mobile-track-container">
           <div class="history-mobile-track-line"></div>
-          <div class="history-mobile-nodes">
+          <TransitionGroup
+            :name="'timeline-' + slideDirection"
+            tag="div"
+            class="history-mobile-nodes"
+          >
             <div
-              v-for="(yearIndex, i) in mobileTimelineIndices"
-              :key="i"
+              v-for="yearIndex in mobileTimelineIndices"
+              :key="yearIndex"
               class="history-mobile-node"
               :class="{ invisible: yearIndex < 0 || yearIndex >= historyYears.length }"
               @click="yearIndex >= 0 && yearIndex < historyYears.length && selectYear(yearIndex)"
@@ -115,7 +119,7 @@
                 {{ historyYears[yearIndex]?.year }}
               </div>
             </div>
-          </div>
+          </TransitionGroup>
         </div>
 
         <i
@@ -158,6 +162,7 @@
 
   const currentYearIndex = ref(historyYears.length - 1)
   const currentEventIndex = ref(0)
+  const slideDirection = ref<'next' | 'prev'>('next')
 
   const currentYearData = computed(() => {
     const data = historyYears[currentYearIndex.value]
@@ -192,6 +197,7 @@
 
   const nextYear = () => {
     if (currentYearIndex.value < historyYears.length - 1) {
+      slideDirection.value = 'next'
       currentYearIndex.value++
       currentEventIndex.value = 0
     }
@@ -199,6 +205,7 @@
 
   const prevYear = () => {
     if (currentYearIndex.value > 0) {
+      slideDirection.value = 'prev'
       currentYearIndex.value--
       currentEventIndex.value = 0
     }
@@ -218,6 +225,7 @@
   }
 
   const selectYear = (index: number) => {
+    slideDirection.value = index > currentYearIndex.value ? 'next' : 'prev'
     currentYearIndex.value = index
     currentEventIndex.value = 0
   }
@@ -481,4 +489,47 @@
       @apply text-#0F67F8 font-semibold scale-110;
     }
   }
+
+  /* Timeline Animation */
+  .timeline-next-move,
+  .timeline-prev-move {
+    transition: all 0.5s ease;
+  }
+
+  .timeline-next-enter-active,
+  .timeline-next-leave-active,
+  .timeline-prev-enter-active,
+  .timeline-prev-leave-active {
+    transition: all 0.5s ease;
+  }
+
+  .timeline-next-leave-active {
+    position: absolute;
+    left: 100px;
+  }
+
+  .timeline-prev-leave-active {
+    position: absolute;
+    right: 100px;
+  }
+
+  .timeline-next-enter-from {
+    opacity: 0;
+    transform: translateX(100%);
+  }
+
+  .timeline-next-leave-to {
+    opacity: 0;
+    transform: translateX(-100%);
+  }
+
+  .timeline-prev-enter-from {
+    opacity: 0;
+    transform: translateX(-100%);
+  }
+
+  .timeline-prev-leave-to {
+    opacity: 0;
+    transform: translateX(100%);
+  }
 </style>