Ability.vue 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. <template>
  2. <section
  3. id="ability"
  4. ref="abilityRef"
  5. class="ability transition-all duration-1000 ease-out"
  6. :class="[isAbilityVisible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-20px']"
  7. >
  8. <div class="ability-title pf-sc-semibold">一体化智慧解决方案</div>
  9. <div class="ability-desc pf-sc-regular">
  10. 绘家科技提供从软件到硬件的完整解决方案,覆盖物业管理的全场景需求
  11. </div>
  12. <div class="ability-content">
  13. <div class="ability-tabs">
  14. <div class="ability-tab-indicator" :style="abilityTabIndicatorStyle"></div>
  15. <div
  16. v-for="tab in abilityTabs"
  17. :key="tab.title"
  18. class="ability-tab-item"
  19. :class="[
  20. activeAbilityTab.id === tab.id ? 'text-white' : 'text-#091221 hover:text-#0F67F8',
  21. ]"
  22. @click="handleAbilityTabClick(tab)"
  23. >
  24. {{ tab.title }}
  25. </div>
  26. </div>
  27. <div class="tab-content">
  28. <Transition name="tab-fade" mode="out-in">
  29. <div :key="activeAbilityTab.id" class="ability-grid">
  30. <div
  31. v-for="ability in abilities[activeAbilityTab.id]"
  32. :key="ability.title"
  33. class="ability-card"
  34. >
  35. <i :class="ability.icon" class="ability-card-icon"></i>
  36. <div class="ability-card-title pf-sc-semibold">
  37. {{ ability.title }}
  38. </div>
  39. <div class="ability-card-desc pf-sc-regular">
  40. {{ ability.desc }}
  41. </div>
  42. <div class="ability-card-link">
  43. 查看详情
  44. <i
  45. class="i-custom-arrow-right-c color-#0F67F8 wh-18px lt-sm:wh-28px transition-transform group-hover:translate-x-4px"
  46. ></i>
  47. </div>
  48. </div>
  49. </div>
  50. </Transition>
  51. </div>
  52. </div>
  53. </section>
  54. </template>
  55. <script setup lang="ts">
  56. import { abilityTabs, abilities } from '@/constants/common'
  57. const abilityRef = ref<HTMLElement | null>(null)
  58. const { isVisible: isAbilityVisible } = useScrollReveal(abilityRef)
  59. const activeAbilityTab = ref<AbilityTab>(abilityTabs[0] as AbilityTab)
  60. const abilityTabIndicatorStyle = computed(() => {
  61. const activeTabIndex = abilityTabs.findIndex((tab) => tab.id === activeAbilityTab.value.id)
  62. return {
  63. transform: `translateX(${activeTabIndex * 100}%)`,
  64. }
  65. })
  66. const handleAbilityTabClick = (tab: AbilityTab) => {
  67. activeAbilityTab.value = tab
  68. }
  69. </script>
  70. <style scoped lang="scss">
  71. .ability {
  72. @apply py-120px;
  73. @extend %landing-container;
  74. @apply lt-sm:py-120px lt-sm:px-32px;
  75. background-size: 100% 100%;
  76. background-image: url('@/assets/images/bg-ability.png');
  77. @screen lt-sm {
  78. background-size: 100% 100%;
  79. background-image: url('@/assets/images/bg-ability-mobile.png');
  80. }
  81. }
  82. .ability-title {
  83. @apply font-s-36px text-#000000 pf-sc-semibold flex-center lh-60px;
  84. @apply lt-sm:font-s-48px lt-sm:lh-60px;
  85. }
  86. .ability-desc {
  87. @apply font-s-16px text-#091221/70 pf-sc-regular lh-30px flex-center mt-4px;
  88. @apply lt-sm:font-s-24px lt-sm:lh-40px lt-sm:text-center lt-sm:px-60px;
  89. }
  90. .ability-content {
  91. @apply mt-24px flex-center flex-col;
  92. @apply lt-sm:mt-40px;
  93. }
  94. .ability-tabs {
  95. @apply relative flex items-center rounded-14px border border-#ECEFF6 bg-#F6F8FD p-6px;
  96. @apply lt-sm:rounded-16px lt-sm:p-8px lt-sm:w-[calc(100%-40px)];
  97. }
  98. .ability-tab-indicator {
  99. @apply absolute w-136px h-[calc(100%-12px)] transition-all duration-300 ease-out rounded-8px bg-#0F67F8;
  100. @apply lt-sm:w-[calc((100%-16px)/3)] lt-sm:h-[calc(100%-16px)] lt-sm:rounded-12px;
  101. }
  102. .ability-tab-item {
  103. @apply relative z-1 cursor-pointer py-14px px-20px text-center font-s-16px transition-colors duration-300 pf-sc-regular;
  104. @apply lt-sm:flex-1 lt-sm:px-0 lt-sm:py-20px lt-sm:font-s-24px;
  105. }
  106. .tab-content {
  107. @apply pt-45px;
  108. @apply lt-sm:pt-40px lt-sm:w-full;
  109. }
  110. .ability-grid {
  111. @apply grid grid-cols-3 gap-24px;
  112. @apply lt-sm:grid-cols-2 lt-sm:gap-25px;
  113. }
  114. .ability-card {
  115. @apply group relative flex flex-col rounded-16px border border-#ECEFF6 bg-[linear-gradient(0deg,_#FFFFFF_0%,_rgba(255,255,255,0.6)_100%)] p-24px transition-all duration-300 hover:border-#0F67F8/30 hover:shadow-[0_8px_24px_rgba(15,103,248,0.08)];
  116. @apply lt-sm:p-24px lt-sm:rounded-16px;
  117. }
  118. .ability-card-icon {
  119. @apply wh-48px;
  120. @apply lt-sm:wh-78px;
  121. }
  122. .ability-card-title {
  123. @apply mt-16px font-s-18px font-semibold text-#091221 pf-sc-semibold;
  124. @apply lt-sm:font-s-32px;
  125. }
  126. .ability-card-desc {
  127. @apply mt-8px flex-1 font-s-14px text-#091221/70 pf-sc-regular;
  128. @apply lt-sm:font-s-24px lt-sm:mt-16px;
  129. }
  130. .ability-card-link {
  131. @apply mt-24px flex items-center gap-8px font-s-16px pf-sc-regular text-#0F67F8 transition-colors hover:text-#0A50FF cursor-pointer;
  132. @apply lt-sm:mt-48px lt-sm:font-s-28px;
  133. }
  134. .tab-fade-enter-active {
  135. transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
  136. }
  137. .tab-fade-leave-active {
  138. transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  139. }
  140. .tab-fade-enter-from {
  141. opacity: 0;
  142. transform: translateX(30px);
  143. }
  144. .tab-fade-leave-to {
  145. opacity: 0;
  146. transform: translateX(-30px);
  147. }
  148. .grid > div {
  149. animation: card-slide-up 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
  150. }
  151. .grid > div:nth-child(1) {
  152. animation-delay: 0.05s;
  153. }
  154. .grid > div:nth-child(2) {
  155. animation-delay: 0.1s;
  156. }
  157. .grid > div:nth-child(3) {
  158. animation-delay: 0.15s;
  159. }
  160. .grid > div:nth-child(4) {
  161. animation-delay: 0.2s;
  162. }
  163. .grid > div:nth-child(5) {
  164. animation-delay: 0.25s;
  165. }
  166. .grid > div:nth-child(6) {
  167. animation-delay: 0.3s;
  168. }
  169. .grid > div:nth-child(7) {
  170. animation-delay: 0.35s;
  171. }
  172. .grid > div:nth-child(8) {
  173. animation-delay: 0.4s;
  174. }
  175. @keyframes card-slide-up {
  176. from {
  177. opacity: 0;
  178. transform: translateY(20px);
  179. }
  180. to {
  181. opacity: 1;
  182. transform: translateY(0);
  183. }
  184. }
  185. </style>