# 五金行日曆 ![](https://i.imgur.com/CJ4Hpge.jpg =600x) > [FIVE METAL SHOP CALENDAR 五金行日曆 2020](https://www.shoppingdesign.com.tw/post/view/4618/) 一直很喜歡這本可愛又充滿設計感的傳統日曆,但是礙於懶人個性一定放到明年還在第一頁 太可愛了也會捨不得撕,趁著這次練習 Date(),不如就自己手刻一本。 ## 重點語法 撰寫語法使用 SASS,如果看不習慣的話可以轉譯成 CSS 主要會頻繁使用到以下語法: * **flex** * **transform: translate、skew、scale** * **background: linear-gradient** * **box-shadow** * **text-shadow** **<font color="red">*這次 CodePen 設定 CSS Base 有開啟 Reset</font>** ## 一、分析架構 開始切版之前,首先要分析架構 就像蓋房子一樣,地基要打得穩,房子才能蓋的堅固 如果是初學者,建議可以試著在紙上畫出網頁架構 **外框容器** * calendar:日曆主體,用 `after` 製作厚度 * header:上方裝訂,用 `before` 製作厚度 * hook:掛鉤部分 * body:主要呈現內容 ![](https://i.imgur.com/DU1OuvE.jpg =500x) **資料內容** * month:上方當月月份 * date:今天日期 * fullMonth:小月曆 * week:星期、農曆 * icons:小圖示 ![](https://i.imgur.com/dkzGprg.jpg =500x) ## 二、HTML 切版 框架分析完後,就可以開始切框架 切版時先放入靜態資料,模擬放入資料的狀況,調整樣式也較準確 <font color="red">*****</font> 可以在 css 最上方加入這段,自動把所有物件加上外框 ``` * { outline: 1px solid red } ``` ```htmlmixed= <div id="app"> <div class="calendar"> <div class="header"> <div class="pin"></div> <p>2020</p> <div class="pin"></div> </div> <div class="hook"></div> <div class="body"> <div class="month"> <p>8</p> <p>Aug</p> </div> <div class="date">11</div> <div class="footer"> <div class="fullMonth"> <div class="title">August</div> <table> <tr> <th>...</th> </tr> <tr> <td>...</td> </tr> </table> </div> <div class="week"> <p class="en">tuseday</p> <p class="day">星期二</p> <p class="lunar">農6-22</p> </div> <div class="icons"> <div class="material-icons">wb_sunny</div> <div class="material-icons">cloud</div> <div class="material-icons">brightness_1</div> </div> </div> </div> </div> </div> ``` **小月曆** 的部分會有字體沒辦法再縮小的問題: 1. 可以用 `transform: scale` 來縮小整體 2. 再用 `transform-rigin` 調整中心位置 3. 加上 `ransform: translate` 調整位移 初步完成如下圖: ![](https://i.imgur.com/oH2UXha.png =500x) ## 三、用偽元素製作細節 框架完成後,為避免框架上有太多元件 裝飾性質的東西可以用 `before`、`after` 來完成 ( 下圖綠色部分 ) **月曆厚度** 可以用 `transform: skew` 製作傾斜效果 先用 `scale` 放大會比較好對齊,邊調整位置和角度,讓兩條厚度可以接在一起 ![](https://i.imgur.com/6yZU2u4.png =500x) ## 四、陰影運用 陰影 `box-shadow` 的運用是繪製實物時最重要的部分,可以分為幾種方式: ### 基本陰影堆疊 陰影可以無限堆疊,並且設定不同位移、強度、顏色 依照畫面的需求堆疊出陰影,增加立體感 ![](https://i.imgur.com/pRY5Bhs.png =500x) ### 利用陰影製作重複元素 陰影除了堆疊,也可以用來製作複製元素 利用 **位移變化** 和相同 **陰影強度(模糊效果)**,可以做出頁邊色票 魔鬼藏在細節中,切版最重要的就是細心和耐心 推薦文章: [CSS 模糊效果](https://www.oxxostudio.tw/articles/201407/css-blur.html) ```sass box-shadow: 0 0 2px 1px #79746B, 1px*1 -22px*1 2px 1px #A07F2E, 1px*2 -22px*2 2px 1px #884940, 1px*3 -22px*3 2px 1px #216164, 1px*4 -22px*4 2px 1px #853555, 1px*5 -22px*5 2px 1px #628279, 1px*6 -22px*6 2px 1px #493B62, 1px*7 -22px*7 2px 1px #772C22, 1px*8 -22px*8 2px 1px #436251, 1px*9 -22px*9 2px 1px #0B6575, 1px*10 -22px*10 2px 1px #99834C, 1px*11 -22px*11 2px 1px #4D4229, 1px*12 -22px*12 2px 1px #89425A, 1px*13 -22px*13 2px 1px #5A4C6A, 1px*14 -22px*14 2px 1px #975B4B ``` ![](https://i.imgur.com/WVFgEVM.png =500x) ## 五、抓取時間 加上顏色和相關細節設定後,就要來加入時間內容 ### 日期、星期 ```javascript= const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] const days = ['日', '一','二','三','四','五','六'] const en = ['sunday', 'monday','tuseday','wednesday','thursday','friday','saturday'] const today = new Date() const yy = today.getFullYear() const mm = today.getMonth() const dt = today.getDate() const dy = today.getDay() function render (){ getElemt('.header p').innerHTML = `${yy}` getElemt('.month').innerHTML = ` <p>${mm + 1}</p> <p>${months[mm].substring(0, 3)}</p>` // 取出前三個字元 getElemt('.date').innerHTML = `${dt}` getElemt('.fullMonth .title').innerHTML = `${months[mm]}` getElemt('.week .day').innerHTML = `星期${days[dy]}` getElemt('.week .en').innerHTML = `${en[dy]}` } ``` ### 電子鐘 ```javascript= function timer (){ let newTime = new Date() let h = newTime.getHours() let m = newTime.getMinutes() let s = newTime.getSeconds() let hour = ((h < 10) ? '0' : '') + h let min = ((m < 10) ? '0' : '') + m let sec = ((s < 10) ? '0' : '') + s getElemt('.timer').innerHTML = `${hour}:${min}:${sec}` } setInterval(timer, 1000) ``` ## 六、製作小月曆 ### 取得當月份總天數 * 當月的第32天 - 當天日期 = 當月最後一天 * 舉栗:8月的第32天為9/1,32-1=31 * 得到8月的最後一天為31號,當月有31天 ```javascript= function daysInMonth(m, y) { return 32 - new Date(y, m, 32).getDate() } ``` ### 小月曆本人 參考資料:[Challenge of building a Calendar with Pure JavaScript](https://link.medium.com/1UTiIVbCP8) ```javascript= function calendar (year, month){ let firstDay = (new Date(year, month)).getDay() // 取得當月第一天 let date = 1 // 當月第一天/日期,起始值 for( let r=0; r<6; r++ ) { // 最多6行 let row = createElemt('tr') let cell, cellText for ( let i=0; i<7; i++) { // 一星期7天,最多7列 if( r === 0 && i < firstDay ) { // 第0列,且當週 < 7天,填補空格 cell = createElemt('td') row.appendChild(cell) } else if ( date > daysInMonth(month, year) ) { // 若當天日期 > 當月最後一天,跳出現在迴圈 break } else { cell = createElemt('td') cellText = document.createTextNode(date) // 補上空格並填入日期 if( year === yy && month === mm && date === dt ) { cell.classList.add('now') // 今天日期加上 now } cell.appendChild(cellText) row.appendChild(cell) date ++ } } getElemt('.fullMonth table').appendChild(row) } } ``` ### 農曆計算 參考資料:[1900年至2100年公历、农历互转Js代码](https://blog.jjonline.cn/userInterFace/173.html) ## 七、關燈效果 ![](https://i.imgur.com/EDIaxAp.png =x420)![](https://i.imgur.com/XGvytrh.png =x420) 運用 `text-shadow` 的堆疊方式就可以做出文字發光效果 開關的部分我用 `checkbox` 和 `label` 做簡單的切換 * HTML ```htmlmixed= <div class="lightBtn"> <input id="btn" type="checkbox"/> <label for="btn"> <span class="off">關燈</span> <span class="on">開燈</span> </label> </div> ``` * SASS ```sass= #btn display: none // 隱藏 checkbox #btn:checked ~ label // 點選 checkbox 後,變更 label 內設定 .off // 關燈樣式 ON .on // 開燈樣式 OFF ``` * JavaScript ```javascript= const btn = getElemt('#btn') btn.addEventListener('click', () => { if( btn.checked ) { getElemt('body').classList.add('active') } else { getElemt('body').classList.remove('active') } }) ``` --- DEMO:[Calendar 五金行日曆](https://codepen.io/ericadu/full/GRZJjjE)