iT邦幫忙

2022 iThome 鐵人賽

DAY 18
0
Modern Web

Have fun! 新手也能打造的Javascript微型專案系列 第 18

Have fun! 新手也能打造的Javascript微型專案! Day18: 總是心浮氣躁嗎? 利用垂直置中技巧做個簡單的冥想頁面吧!

  • 分享至 

  • xImage
  •  
tags: ItIron2022 Javascript

前言

最近開始迷上做佛系瑜伽,教學影片中其中都會穿插一些冥想的玩意,隨著導師的聲音深呼吸、吐氣,這樣的放鬆過程挺有意思的,今天就讓我們做一個超簡單的冥想頁面讓你可以專注在呼吸放鬆上吧!

預期成果

今天的成品應該是目前以來最為簡單的一個了,我們要做的僅是一個用文字與簡單的動畫引導你呼吸吐氣的玩意而已,javascript的部分也是短短幾行就可以完成了! 主要重點在於css的動畫處理以及垂直置中的技巧上,用輕鬆的心情一起來完成這個小專案吧!

Getting started

> Step1: 專案結構

一樣請你先建立index.html, style.css & script.js檔案,並在html & css檔案填入以下的內容,bg的圖片請至文末的專案repo那邊下載,我這邊就不再提供囉!

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Relaxer</title>
    <link rel="stylesheet" href="./style.css" />
    <script src="./script.js" defer></script>
  </head>

  <body>
    <h1>Relaxer</h1>
    <div class="container" id="container">
      <div class="circle"></div>
      <p id="text"></p>

      <div class="pointer-container">
        <span class="pointer"></span>
      </div>

      <div class="gradient-circle"></div>
    </div>
  </body>
</html>
@import url("https://fonts.googleapis.com/css?family=Montserrat&display=swap");

* {
  box-sizing: border-box;
}

body {
  background: #224941 url("./bg.jpg") no-repeat center center/cover;
  min-height: 100vh;
  color: #fff;
  font-family: "Montserrat", "sans-serif";
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
  margin: 0;
}

h1 {
  margin-top: 40px;
}

.container {
  display: flex;
  justify-content: center;
  align-items: center;
  margin: auto;
  height: 300px;
  width: 300px;
  position: relative;
  transform: scale(1);
}

.circle {
  background-color: #010f1c;
  height: 100%;
  width: 100%;
  border-radius: 50%;
  position: absolute;
  top: 0;
  left: 0;
  z-index: -1;
}

.gradient-circle {
  background: conic-gradient(
    #55b7a4 0%,
    #4ca493 40%,
    #fff 40%,
    #fff 60%,
    #336d62 60%,
    #2a5b52 100%
  );
  width: 320px;
  height: 320px;
  border-radius: 50%;
  position: absolute;
  z-index: -2;
  top: -10px;
  left: -10px;
}

.pointer {
  background-color: #fff;
  border-radius: 50%;
  height: 20px;
  width: 20px;
  display: block;
}

.pointer-container {
  position: absolute;
  top: -40px;
  left: 140px;
  width: 20px;
  height: 190px;
  animation: rotate 7.5s linear forwards infinite;
  transform-origin: bottom center;
}

@keyframes rotate {
  from {
    transform: rotate(0deg);
  }

  to {
    transform: rotate(360deg);
  }
}

/* add animations for js trigger */
.container.grow {
  animation: grow 3s linear forwards;
}

@keyframes grow {
  from {
    transform: scale(1);
  }

  to {
    transform: scale(1.2);
  }
}

.container.shrink {
  animation: shrink 3s linear forwards;
}

@keyframes shrink {
  from {
    transform: scale(1.2);
  }

  to {
    transform: scale(1);
  }
}

包含bg.jpg檔案,你的專案結構目前應該是這樣的。

畫面上看起來也很正常,先忽略那個轉來轉去的小圓球。

我們css檔案中有幾個點你需要注意一下

  • 我們在檔案中利用keyframe寫了兩個暫時還沒用到animation,分別是grow & shrink,之後需要配合js讓整個圓圈在該吸氣的時候放大、呼氣時縮小
  • 在這次的範例中我用了flex container配合justify-content & align-items達到水平與垂直置中,css發展到現在能達到相同效果的做法已有數十種,建議你可以用css垂直置中這樣的關鍵字去查一下,是非常熱門的面試問題,至少準備個3種以上的語法在身上比較保險。
  • 為了讓圓圈配合呼吸、屏氣以及吐氣,我在這邊使用了conic-gradient語法,可以讓圍圈在我指定的範圍內做不同顏色的變化,另外再配合一個黑色的circle div蓋在它上方做出外圍變色圈的假象,實際上原本這樣的,不同元素的疊放也是很常見的技巧。

> Step2: 完成js檔案

雖然我們這次要做的邏輯相當簡單,但還是養成好習慣,動手前先好好想一想吧!
注意到我們上方css檔案中有個rotate的動畫,也就是讓小球繞著轉的那個動畫,我們在css設定中讓它每7.5秒轉一圈,因此我們在利用js讓整個大圓圈放大縮小時也要特別注意這個時間。根據我們之前在conic-gradient的比例規劃(可參照上方的圓餅圖),呼吸、屏氣與吐氣的比例應該為40%:20%:40%,也就是2:1:2,以7.5秒為一圈的話便是3秒、1.5秒與三秒!

最困難的地方就在這邊結束了,我們現在要做的事情就很簡單囉,我們需要照以下的邏輯處理

  1. 載入頁面一開始就加入grow class讓圓圈開始變大
  2. 3秒後停止變大並開始計時1.5秒(屏氣的時間)
  3. 1.5秒後加入shrink class讓圓圈縮小
  4. 利用定時器讓以上行為每7.5秒重複一次

因此整個js的結構會是這樣的

選取整個圓圈元素與中間顯示文字的元素
宣告相關時間變數
  總長: 7.5秒
  屏氣: 1/5 * 總長
  吸氣: 2 * 屏氣

建立觸發呼吸動畫的函數,其中函數內結構為
  加入grow class讓整個容器放大,中間顯示請吸氣文字
  吸氣時間後將文字改為屏氣,並利用屏氣時間建立新的計時器
  屏氣後加入shrink class讓容器縮小,中間顯示請吐氣文字
  
呼叫第一次的觸發呼吸動畫函數
建立定時器每總長時間便執行以上函數

理解以上結構後就可以把以下程式碼寫入js檔案中囉!

const container = document.getElementById("container");
const text = document.getElementById("text");

const totalTime = 7500;
const holdTime = totalTime / 5;
const breatheTime = holdTime * 2;

function breatheAnimation() {
  text.innerText = "Breathe in!";
  container.className = "container grow";
  setTimeout(() => {
    text.innerText = "Hold it!";
    setTimeout(() => {
      text.innerText = "Breathe out!";
      container.className = "container shrink";
    }, holdTime);
  }, breatheTime);
}
breatheAnimation();
setInterval(breatheAnimation, totalTime);

完美! 一切順利的運作,雖然簡單但看起來卻挺有一回事的對吧?

總結

今天我們做了一個很簡單的冥想專案,重點反而在css的處理上(垂直置中的部分我強烈新手們去研究一下,方法真的非常多,而且很常考),js的部分唯一複雜的地方是setTimeout & setInterval的使用,實際上js的部分是可以再做優化的,setTimeout這樣層層包裝其實可讀性並不高,是有辦法透過promise & async/await去改寫的,但這就超出這系列文的範圍,就交給有心人自己研究囉!

文章中的範例程式碼可以在這邊取得,歡迎自行取用

轉職Q & A

Danny,我在面試過程中不免俗地被問到期待的薪水,這種問題我該怎麼回答啊?

來了,難度最高的問題之一,確實是個好問題!這邊僅是我個人主觀的想法,你可以作為參考但不要當作教科書來用 :D 首先你必須先知道市場上的行情,這點在一開始的文章中我們就有提到目前jr市場的薪資區間,有這樣的基本概念後我們再來談薪水。

我個人在談薪水的時候會習慣以年薪為單位去跟對方談,畢竟有不少公司是月薪普普但靠獎金跟年終把整包薪資撐起來的,用年薪會更方便對方去操作,也比較不會因為月薪的期待差太多而錯過一些機會。接著就是要喊多少年薪的問題,我知道新人喊價是很困難的事情,但你可以在心裡根據求職地區以及個人期待先規劃一個可接受的區間,比方說年薪60~80,雖然大概率對方會直接用你的底線區間做核薪的依據,但畢竟也是你能接受的數字,之後再透過面試的過程去調整你的區間,尤其當你實際拿到數份offer後你會更理解自己的價碼,可能會覺得之前預設的數字太低/太高,這時候就可以在之後的面試過程去調整。

薪資協議是一種談判,手持offer的情況要談判自然會更輕鬆一點,你也可以用既有的offer去做competitive offer強制拉高對方的價碼,但我會建議一切誠實,不要為了把價錢提高而虛報數字,弄得不好最後兩邊都打水漂就好笑了,這是一門藝術,我自己也還在學習!
不實際出去面試你很難知道自己現在到底值什麼價碼,就放膽去試吧! 真的沒有正確的答案,一切因人因地而異!

本文章同步發布於個人部落格,有興趣的朋友也可以來逛逛~!


上一篇
Have fun! 新手也能打造的Javascript微型專案! Day17: 用打字猜數字無聊? 那就用SpeechRecognition語音猜數字唄!(下)
下一篇
Have fun! 新手也能打造的Javascript微型專案! Day19: 觀念跟語法老是忘記? 那寫個flash-card程式來幫助自己記憶吧!(上)
系列文
Have fun! 新手也能打造的Javascript微型專案30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言