iT邦幫忙

2022 iThome 鐵人賽

DAY 19
0
自我挑戰組

在30天利用HTML & CSS & JavaScript完成Side Project實作系列 第 19

Day 19 Side Project : Double Vertical Slider雙捲軸

  • 分享至 

  • xImage
  •  


今天要來做的是垂直的輪播圖,點選「上」「下」箭頭可以反方向切換圖片和圖片的描述,做project順便看看帥哥好快樂≡ω≡


事前準備

  1. 引入 fontAwesome 的cdn,並選擇第一個all.min.css
    https://cdnjs.com/libraries/font-awesome
    https://ithelp.ithome.com.tw/upload/images/20220920/20149362MVi9dFqqwW.png

  2. 準備3~5張喜歡的圖片


畫面和功能拆解

https://ithelp.ithome.com.tw/upload/images/20220925/20149362h7Zq7oEdab.png

  1. 畫面可以簡化成左右兩邊,左邊是圖片描述,右邊是圖片
  2. 點「上」「下」箭頭,圖片和描述會以反方向切換

運用知識點羅列

  • CSS
知識點 使用說明
transform 調整元素位置
transition 控制畫面轉變的時間及變化曲線
  • JS
知識點 使用說明
addEventListener 為上下箭頭加入事件監聽
clientHeight 獲取元素內部高度

流程講解

  • HTML
    左邊-圖片描述
 <div class="container">
        <div class="left-side">
            <!-- 描述一 -->
            <div style="background-color:...;">
                <h1>Thor</h1>
                <p><img src="..." alt="tomato"> Rotten Tomatoes 71%</p>
            </div>

            <!-- 描述二 -->
            <div style="background-color:...;">
                <h1>Loki</h1>
                <p> <img src="..." alt="tomato"> Rotten Tomatoes 92%</p>
            </div>

            <!-- 描述三 -->
            <div style="background-color:...;">
                <h1>Doctor Strange</h1>
                <p><img src="..." alt="tomato"> Rotten Tomatoes 80%</p>
            </div>
        </div>

右邊-圖片
圖片的順續會剛好相反,左邊按照1~3的順序,右邊就3~1,最後的要放在第一個,因為左右兩邊方向相反,所以才這樣寫

        <div class="right-side">
            <!-- 圖片三 -->
            <div style="background-image: url('...');"></div>
            <!-- 圖片二 -->
            <div style="background-image: url('...');"></div>
            <!-- 圖片一 -->
            <div style="background-image: url('...');"></div>
        </div>

按鈕

        <div class="button-group">
              <button class="up-btn">
                <i class="fa-solid fa-arrow-up"></i>
            </button>
            <button class="down-btn">
                <i class="fa-solid fa-arrow-down"></i>
            </button>
        </div>

呈現如下圖,因為還沒有給予寬和高撐起div,所以看不到背景圖片
https://ithelp.ithome.com.tw/upload/images/20220925/20149362i1v5pmulKu.png


  • CSS
    大局配置
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  height: 100vh;
  color: white;
}

外部容器

.container {
  position: relative;
  overflow: hidden;
  width: 100vw;
  height: 100vh;
}

左邊-圖片描述

.left-side {
  height: 100%;
  width: 35%;
  position: relative;
  left: 0;
  top: 0;
}
.left-side > div {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
.left-side h1 {
  font-size: 40px;
  margin-bottom: 10px;
  margin-top: -30px;
}

右邊-圖片

.right-side {
  position: absolute;
  width: 65%;
  height: 100%;
  top: 0;
  left: 35%;
}
.right-side div {
  background: no-repeat center/cover black;
  height: 100%;
  width: 100%;
}

按鈕

.container .button-group button {
  position: absolute;
  left: 35%;
  top: 50%;
  z-index: 100;
  background-color: white;
  border: 0;
  cursor: pointer;
  font-size: 16px;
  padding: 10px;
}

以上都設好,呈現如下圖
https://ithelp.ithome.com.tw/upload/images/20220925/20149362Ru2Mj4txEi.png
「上」的箭頭不見了,因為被「下」箭頭擋住啦ヽ( ຶ▮ ຶ)ノ
那除了用絕對定位以外,還有什麼方法可以調整它的位子呢?

是裡是用...

Transform
把下箭頭悄悄做個位移(translateX),並把垂直高度調整一下(translateY)

/* 下 */
.container .button-group button.down-btn {
  transform: translateX(-100%) translateY(100%);
}

呈現如下
https://ithelp.ithome.com.tw/upload/images/20220925/20149362vbmW11stYr.png

最後再做一點圓角以及按鈕滑過和被點的效果

/* 上 */
.container .button-group button.up-btn {
  border-bottom-right-radius: 10px;
}
/* 下 */
.container .button-group button.down-btn {
  transform: translateX(-100%) translateY(100%);
  border-bottom-left-radius: 10px;
}
.container .button-group button:hover {
  color: #999;
}
.container .button-group button:focus {
  outline: 0; /*或none*/
}

好哩!以上都寫好,呈現如下,接下來要進入JS的部分
https://ithelp.ithome.com.tw/upload/images/20220925/20149362xWliujBD8J.png


  • JS(製作滑動功能)
    變數設置和初始化
let container = document.querySelector(".container");
let rightSide = document.querySelector(".right-side");
let leftSide = document.querySelector(".left-side");
let upBtn = document.querySelector(".up-btn");
let downBtn = document.querySelector(".down-btn");
let rightSideLength = rightSide.querySelectorAll("div").length;  //圖片數量=3
let activeImgIdx = 0;  //圖片索引

截一張目前的畫面
https://ithelp.ithome.com.tw/upload/images/20220925/20149362k5ZxqVYFMq.png
索爾對到的圖片是奇異博士 (。﹏。*) 想把左邊換成奇異博士 Doctor Strange 該怎麼做呢?

可以參考如下寫法

leftSide.style.top = `-${(rightSideLength - 1) * 100}%`;  //%也可以用vh代替

leftSide.style.top 是我們針對左側的高度來做調整

  1. 首先設置成負數,因為實際上它跟右邊是反方向的,所以要把初始值設為負數
  2. rightSideLength - 1 這整個印出來會等於2,rightSideLength代表圖片總數量(=3),-1是因為索引是從0開始
  3. 乘以100%,是代表高度的百分比,寫成vh(視口高度)也有同樣效果

以上寫好呈現如下
https://ithelp.ithome.com.tw/upload/images/20220925/20149362j7APqYeYy4.png
好哩! 奇異博士對到正確的描述了ก็ʕ•͡ᴥ•ʔ ก้ 接下來對按鈕去添加事件監聽

upBtn.addEventListener("click", () => {
  changeImg("up");
});

downBtn.addEventListener("click", () => {
  changeImg("down");
});

changeImg = (direction) => {
  let imgHeight = container.clientHeight;
  console.log(imgHeight);
  //後面還有
};

clientHeight

The Element.clientHeight read-only property is zero for elements with no CSS or inline layout boxes; otherwise, it's the inner height of an element in pixels. It includes padding but excludes borders, margins, and horizontal scrollbars (if present).
擷取至MDN

大致上是說 clientHeight 是唯獨屬性,代表元素的內部高度,單位為px。它包括padding,但不包括border、margin和水平滾動條(如果存在)

簡單來說
clientHeight = height + padding - height of horizontal scrollbar(水平滾動條的高度).

繼續接下來的設定

let changeImg = (direction) => {
  let imgHeight = container.clientHeight;
  console.log(imgHeight);
  if (direction === "up") {
    activeImgIdx++;
    if (activeImgIdx > rightSideLength - 1) {
      activeImgIdx = 0;
    }
  }
  rightSide.style.transform = `translateY(-${activeImgIdx * imgHeight}px)`;
};

當「上」的箭頭被點按(direction為up)時,activeImgIdx 圖片索引就要 + 1,圖片到底時會直接回到第一張(activeImgIdx = 0)
imgHeight必須是動態的,且要在Y軸上移動,所以到了translateY出馬的時刻,利用圖片的索引 * 元素內部高度計算出要位移的距離

設定好呈現如下,點「上」箭頭圖片會切換了

我想要圖片可以不要那麼死板板的出現,可以加上transition去設定
所以我們回到CSS的部分,加上transition: transform 0.5s ease;,讓滑進效果自然點
https://ithelp.ithome.com.tw/upload/images/20220925/20149362DHtKlztbrz.png

最後最後,終於要結束了 剩左邊的圖片描述和「下」箭頭要處理(為了完整性,截取整段code)

let changeImg = (direction) => {
  let imgHeight = container.clientHeight;
  console.log(imgHeight);
  if (direction === "up") {
    activeImgIdx++;
    if (activeImgIdx > rightSideLength - 1) {
      activeImgIdx = 0;
    }
  } else {
    activeImgIdx--;
    if (activeImgIdx < 0) {
      activeImgIdx = rightSideLength - 1;
    }
  }
  rightSide.style.transform = `translateY(-${activeImgIdx * imgHeight}px)`;
  leftSide.style.transform = `translateY(${activeImgIdx * imgHeight}px)`;
};

左右兩邊設定會相反,所以 leftSide.style.transform = translateY(${activeImgIdx * imgHeight}px)為正數,「下」箭頭的部分就把activeImgIdx++改為activeImgIdx-- ,如果到了第一張圖片時,再點上箭頭會回到最後一張,就這樣一直循環

附上codepen連結 https://codepen.io/hangineer/pen/OJZOgzK
今天的介紹到這裡(✿◡‿◡)若有解說不夠詳盡或是錯誤歡迎指教,感激不盡!那明天見囉


參考資料

50 Projects In 50 Days - HTML, CSS & JavaScript
MDN-clientHeight
索爾圖片參考
洛基圖片參考
奇異博士圖片參考


上一篇
Day 18 Side Project : Drag N Drop 拖與拉
下一篇
Day 20 Side Project : Password Generator 密碼生成器(上)
系列文
在30天利用HTML & CSS & JavaScript完成Side Project實作30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言