[react] React Slick
React-Slick 套件能夠讓我們快速的建立輪播效果(carousel),這篇主要介紹 Slick 參數及 CSS 如何設定。
安裝
npm install react-slick slick-carousel
範例資料
先在專案底下新增範例資料,名為 movies.json
。
[ { "name": "coco", "url": "https://www.themoviedb.org/t/p/w220_and_h330_face/gGEsBPAijhVUFoiNpgZXqRVWJt2.jpg" }, { "name": "Orphan: First Kill", "url": "https://www.themoviedb.org/t/p/w220_and_h330_face/pHkKbIRoCe7zIFvqan9LFSaQAde.jpg" }, { "name": "Top Gun: Maverick", "url": "https://www.themoviedb.org/t/p/w220_and_h330_face/62HCnUTziyWcpDaBO2i1DX17ljH.jpg" }, { "name": "One Piece Film Red", "url": "https://www.themoviedb.org/t/p/w220_and_h330_face/m80kPdrmmtEh9wlLroCp0bwUGH0.jpg" }, { "name": "Spider-Man: No Way Home", "url": "https://www.themoviedb.org/t/p/w220_and_h330_face/uJYYizSuA9Y3DCs0qS4qWvHfZg4.jpg" }, { "name": "Lightyear", "url": "https://www.themoviedb.org/t/p/w220_and_h330_face/65WFr1ZMAbEniIh4jEhbRG9OHHN.jpg" }, { "name": "Welcome to the Club", "url": "https://www.themoviedb.org/t/p/w220_and_h330_face/kxB9E6fo0ycHzd13oOTHmGa5Njd.jpg" }]
接著在 App.jsx
中將範例資料引入,並直接使用 map function 讀取範例資料並讓圖片顯示出來。
import movies from "./movies.json";import "./App.css";function App() { return ( <div className="App"> <Slider {...settings}> {movies.map((movie) => ( <div className="wrap"> <img src={movie.url} /> </div> ))} </Slider> </div> );}export default App;
CSS 的部分也先進行一些簡單的設定:
.App { margin-top: 20px; padding: 0 calc(3.5vw + 80px); position: relative;}.wrap { width: 300px; outline: none;}img { border: 4px solid transparent; border-radius: 4px; margin: auto; box-shadow: rgb(0 0 0 / 69%) 0px 26px 30px -10px, rgb(0 0 0 / 20%) 0px 16px 10px -10px; transition-duration: 300ms; max-width: 100%;}img:hover { border: 4px solid rgba(249, 249, 249, 0.8);}
Slider
接著就可以使用 Slider 來建立輪播效果了,在 App.jsx
中引入 Slider 和 CSS。
記得我們自己的 CSS 一定要放在 React-Slick 的 CSS 的下方,這樣才能夠去覆寫 Slick 原本的 CSS,不這麼做的話要去覆寫 Slick CSS 只能用 !important 的方式。
import movies from "./movies.json";import Slider from "react-slick";import "slick-carousel/slick/slick.css";import "slick-carousel/slick/slick-theme.css";import "./App.css";function App() { return ( <div className="App"> <Slider> {movies.map((movie) => ( <div className="wrap"> <img src={movie.url} /> </div> ))} </Slider> </div> );}export default App;
現在回到畫面上應該只會看到左右兩邊有箭頭,畫面上僅有一張圖片。
這是因為我們需要透過參數傳遞的方式,告訴 Slider 我們要去啟用哪些功能或是哪些設定。
簡單介紹一下一些基礎參數,這邊使用圖片當範例說明:
- dots:在 Slider 底下會看到點點(dots),也稱 paging,可以使用這些 dots 移至其他 page,而滑動的距離會根據
slidesToScroll
來決定一次要滑動幾張圖片。 - infinite:如設定為 true,當 Slider 滑到最後一張圖片時,下一張圖片會自動回到第一張圖片。
- speed:滑動的時間,單位為毫秒。
- slidesToShow:一次要顯示幾張圖片。
- slidesToScroll:一次滑動要顯示幾張圖片。
- autoplay:如設定為 true,則圖片會自動進行輪播,當滑鼠移至 Slider 時才會停下。
import movies from "./movies.json";import Slider from "react-slick";import "slick-carousel/slick/slick.css";import "slick-carousel/slick/slick-theme.css";import "./App.css";function App() { const settings = { dots: true, infinite: true, speed: 500, slidesToShow: 3, slidesToScroll: 3, autoplay: true, }; return ( <div className="App"> <Slider {...settings}> {movies.map((movie) => ( <div className="wrap"> <img src={movie.url} /> </div> ))} </Slider> </div> );}export default App;
設定 dot(paging) 的 CSS
要去覆寫 Slick 套件裡面的 CSS,都必須使用 Classname 的方式來覆寫,經過觀察後得知,dots 底下的按鈕是使用偽元素,而當前的 dot 會有 slick.active
的 Class,我們可以試著將當前 dot 設定為白色。
.App { margin-top: 20px; padding: 0 calc(3.5vw + 80px); position: relative;}.wrap { width: 300px; outline: none;}img { border: 4px solid transparent; border-radius: 4px; margin: auto; box-shadow: rgb(0 0 0 / 69%) 0px 26px 30px -10px, rgb(0 0 0 / 20%) 0px 16px 10px -10px; transition-duration: 300ms; max-width: 100%;}img:hover { border: 4px solid rgba(249, 249, 249, 0.8);}.slick-dots li.slick-active button:before { color: #fff;}
RWD 設定
目前 Slider 還沒有支援 RWD,所以當畫面縮小的時候,我們的圖片就會全部擠在一起。
所以可以在設定中加上 RWD 參數:
import movies from "./movies.json";import Slider from "react-slick";import "slick-carousel/slick/slick.css";import "slick-carousel/slick/slick-theme.css";// import settings from "./settings";import "./App.css";function App() { const settings = { dots: true, infinite: true, speed: 500, slidesToShow: 3, slidesToScroll: 3, responsive: [ { breakpoint: 480, settings: { slidesToShow: 1, slidesToScroll: 1, }, }, ], }; return ( <div className="App"> <Slider {...settings}> {movies.map((movie) => ( <div className="wrap"> <img src={movie.url} /> </div> ))} </Slider> </div> );}export default App;
現在只要畫面的寬度小於480px
,就只顯示一張圖片,而滑動也是,一次只滑動一張圖片。
將設定檔獨立成一份檔案
在設定 RWD 的時候不知道你有沒有發現,我們的設定檔的程式碼越來越長了,如果今天有非常多的 breakpoint 需要設定,則會更於冗長,所以可以把它獨立成一份檔案,要使用的時候在引入就好了。
const settings = { dots: true, infinite: true, speed: 500, slidesToShow: 3, slidesToScroll: 1, responsive: [ { breakpoint: 480, settings: { slidesToShow: 1, slidesToScroll: 1, }, }, ],};export default settings;
import movies from "./movies.json";import Slider from "react-slick";import "slick-carousel/slick/slick.css";import "slick-carousel/slick/slick-theme.css";import settings from "./settings";import "./App.css";function App() { return ( <div className="App"> <Slider {...settings}> {movies.map((movie) => ( <div className="wrap"> <img src={movie.url} /> </div> ))} </Slider> </div> );}export default App;
Custom Paging 設定
如果想要自訂自己的 Paging,則可以在參數中加上 customPaging function
,該 function 有自帶一個參數,是我們的 Slider 讀取到的圖片數量(index,由 0 開始計算),所以現在可以將 Paging 改成圖片的方式顯示,除此之外在參數中加上centerMode : true
,讓我們選取到的圖片可以顯示在畫面中間的位置。
由於需要讀取到圖片,所以在設定檔中將圖片的位置宣告成一個陣列,讓我們的 customPaging 可以利用 index 去讀取。
const imagesDots = [ "https://www.themoviedb.org/t/p/w220_and_h330_face/gGEsBPAijhVUFoiNpgZXqRVWJt2.jpg", "https://www.themoviedb.org/t/p/w220_and_h330_face/pHkKbIRoCe7zIFvqan9LFSaQAde.jpg", "https://www.themoviedb.org/t/p/w220_and_h330_face/62HCnUTziyWcpDaBO2i1DX17ljH.jpg", "https://www.themoviedb.org/t/p/w220_and_h330_face/m80kPdrmmtEh9wlLroCp0bwUGH0.jpg", "https://www.themoviedb.org/t/p/w220_and_h330_face/uJYYizSuA9Y3DCs0qS4qWvHfZg4.jpg", "https://www.themoviedb.org/t/p/w220_and_h330_face/65WFr1ZMAbEniIh4jEhbRG9OHHN.jpg", "https://www.themoviedb.org/t/p/w220_and_h330_face/kxB9E6fo0ycHzd13oOTHmGa5Njd.jpg",];const settings = { dots: true, infinite: true, speed: 500, slidesToShow: 3, slidesToScroll: 1, centerMode: true, responsive: [ { breakpoint: 480, settings: { slidesToShow: 1, slidesToScroll: 1, }, }, ], customPaging: (i) => { return ( <a> <img src={imagesDots[i]} /> </a> ); },};export default settings;
調整 Paging CSS
現在可以發現我們的 Paging 的圖片非常小張,現在來調整 Paging 的圖片大小。
在那之前還需要加上 dots 的 class 名稱,方便做調整:
const imagesDots = [ "https://www.themoviedb.org/t/p/w220_and_h330_face/gGEsBPAijhVUFoiNpgZXqRVWJt2.jpg", "https://www.themoviedb.org/t/p/w220_and_h330_face/pHkKbIRoCe7zIFvqan9LFSaQAde.jpg", "https://www.themoviedb.org/t/p/w220_and_h330_face/62HCnUTziyWcpDaBO2i1DX17ljH.jpg", "https://www.themoviedb.org/t/p/w220_and_h330_face/m80kPdrmmtEh9wlLroCp0bwUGH0.jpg", "https://www.themoviedb.org/t/p/w220_and_h330_face/uJYYizSuA9Y3DCs0qS4qWvHfZg4.jpg", "https://www.themoviedb.org/t/p/w220_and_h330_face/65WFr1ZMAbEniIh4jEhbRG9OHHN.jpg", "https://www.themoviedb.org/t/p/w220_and_h330_face/kxB9E6fo0ycHzd13oOTHmGa5Njd.jpg",];const settings = { dots: true, infinite: true, speed: 500, slidesToShow: 3, slidesToScroll: 3, dotsClass: "slick-dots slick-thumb", responsive: [ { breakpoint: 480, settings: { slidesToShow: 1, slidesToScroll: 1, }, }, ], customPaging: (i) => { return ( <a> <img src={imagesDots[i]} /> </a> ); },};export default settings;
.App { margin-top: 20px; padding: 0 calc(3.5vw + 80px); position: relative;}.wrap { width: 300px; outline: none;}img { border: 4px solid transparent; border-radius: 4px; margin: auto; box-shadow: rgb(0 0 0 / 69%) 0px 26px 30px -10px, rgb(0 0 0 / 20%) 0px 16px 10px -10px; transition-duration: 300ms; max-width: 100%;}img:hover { border: 4px solid rgba(249, 249, 249, 0.8);}.slick-dots li.slick-active button:before { color: #fff;}.slick-thumb { bottom: -120px;}.slick-thumb > li { width: 60px; margin: 0 20px;}
Active CSS
最後再來調整一點 CSS,當圖片被選到時,就將圖片調整成全彩的,其他沒被選到的圖片就設定為黑白的。
.App { margin-top: 20px; padding: 0 calc(3.5vw + 80px); position: relative;}.wrap { width: 300px; outline: none;}img { border: 4px solid transparent; border-radius: 4px; margin: auto; box-shadow: rgb(0 0 0 / 69%) 0px 26px 30px -10px, rgb(0 0 0 / 20%) 0px 16px 10px -10px; transition-duration: 300ms; max-width: 100%;}img:hover { border: 4px solid rgba(249, 249, 249, 0.8);}.slick-dots li.slick-active button:before { color: #fff;}.slick-thumb { bottom: -120px;}.slick-thumb > li { width: 60px; margin: 0 20px;}.slick-thumb li.slick-active img { -webkit-filter: grayscale(0); filter: grayscale(0);}.slick-thumb li img { -webkit-filter: grayscale(100%); filter: grayscale(100%);}.slick-slide:not(.slick-current) div div img { -webkit-filter: grayscale(100%); filter: grayscale(100%);}