iT邦幫忙

2022 iThome 鐵人賽

DAY 16
0
自我挑戰組

Do you wanna play? CSS game ぎりぎり系列 第 16

[Day 16] Upload: 以假亂真的上傳

  • 分享至 

  • xImage
  •  

我們常常在交作業、交報告、分享檔案的時候需要上傳的步驟,那你有想過做一個好看的上傳動畫嗎?
今天我們就來實作Day #15,不會實際上傳檔案的好看動畫

Upload


CodePen: https://codepen.io/stevetanus/pen/vYjemrj


1. HTML

<div class="frame">
  <div class="center">
    <div class="bar"></div>
    <div class="title">Drop file to upload</div>
    <div class="dropzone">
      <div class="content">
        <img src="https://100dayscss.com/codepen/upload.svg" class="upload">
        <span class="filename"></span>
        <input type="file" class="input">
      </div>
    </div>
    <img src="https://100dayscss.com/codepen/syncing.svg" class="syncing">
    <img src="https://100dayscss.com/codepen/checkmark.svg" class="done">
    <div class="upload-btn">Upload file</div>
  </div>
</div>

.bar.title下方的進度條,.dropzone為上傳區,包含.content,裡面有上傳的圖樣img、上傳後的檔案名.filename.input可以點取方框上傳,最下面則有上傳中.syncing、上傳完成.done的圖樣和上傳檔案的按鈕.upload-btn
input type='file'使產生上傳檔案的input tag。


2. SCSS(CSS)

.dropzone(上傳區)

.dropzone {
  ...
  position: absolute;
  display: table;
  table-layout: fixed;
  // dashed 為虛線border
  border: 1px dashed #A4A4A4;
  text-align: center;
  overflow: hidden;
  
  &.active{
    opacity: 0;
    display: none;
  }
  &.is-dragover{
    border-color: #666;
    background: #eee;
  }
  
  .content {
    display: table-cell;
    vertical-align: middle;
  }
}

.dropzone為table排版,table-layout: fixed可以加快table的顯示速度,text-align: center讓圖片左右置中,.content中為table-cellvertical-align達到垂直置中。
加上is-dragover的class後,顏色會變暗,而加上.active則會消失移除。

table-layout: https://blog.miniasp.com/post/2009/04/20/Use-CSS-table-layout-property-to-speed-up-table-rendering
vertical-align常用在table和行內元素(inline-elements): https://developer.mozilla.org/en-US/docs/Web/CSS/vertical-align

.input

.input {
    position: absolute;
    // 使得整個.dropzone點擊都可以選擇檔案
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    opacity: 0;
  }

.upload-btn(上傳按鈕)

.upload-btn{
  ...
  background: #6ECE3B;
  height: 40px;
  text-align: center;
  line-height: 40px; //line-height == height
  box-shadow: 0 2px 0 0 #498C25;
  cursor: pointer;
  transition: all .2s ease-in-out;
  
  &:hover {
    box-shadow: 0 2px 0 0 #498C25, 0 2px 10px 0 #6ECE3B;
  }
}

.upload-btnhover的時候,會有兩個陰影的效果。
line-height等於height,行高等於元素高度時,文字上下置中。

.bar(進度條動畫)

.bar 
  width: 300px;
  background: #6ece3b;
  transition: all 3s ease-out;
  transform: scaleX(0);
  transform-origin: 0 0;
  
  &.active{
    transform: scaleX(1) translate3d(0,0,0);
  }
}

.bar加上.active會有3s從左到右延伸的動畫。

.syncing(上傳動畫)

.syncing {
  ...
  opacity: 0;
  
  &.active {
    animation: syncing 3.2s ease-in-out;
  }
}

@keyframes syncing {
	0% {
		transform: rotate(0deg);
	}
	10% {
		opacity: 1;
	}
	90% {
		opacity: 1;
	}
	100% {
		transform: rotate(360deg);
		opacity: 0;
	}
}

上傳動畫在3.2秒完成,從透明到顯現並轉360度,再度消失。

.done(上傳完成)

.done {
  ...
  opacity: 0;
  
  &.active {
    animation: done .5s ease-in 3.2s;
    animation-fill-mode: both;
  }
}

@keyframes done {
	from {
		opacity: 0;
	}
	to {
		opacity: 1;
	}
}

.done的動畫在3.2秒後開始,0.5秒結束,animation-fill-mode: both使.done最後的opacity停留在1。


3. JavaScript

let dropzone = document.querySelector('.dropzone');
dropzone.addEventListener("dragover", ()=>{
  dropzone.classList.add("is-dragover");
});

dropzone.addEventListener("dragenter", ()=>{
  dropzone.classList.add("is-dragover");
})

dropzone.addEventListener("dragend", ()=>{
  dropzone.classList.remove("is-dragover");
})

dropzone.addEventListener("dragleave", () => {
  dropzone.classList.remove("is-dragover");
});
dropzone.addEventListener("drop", () => {
  dropzone.classList.remove("is-dragover");
});

這邊主要控制用拖拉的方式匯入檔案,dragoverdragenter事件時加入is-dragover,而在dragenddragleavedrop的時候移除,回復到原本的白色。

fileInput.addEventListener("change", () => {
  fileName = document.querySelector(".filename");
  for (let i = 0; i < fileInput.files.length; i++) {
    fileName.innerHTML = `${fileInput.files[i].name}`;
  }
  upload.style.display = "none";
});

在上傳檔案時,使得fileInput改變,在.filename的span元素加入HTML: 上傳的檔案名字,顯示檔案名在上傳區,並且讓上傳檔案的照片(upload)移除。

button.addEventListener("click", () => {
  startUpload();
});

function startUpload() {
  // 一定要有檔案名字才會執行
  if (!uploading && fileName != "") {
    // 上傳中,使動畫只觸發一次
    uploading = true;
    button.innerHTML = "Uploading...";
    dropzone.classList.add("active");
    syncing.classList.add("active");
    done.classList.add("active");
    bar.classList.add("active");
    timeOut = window.setTimeout(showDone, 3200);
  }
}

function showDone() {
  button.innerHTML = "Done";
}

點擊上傳按鈕觸發startUpload,改變上傳文字為"Uploading",加上元素們的.active開始動畫,setTimeout會在3200毫秒後再觸發showDone的動畫,讓上傳文字變為"Done"。


打包帶走(take away)

HTML

目標 屬性
上傳檔案 <input type="file">
CSS
目標 屬性
------------- -------------
虛線border border: 1px dashed
加快table的顯示速度 width固定、table-layout: fixed
table-cell置中 vertical-align達到垂直置中。
兩層陰影 box-shadow: 0 2px 0 0 #498C25, 0 2px 10px 0 #6ECE3B;
進度條動畫 width、fromscaleX(0)transform-origin: 0 0toscaleX(1)translate3d(0,0,0)
JavaScript
目標 屬性
------------- -------------
拖拉檔案效果 dragoverdragenter相對於dragenddragleavedrop
元素加上文字 button.innerHTML = "Uploading...";
setTimeout 第二個函數為延遲時間

setTimeout: https://developer.mozilla.org/en-US/docs/Web/API/setTimeout


後記

好的,又是個星期五,大家辛苦了!!!小弟弟我最近在看求婚大作戰,對的沒錯就是那部經典日劇,我竟然現在才知道(˚Δ˚)b,小小戀歌怎麼可以那麼好聽~/images/emoticon/emoticon51.gif


上一篇
[Day 15] Bicyclopter: 腳踏車還是直升機? 我要腳踏直升機!
下一篇
[Day 17] 番外篇: scale, rotate, translate(縮放、旋轉、移動)
系列文
Do you wanna play? CSS game ぎりぎり30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言