Goals
將舊的程式碼重構後,重新設計出一個自動抓取登錄中的活動並依照此活動的優先度、時間、狀態等等來排序,並且能夠自動播放、手動播放、鍵盤控制、滑鼠控制等的 RWD Carousel。
由於此專案原本的 css 非常混亂,所以幾乎每個不同的 <div>
區塊都是參砸著 inline-css、Internal Style Sheet、External Style Sheet
且也可以看到很多當時工程師為了趕下班未經思考亂寫出來的、毫無可讀性、架構可言的 code。
後端程式碼涉及公司隱私的部分就不多做介紹,總之就是一樣去 DB 撈一個活動 table 的活動 ID 出來並跟另一個 table 做比對來判斷活動是否要顯示、活動種類、活動 URL…等。
所以此次工作目標拆分成小項目的話,可以分成以下幾個部分:
- 將傳統這種
Tight Coupling
(程式緊密耦合)的程式碼重構,將有關後端的程式碼模組化後再進行Back-end Data Injection
。 - 將原本參雜在
index
的 Carousel 程式區塊單獨取出來做一個 Component。 - 刪除原本的 CSS 並導入利用 TailwindCSS 達成 RWD,同時重新撰寫 CSS 與 JS 去控制元素顯示。
- 原始的程式碼是所有的圖片(除了第一張)預設隱藏的並在按鈕被點擊對應
id
時去執行JS function
來顯示。CSS 的部分則是透過改變display: none
和display: block
屬性來實現顯示對應 carousel img 的。 - 而現在要改成控制
active
,來add
和remove
class
來達到顯示和隱藏的效果。 - 自動輪播功能、手動輪播功能、手動跳頁、鍵盤控制…等等。(不能互相衝突)
Design Carousel Layout
整個 Carousel 的 HTML Layout 如下:
1 | <div class="carousel-container relative"> |
這邊設計重點有:
- 容器化
- 相對定位
通過使用相對定位,能更容易地控制 Carousel 中各個元素的位置和排列,使其達到我們所需的外觀和功能。
Implementing the Carousel Functionality
JS
基本樣式有了,但只顯示一張活動圖且不能互動也沒動畫效果顯然不是我們要的,
上面給每個容器都定義好了 class
屬性,接下來就可以透過 JS
來擷取這些元素並控制。
儘管專案內有引入 JQuery CDN,但未來還是可能要將 JQuery 淘汰所以還是用 vanilla JS
來撰寫程式,這樣好處是也較能理解 JS 以及底層的實際運作原理。
首先取得所有相關的元素並定義初始 index (預設 0,即第一張 image):
1 | // Get carousel elements |
Creating X-axis
1 | // Function to show the current slide with transition |
- 這裡利用
foreach
遍歷每個carouselItems
,首先會先每個carouselItems
的.active
來確保只顯示當前要顯示的 carouselItems 的 image。item
:每個 carousel-itemi
:每個 carousel-item 的索引。
- 判斷如果(索引 === 傳進來的索引)的話,救代表此
carouselItems
為當前要顯示的carouselItems
,就加上.active
來顯示。 carouselInner.style.height = item.offsetHeight + "px"
直接自動抓取目前 active 的 item 的高度並設定給 carousel-inner,這樣就能讓整個 Carousel 高度隨著圖片高度變化而變化,不會有空白的問題。這行非常重要,可確保幻燈片容器的高度與當前要顯示的幻燈片項的高度保持一致,避免在切換幻燈片時產生跳動或布局問題。
- 獲取所有的 sliderBtns,同樣先移除所有的
.active
,再判斷如果(索引 === 傳進來的索引)的話,就加上.active
來顯示,以製作之後的sliderBtns
的active
狀態。
Prev & Next & Slider Button Function
1 | // Function to go to the previous slide |
為了達到能無限循環播放效果,所以加了這兩個條件判斷:
- 如果目前
currentSlide
小於 0 的話,就指派最後一張圖片的索引給currentSlide
- 反之如果
currentSlide
大於等於carouselItems.length
的話,就將currentSlide
設定為第一張圖片的索引。
而為了能讓使用者能點擊 sliderBtns
就跳到對應 index 的 carouselItems
,這邊直接讓使用者點擊到的那個sliderBtns
的index
觸發showSlide
函式,並將currentSlide
設定為對應index
,這樣就能達到點擊sliderBtns
就能跳到對應的carouselItems
。
Auto-play function
一般電商網站都一定會要求有自動播放的功能,才能吸引使用者的注意力。所以這裡也寫一個每隔 4 秒就自動播放下一張幻燈片的功能。
直接在開頭宣告一個 autoPlayTimer
,並直接在 showSlide
函式後加上每隔 4 秒就觸發 nextSlide
函式的 autoPlayTimer
。
1 | // 自動換頁計時器 |
Reset Auto-play function
當使用者去手動透過 sliderBtns、prevBtn 還是 nextBtn
換頁時,都應該重置 autoPlayTimer
,不然會造成使用者在手動換頁時,autoPlayTimer
也在自動播放,會造成連續換頁的不協調感。
定義一個 resetAutoPlayTimer
函式,用來重置 autoPlayTimer
的時間。
1 | // Function to reset the auto-play timer |
並在 prevSlide、nextSlide、sliderBtns
函式中都加入 resetAutoPlayTimer();
函式來重置 autoPlayTimer
的時間。
1 | // Function to go to the previous slide |
這樣當使用者去手動換頁、跳頁時就能不會再跟自動換頁互相干擾了。
CSS
這邊不用 tailwindcss 的類別去寫整個功能的 CSS 的原因有幾下幾點:
- 複雜度和靈活性
- 動畫需在特定情況下的進行控制
- 程式碼的可讀性和可維護性
由於動畫效果常需要細粒度的控制和設置,包括定義關鍵幀、時間軸和各種動畫屬性。使用原生的 CSS 可提供更大的靈活性和自由度,以實現更複雜和精細的動畫效果。
在這使用 TailwindCSS
的實用類別和行內樣式語法可能會導致代碼變得冗長和難以閱讀,尤其是在處理多個動畫效果和交互時。TailwindCSS
主要就是拿來寫 RWD 以及一些客製化的元件樣式,對於這種還需要條件去判斷的動畫效果,還是用原生 CSS 較優勢。
以下是 CSS 的程式碼:
1 | .carousel-inner { |
- 包覆
.carousel-inner
的容器要設定position: relative
,才能讓.carousel-item
的position: absolute
能夠相對於.carousel-inner
來定位。 carousel-item
用position: absolute
來定位才能將所有的 images 疊加在一起,只有當前是 active 的圖片是可見的,其他則會透過透明度和轉換移動到視圖外,創造出平滑過渡的效果。
關於 absolute
& relative
的原理可以去看這篇 CSS relative? absolute?
簡而言之,就是當
.carousel-item
設定absolute
後,就會會去往外層去尋找父元素有是否有position:relative | absolute | fixed | inherit
的元素,若是都沒有,就會以該網頁頁面(<body>)
的左上角為定位點。
而這裡我將 carousel-inner 設定為 relative
,是因為我希望 .carousel-item
的定位點是以 .carousel-inner
為定位點,就能防止每張 .carousel-item
出現位置不同導致圖片消失的情況發生。
若您覺得這篇文章對您有幫助,歡迎分享出去讓更多人看到⊂◉‿◉つ~
留言版