iT邦幫忙

2022 iThome 鐵人賽

DAY 5
0

https://i.imgur.com/VuhDOSg.jpg

組件實作 : Demo

一、前言

slideshow 幻燈片組件可以為網頁帶來動態的效果,與使用者產生互動,我們用 6 張圖片組成一個輪播視窗。你除了可以使用視窗兩側的箭頭來切換圖片,也可以按下小圓點來切換,slideshow 除了可放在<head>當作顯眼的看板,也可以放在側邊欄或是文章內部等任何你想放置的地方,用途很廣泛。不說廢話,現在就開始來實作吧~


二、直接實作 Slideshow 組件

我們參考 How TO - Slideshow【1】來製作,首先,在一個 class 名稱為slide__item的 div 中先加入文字和圖片等相關資訊,slide__item總共需要製作 6 個,最外層我們用一個 class 名稱為slideshow的 div 包住所有元素。

HTML:

<div class="slide__item fades">
  <div class="slide__pagenumber">1 / 6</div>
  <img src="https://picsum.photos/1920/400?random=1" />
  <div class="slide__content">Hello page 1</div>
</div>

顯示結果:

https://i.imgur.com/yv07Wu6.jpg

快速介紹上述程式碼用途:slide__item用來放一張幻燈片需要的所有元素,fades 是切換時的動畫效果,slide__pagenumber放的是切換時顯示的頁數,img 則是使用 Fake images,slide__content則是圖片的說明文字。

把剛剛的程式碼放到名稱為slideshow的 div 中,看你要放多少張圖片,就寫多少個slide__item

HTML:

<div class="slideshow">
  <div class="slide__item fades">
    <div class="slide__pagenumber">1 / 6</div>
    <img src="https://source.unsplash.com/random/1920x400?sig=1" />
    <div class="slide__content">Hello page 1</div>
  </div>
  <div class="slide__item fades">
    <div class="slide__pagenumber">2 / 6</div>
    <img src="https://source.unsplash.com/random/1920x400?sig=2" />
    <div class="slide__content">Hello page 2</div>
  </div>
  <div class="slide__item fades">
    <div class="slide__pagenumber">3 / 6</div>
    <img src="https://source.unsplash.com/random/1920x400?sig=3" />
    <div class="slide__content">Hello page 3</div>
  </div>
  <div class="slide__item fades">
    <div class="slide__pagenumber">4 / 6</div>
    <img src="https://source.unsplash.com/random/1920x400?sig=4" />
    <div class="slide__content">Hello page 4</div>
  </div>
  <div class="slide__item fades">
    <div class="slide__pagenumber">5 / 6</div>
    <img src="https://source.unsplash.com/random/1920x400?sig=5" />
    <div class="slide__content">Hello page 5</div>
  </div>
  <div class="slide__item fades">
    <div class="slide__pagenumber">6 / 6</div>
    <img src="https://source.unsplash.com/random/1920x400?sig=6" />
    <div class="slide__content">Hello page 6</div>
  </div>
</div>

顯示結果:

https://i.imgur.com/U5pMv99.jpg

左右兩側切換的箭頭按鈕,使用兩個 a 標籤來實作。

HTML:

<a id="prev" class="slide__arraw slide__arraw--prev"> ❮ </a>
<a id="next" class="slide__arraw slide__arraw--next"> ❯ </a>

製作六個小圓點,使用 class 名稱為dot的 div 來製作。(data-value只是用來識別有幾個dot)。

HTML:

<div class="slide__dot">
  <div class="dot" data-value="1"></div>
  <div class="dot" data-value="2"></div>
  <div class="dot" data-value="3"></div>
  <div class="dot" data-value="4"></div>
  <div class="dot" data-value="5"></div>
  <div class="dot" data-value="6"></div>
</div>

小圓點的 CSS 的外觀製作,相關的屬性寫在 class 名稱為 dot 的 div 中。

CSS:

.dot {
  width: 15px;
  height: 15px;
  margin: 0 5px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.1);
  background: rgba(255, 255, 255, 0.3);
  box-shadow: 0px 0px 2px 2px rgba(255, 255, 255, 0.3);
}

再來,為了讓畫面滿版,需要讓多餘 margin 和 padding 消失。

CSS:

* {
  margin: 0;
  padding: 0;
}

針對圖片的處理,我們想要一個寬度滿版,高度為 400 px 的圖片,object-fit可以用來調整圖片的內容【1】。transition用於動畫的過渡效果,例如 transition: 0.5s;指的是整個動作要再 0.5 秒之內結束。而transform有讓元素有各種效果【2】,比如讓圖片位移、旋轉、縮放等等,transform可以搭配transition使用,對於 img 相關的 CSS 設定如下。

CSS

img {
  width: 100%;
  height: 400px;
  object-fit: cover;
  vertical-align: middle;
  transition: 0.5s;
}
img:hover {
  transform: scale(1.5);
  transition: 0.5s;
}

寫到這裡,你的圖片應該會有縮放的效果,在來是對slideshow內部元素做設定,slideshow是包在最外面的父層,我們用它來所有的圖片,以及剛剛的切換頁面箭頭和圓點位做修改。

CSS:

.slideshow {
  position: relative;
  transition: 2s;
  user-select: none;
}

.slide__item {
  display: none;
  position: relative;
  overflow: hidden;
}
.slide__pagenumber {
  padding: 10px;
  border-radius: 80% 30% / 80% 50%;
  background: rgba(0, 0, 0, 0.7);
  color: white;
  position: absolute;
  right: 0;
  z-index: 1;
}
.slide__content {
  position: absolute;
  color: white;
  background: rgba(0, 0, 0, 0.5);
  bottom: 0;
  padding: 0 10px;
  border-radius: 5px;
}
.slide__arraw {
  padding: 20px;
  position: absolute;
  line-height: 20px;
  font-size: 20px;
  text-decoration: none;
  color: white;
}
.slide__arraw:hover {
  background: rgba(0, 0, 0, 0.7);
  border-radius: 5px;
  color: white;
  cursor: pointer;
  transition: 0.6 ease;
}
.slide__arraw--prev {
  position: absolute;
  top: 50%;
  left: 0;
  transform: translateY(-50%);
}
.slide__arraw--next {
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
}
.slide__dot {
  padding: 5px 5px;
  display: flex;
  position: absolute;
  bottom: 0px;
  left: 50%;
  transform: translateX(-50%);
}

transform: translateX(-50%); 置中寫法可參考 position 用法【3】。


三、製作圖片切換的效果

實際上,圖片的切換靠的是索引值slideIndex(我們先預設slideIndex值為1)的切換來決定要顯示哪一張圖片,主要的切換功能寫在 showSlide()這個 Funciotn 中。那麼該如何更改slideIndex的索引值呢?先直接看所有的 JavaScript 程式碼。

JavaScript:

window.onload = function () {
  let slideIndex = 1;
  showSlide(slideIndex);

  let prev = document.getElementById("prev");
  prev.addEventListener("click", divideSlides, false);

  let next = document.getElementById("next");
  next.addEventListener("click", plusSlides, false);

  const selectdot = document.querySelectorAll(".dot");
  for (let i = 0; i < selectdot.length; i++) {
    selectdot[i].addEventListener("click", function (e) {
      showSlide((slideIndex = i + 1));
    });
  }

  function plusSlides() {
    showSlide((slideIndex += 1));
  }

  function divideSlides() {
    showSlide((slideIndex -= 1));
  }

  function showSlide(num) {
    let slides = document.getElementsByClassName("slide__item");
    let dots = document.getElementsByClassName("dot");
    if (num > slides.length) {
      slideIndex = 1;
    }

    if (num < 1) {
      slideIndex = slides.length;
    }
    for (let i = 0; i < slides.length; i++) {
      slides[i].style.display = "none";
    }
    for (let i = 0; i < dots.length; i++) {
      dots[i].className = dots[i].className.replace("active", "");
    }

    slides[slideIndex - 1].style.display = "block";
    dots[slideIndex - 1].className += " active";
  }
};

首先,slideIndex的值設為 1,我們使用 prev 和 next 來當作 a 元素被切換時要做的事件監聽,prev 為左邊箭頭被按下時,會執行 divideSlides()這個 Funciotn,就是把當前索引值 slideIndex 給減一,而next則是與prev功能相似(使用plusSlides()),只不過它是將索引值加一。

selectdot則是處理那六個小圓點,每當小圓點被選擇時,slideIndex 索引值會被改變,再來看showSlide這個 Funciotn,slides會對應到 class 名稱為slide__item的 div,這東西其實是控制整個圖片,如果我們要讓圖片隱藏或是顯示,只要控制它就行。dots則是用控制所有的 dot,也就是所有的小圓點。

if (num < 1)或是if (num < 1)這個主要是判別索引值的大小,不要超過這 6 張圖片的範圍,若是超過範圍,就讓索引值為最大或是最小的那個編號。

slides[i].style.display = "none";這句寫法用在:把所有的圖片都設為隱藏,而它對應的是 slides[slideIndex - 1].style.display = "block";這一句寫法,另外,與它相似的另外一個要被清除的東西,則是dotsactive,使用dots[i].className.replace("active","")是為了讓dot小圓點上面,全部有active的 class 都被清除掉,也就是把 dot 上面的所有 class=”active”全部都給移除乾淨。不論是slidesnone,或是dotsactive,都跟下方的兩句程式碼有所關係。

JavaScript:

slides[slideIndex - 1].style.display = "block";
dots[slideIndex - 1].className += "active";

slides 是針對 slideIndex 索引值來開啟相對應的slide__item,而 dots 則是被滑鼠選種的小圓點,會加上active這個 class名稱,但這東西會累加,所以先前才會需要把所有的active都給移除乾淨。

最後,我們再 CSS 裡面補上 dot 為 active 時的效果,以及增加 fades 為切換圖片時產生的特效,至於@keyframesm用法會在後續文章裡補上,這裡先拿來用。程式碼這樣寫。

CSS:

.active,
.dot:hover {
  background: rgba(255, 255, 255, 0.9);
  cursor: pointer;
}

.fades {
  animation: 1.5s fades;
}
@keyframes fades {
  from {
    opacity: 0.4;
  }
  to {
    opacity: 1;
  }
}

顯示結果:

https://i.imgur.com/ljVpg3S.jpg

假如你要讓圖片有自動播放的功能,可以在你的 JavaScript 中加入一個setInterval()來讓圖片可以每隔 3 秒自動的播放。

setInterval(function () {
	plusSlides();
}, 3000);

為了確保記憶體內存不會被耗光,在這邊的 HTML 中加入一個refresh,讓它過每 1 分鐘便會自動刷新頁面一次。 (content裡面數值單位為秒)

<meta http-equiv="refresh" content="60" />

在 CodePen 中則改用history.go(0);代替refresh

setInterval(function () {
	history.go(0);
}, 60000);

因為不清楚會不會有什麼 Function 或是什麼其他原因導致記憶體被吃掉,所以我們用一個refresh來讓頁面刷新。需要注意的地方則是,在 CodePen 用 <meta http-equiv="refresh" content="60" /> 會沒有效果,改用history.go(0);代替,用法可參考Reload on click function not working in javascript。(會有 Page Not Found,故暫不採用 history.go(0);


四、推薦資源

  1. Slideshow Gallery
  2. slideshow-codepen
  3. CodePen Home Slideshow, CSS only
  4. Examples | Keen-Slider
  5. Swiper Demos
  6. 5 Modern JS Sliders for 2022
  7. 7 Awesome JavaScript Carousel Libraries
  8. How TO - Image Comparison Slider
  9. W3.CSS Slideshow

五、結論

雖然 Slideshow 它的原理很簡單,只是靠著索引值來去或是隱藏對應的區塊。但是要我再寫一次一模一樣的東西,我沒有把握能寫的完全一樣,或許過一陣子後,我會找到更好的做法來去取代它,這東西要實作出來,肯定會花一點時間。但是這功能也算挺常見,它可以讓網頁站起來變得更生動,個人認為學起來也是一個挺不錯的選擇!


六、參考資料

  1. How TO - Slideshow
  2. [CSS] object-fit / object-position 調整置換元素(img..等)的內容
  3. Center an item with position: relative

上一篇
Day 04:多媒體資源匯入
下一篇
Day 06:Loader 組件實作
系列文
從零開始手刻網站,30 天打造我的前端武器庫30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
d_shadow
iT邦新手 5 級 ‧ 2023-08-10 21:52:07

dots[i].className = dots[i].className.replace("active", "");
跟dots[slideIndex - 1].className += " active";
改成這樣會不會比較好
dots[i].classList.remove("active");
dots[slideIndex - 1].classList.add("active");
不然選擇器.dot標籤一直變長

我要留言

立即登入留言