我們常常在交作業、交報告、分享檔案的時候需要上傳的步驟,那你有想過做一個好看的上傳動畫嗎?
今天我們就來實作Day #15,不會實際上傳檔案的好看動畫
CodePen: https://codepen.io/stevetanus/pen/vYjemrj
<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。
.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-cell
,vertical-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 {
position: absolute;
// 使得整個.dropzone點擊都可以選擇檔案
top: 0;
right: 0;
bottom: 0;
left: 0;
opacity: 0;
}
.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-btn
hover的時候,會有兩個陰影的效果。
在line-height
等於height
,行高等於元素高度時,文字上下置中。
.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 {
...
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 {
...
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。
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");
});
這邊主要控制用拖拉的方式匯入檔案,dragover
、dragenter
事件時加入is-dragover
,而在dragend
、dragleave
、drop
的時候移除,回復到原本的白色。
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"。
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 0 toscaleX(1) 、translate3d(0,0,0) |
JavaScript | |
目標 | 屬性 |
------------- | ------------- |
拖拉檔案效果 | dragover 、dragenter 相對於dragend 、dragleave 、drop |
元素加上文字 | button.innerHTML = "Uploading..."; |
setTimeout | 第二個函數為延遲時間 |
setTimeout: https://developer.mozilla.org/en-US/docs/Web/API/setTimeout
好的,又是個星期五,大家辛苦了!!!小弟弟我最近在看求婚大作戰,對的沒錯就是那部經典日劇,我竟然現在才知道(˚Δ˚)b,小小戀歌怎麼可以那麼好聽~