cases.vue 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. <template>
  2. <section
  3. id="cases"
  4. ref="casesRef"
  5. class="cases transition-all duration-1000 ease-out"
  6. :class="[isCasesVisible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-50px']"
  7. >
  8. <div class="cases-header">
  9. <h2 class="cases-title pf-sc-semibold">知识产权和案例</h2>
  10. <p class="cases-desc pf-sc-regular">
  11. 绘家科技凭借强大的技术实力和丰富的实践经验,为客户提供卓越的智慧社区解决方案
  12. </p>
  13. </div>
  14. <div ref="casesListRef" class="cases-list" @scroll="handleCaseScroll">
  15. <div
  16. v-for="(caseItem, index) in cases"
  17. :key="caseItem.title"
  18. class="cases-card"
  19. :class="{ active: index === activeCaseIndex }"
  20. >
  21. <div class="flex flex-col h-full">
  22. <img :src="caseItem.img" class="cases-card-img" alt="" />
  23. <h3 class="cases-card-title pf-sc-semibold">
  24. {{ caseItem.title }}
  25. </h3>
  26. <p class="cases-card-desc pf-sc-regular">
  27. {{ caseItem.desc }}
  28. </p>
  29. <div class="cases-card-points">
  30. <div v-for="point in caseItem.points" :key="point.title" class="cases-card-point">
  31. <i class="i-custom-check-one cases-card-point-icon"></i>
  32. <div class="cases-card-point-title pf-sc-semibold">
  33. {{ point.title }}
  34. </div>
  35. <div class="cases-card-point-desc pf-sc-regular">
  36. {{ point.itemDesc }}
  37. </div>
  38. </div>
  39. </div>
  40. <button class="cases-btn">
  41. {{ caseItem.btnText }}
  42. <i class="i-custom-arrow-right-c cases-card-btn-icon"></i>
  43. </button>
  44. </div>
  45. </div>
  46. </div>
  47. <div class="cases-dots lt-sm:flex hidden">
  48. <div
  49. v-for="(_, index) in cases"
  50. :key="index"
  51. class="dot"
  52. :class="{ active: index === activeCaseIndex }"
  53. @click="scrollToCase(index)"
  54. ></div>
  55. </div>
  56. </section>
  57. </template>
  58. <script setup lang="ts">
  59. import { cases } from '@/constants/common'
  60. const casesRef = ref<HTMLElement | null>(null)
  61. const { isVisible: isCasesVisible } = useScrollReveal(casesRef)
  62. const activeCaseIndex = ref(0)
  63. const casesListRef = ref<HTMLElement | null>(null)
  64. const handleCaseScroll = (e: Event) => {
  65. const el = e.target as HTMLElement
  66. const scrollLeft = el.scrollLeft
  67. const width = el.offsetWidth
  68. const cardWidth = width * 0.9
  69. const gap = 16
  70. const newIndex = Math.round(scrollLeft / (cardWidth + gap))
  71. if (newIndex !== activeCaseIndex.value) {
  72. activeCaseIndex.value = newIndex
  73. }
  74. }
  75. const scrollToCase = (index: number) => {
  76. if (!casesListRef.value) return
  77. const width = casesListRef.value.offsetWidth
  78. const cardWidth = width * 0.9
  79. const gap = 16
  80. casesListRef.value.scrollTo({
  81. left: index * (cardWidth + gap),
  82. behavior: 'smooth',
  83. })
  84. }
  85. </script>
  86. <style scoped lang="scss">
  87. .cases {
  88. @apply landing-container pt-120px pb-46px lt-sm:pt-120px lt-sm:pb-60px lt-sm:px-32px;
  89. }
  90. .cases-header {
  91. @apply text-center mb-60px lt-sm:mb-60px lt-sm:px-32px;
  92. }
  93. .cases-title {
  94. @apply font-s-36px font-semibold text-#000000 mb-4px lh-60px;
  95. @apply lt-sm:font-s-48px lt-sm:mb-16px;
  96. }
  97. .cases-desc {
  98. @apply font-s-16px text-#091221/70 lh-30px;
  99. @apply lt-sm:font-s-24px lt-sm:lh-40px lt-sm:px-70px;
  100. }
  101. .cases-list {
  102. @apply flex gap-24px;
  103. @apply lt-sm:gap-36px lt-sm:overflow-x-auto lt-sm:overflow-y-hidden lt-sm:px-0 lt-sm:pb-10px;
  104. @apply lt-sm:[scroll-snap-type:x_mandatory] lt-sm:[scrollbar-width:none];
  105. &::-webkit-scrollbar {
  106. @apply lt-sm:hidden;
  107. }
  108. }
  109. .cases-card {
  110. @apply group flex-1 overflow-hidden rounded-16px bg-#F6F8FD p-32px transition-all duration-300;
  111. @apply lt-sm:flex-none lt-sm:w-[calc(100vw-84px)] lt-sm:min-w-[calc(100vw-84px)] lt-sm:p-32px lt-sm:rounded-16px;
  112. @apply lt-sm:[scroll-snap-align:center];
  113. &:first-child {
  114. @apply lt-sm:ml-42px;
  115. }
  116. &:last-child {
  117. @apply lt-sm:mr-42px;
  118. }
  119. }
  120. .cases-card-img {
  121. @apply w-full h-218px rounded-12px;
  122. @apply lt-sm:h-320px lt-sm:rounded-12px;
  123. }
  124. .cases-card-title {
  125. @apply font-s-18px font-semibold text-#091221 mt-24px;
  126. @apply lt-sm:font-s-32px lt-sm:mt-32px;
  127. }
  128. .cases-card-desc {
  129. @apply mt-8px font-s-14px lh-24px text-#091221/70;
  130. @apply lt-sm:font-s-24px lt-sm:lh-36px lt-sm:mt-16px;
  131. }
  132. .cases-card-points {
  133. @apply mt-24px flex flex-col gap-8px flex-1;
  134. @apply lt-sm:mt-32px lt-sm:gap-16px;
  135. }
  136. .cases-card-point {
  137. @apply flex items-center gap-8px;
  138. @apply lt-sm:gap-12px;
  139. }
  140. .cases-card-point-icon {
  141. @apply wh-20px mt-2px;
  142. @apply lt-sm:wh-32px;
  143. }
  144. .cases-card-point-title {
  145. @apply font-s-14px font-semibold text-#091221;
  146. @apply lt-sm:font-s-24px;
  147. }
  148. .cases-card-point-desc {
  149. @apply font-s-14px text-#091221/70;
  150. @apply lt-sm:font-s-24px;
  151. }
  152. .cases-btn {
  153. @apply mt-56px flex items-center justify-between gap-8px rounded-8px bg-white px-16px py-15px font-s-16px text-#0F67F8 transition-all hover:bg-#0F67F8 hover:text-white;
  154. @apply lt-sm:mt-48px lt-sm:h-96px lt-sm:rounded-8px lt-sm:px-32px lt-sm:font-s-28px lt-sm:bg-#0F67F8 lt-sm:text-white;
  155. }
  156. .cases-card-btn-icon {
  157. @apply wh-18px;
  158. @apply lt-sm:wh-32px lt-sm:text-white;
  159. }
  160. .cases-dots {
  161. @apply lt-sm:mt-40px lt-sm:flex-center lt-sm:gap-16px;
  162. .dot {
  163. @apply lt-sm:w-60px lt-sm:h-10px bg-#E5E9F5 rounded-full transition-all cursor-pointer;
  164. &.active {
  165. @apply bg-#0F67F8;
  166. }
  167. }
  168. }
  169. </style>