---
# System prepended metadata

title: InputFile 美化 & 順便實現點擊 Button 時產生波紋效果
tags: [實作畫面]

---

# InputFile 美化 & 順便實現點擊 Button 時產生波紋效果 
###### tags: `實作畫面`

## 結果
https://jsfiddle.net/bjry2pta/
![](https://i.imgur.com/2vCwtSG.gif)
( 框線內都可以點擊上傳 )

## 簡介
* 使用 bootstrap 5
* button 波紋效果需有程式搭配控制

## HTML
```
<br /><br /><br /><br />

<div class="container">
  <label for="fileInput" class="label-input-file p-2 border rounded d-flex align-items-center">
    <label class="fake-button px-4" for="fileInput">
      <i class="bi bi-cloud-arrow-up" style="font-size:20px;"></i>&nbsp;選擇檔案
    </label>
    <input id="fileInput" type="file" accept="image/*" hidden>
    <span class="ms-2" id="fileName"></span>
  </label>
</div>
```

## css
```
 .label-input-file {
   cursor: pointer;
 }

 /* 按鈕基本 style & span 準備 */
 .fake-button {
   padding: 10px;
   border: none;
   border-radius: 5px;
   background-color: #1abc9c;
   color: #fff;
   font-size: 18px;
   outline: none;
   cursor: pointer;
   box-shadow: 6px 7px 40px -4px rgba(0, 0, 0, 0.2);

   /* 為了 span ripper 準備的 style */
   position: relative;
   /* 隱藏會溢出 button 的 ripper 效果 */
   overflow: hidden;
 }

 .fake-button span {
   position: absolute;

   /* 圓形波紋效果 */
   border-radius: 50%;
   /* 波紋顏色 */
   background-color: rgba(0, 0, 0, 0.3);

   width: 100px;
   height: 100px;

   /* 校正至點擊位置 */
   margin-top: -50px;
   margin-left: -50px;

   animation: ripple 1s;

   /* 先隱藏，由動畫 show 出 */
   opacity: 0;
 }

 /* ripple 動畫 */
 /* scale 縮放元素 ( Size ) */
 @keyframes ripple {
   from {
     opacity: 1;
     transform: scale(0);
   }

   to {
     opacity: 0;
     transform: scale(10);
   }
 }
```

## js
```
const inputFile = document.querySelector("#fileInput");
inputFile.onchange = function(e) {
  if (e.target.files.length > 0) {
    const fileNameSpan = document.querySelector("#fileName");
    fileNameSpan.innerHTML = e.target.files[0].name
  }
}

const btn = document.querySelector(".fake-button");

// Listen for click event
btn.onclick = function(e) {

  // 建立一個 span
  let rippleSpan = document.createElement("span");

  // span 加上要套用的 class 名稱 => ripple
  rippleSpan.classList.add("ripple");
  // 在 btn 下加入 span
  this.appendChild(rippleSpan);

  // 取得 click 位置 X
  let x = e.clientX - e.target.offsetLeft;
  // 取得 click 位置 Y 
  let y = e.clientY - e.target.offsetTop;

  // 設定 span 的位置
  rippleSpan.style.left = `${x}px`;
  rippleSpan.style.top = `${y}px`;

  // 等 0.3s 後移除 rippleSpan
  setTimeout(() => {
    rippleSpan.remove();
  }, 300);

};
```

## 來看看沒有動畫時，這個 span 長怎樣
1. .fake-button span 拿掉(註解) 
```
margin-top: -50px;
margin-left: -50px;
animation: ripple 1s;
```

2. .fake-button span 修改
```
opacity: 1; /* 原本是 0 */
```

3. .fake-button span 使用的 animation 修改
```
transform: scale(1); /* 原本是 10 */
```

4. 程式產生的 span 加上文字 "TESTT" 輔助觀察

### 實際新增上span的感覺是這樣↓
![](https://i.imgur.com/Dn27oz0.png)
( 紅點為 click 點擊位置 )

### margin top/left 的效果
這樣就可以明白，為什麼需要 margin top/left -50px，為了讓這個陰影在 click 的位置
![](https://i.imgur.com/Z2q66LW.png)
( 紅點為 click 點擊位置 )

## 參考

[How to create a Ripple Effect on Click the Button ?](https://www.geeksforgeeks.org/how-to-create-a-ripple-effect-on-click-the-button/)