React實作上傳檔案預覽圖片

這是我想要實現的樣子:在一個卡片中點擊上傳檔案,上傳後的照片不能超出我設定的框框,太高就左右留白,太長就上下留白。

這邊有兩個重點:

  1. 上傳檔案的 input 原本樣式很醜,所以我們要直接寫一個蓋掉它 XD。
  2. css 要設定圖片不管怎樣都要自動適應卡片大小。
  3. 上傳後的檔案轉成圖片然後顯示。
  4. 點選刪除要刪掉照片。

我使用的是 react + styled-components,不過 css 寫法都是一樣的,請先準備好一個 react 專案。

 

 

styled-components

 

外框

const UploadCardStyled = styled.label`
  background-color: #fff;
  padding: 10px;
  width: 100%;
  max-width: 400px;
  height: 250px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  border-radius: 12px;
  box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.08);
  position: relative;
  cursor: pointer;
`;


export const UploadCard: React.FC<UploadCardProps> = (props) => {
  return (
    <UploadCardStyled {...props}>
    </UploadCardStyled>
  );
};

 

 

放在中間的按鈕 + 隱藏在後面的input

中間會放一顆上傳的按鈕,不過其實整個被label包起來的區塊都可以點選。

當選擇好檔案上傳之後,會把資料放到叫做fileSrcstate裡,等等要把它放到imgsrc來顯示預覽圖。

//...
const UploadCardButton = styled.span`
  background-color: #fff;
  border: solid 2px #e6e6e6;
  padding: 16px 25px;
  border-radius: 30px;
  font-size: 17px;
  line-height: 1.24;
  margin-bottom: 10px;
`;
const UploadCardInput = styled.input.attrs({
  type: "file",
  accept: "image/png, image/jpeg",
})`
  opacity: 0;
  z-index: -1;
  position: absolute;
`;

export const UploadCard: React.FC<UploadCardProps> = (props) => {
  const [fileSrc, setFileSrc] = useState(null);
  const handleUploadFile = (e) => {
    if (!e.target.files[0]) return;
    var reader = new FileReader();
    reader.onload = function () {
      setFileSrc(reader.result);
    };
    reader?.readAsDataURL(e?.target?.files[0]);
    e.target.value = "";
  };
  return (
    <UploadCardStyled {...props}>
      <UploadCardButton>上傳</UploadCardButton>
      <UploadCardInput onChange={handleUploadFile} />
    </UploadCardStyled>
  );
};

 

 

上傳檔案後的預覽圖片 + 刪除按鈕

為了不讓照片超出卡片,卡片那邊要設定position:relative,然後我們放在裡面的div跟照片都要設定max-widthmax-height100%

//...
const UploadPreview = styled.div`
  max-width: 100%;
  max-height: 100%;
  text-align: center;
`;

const UploadPreviewImg = styled.img`
  max-width: 100%;
  max-height: 100%;
`;

const ClearBtn = styled.button`
  border: 1px solid ${white_1};
  background-color: ${green};
  position: absolute;
  border-radius: 30px;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  padding: 16px 25px;
  cursor: pointer;
`;

export const UploadCard: React.FC<UploadCardProps> = (props) => {
  const [fileSrc, setFileSrc] = useState(null);
  
  const handleUploadFile = (e) => {
    if (!e.target.files[0]) return;
    var reader = new FileReader();
    reader.onload = function () {
      setFileSrc(reader.result);
    };
    reader?.readAsDataURL(e?.target?.files[0]);
    e.target.value = "";
  };
  
  const handleClear = (e) => {
    e.preventDefault();
    setFileSrc(null);
  };
  
  return (
    <UploadCardStyled {...props}>
      {fileSrc ? (
        <>
          <ClearBtn onClick={handleClear}>刪除</ClearBtn>
          <UploadPreview>
            <UploadPreviewImg src={fileSrc} />
          </UploadPreview>
        </>
      ) : (
        <UploadCardButton>上傳</UploadCardButton>
      )}
      <UploadCardInput onChange={handleUploadFile} />
    </UploadCardStyled>
  );
};
  • 第26行:如果你在選擇檔案的時候按「取消」,他就會找不到檔案內容,程式會直接報錯,所以在這邊放一個防呆的。
  • 第32行:上傳重複的圖片,input會直接忽略你的動作,在這邊把他的value清空,就可以暫時騙過瀏覽器,讓他每次都可以上傳,不管是不是重複的圖片。
  • 第39行:刪除的按鈕是放在整個label中,所以會有氣泡事件,等於刪除後又馬上點了上傳檔案,所以加上這行阻止冒泡。

| 軟體開發 | 網站建置 | 網頁系統 | 資料庫網站 |

| 客製化網站 (報名系統、投票系統、掛號系統...) |

| 前後端技術合作 |

歡迎與我們聯繫:jessica@penueling.com

加入Line立即聊聊:@539mjyid

0
0 回復

發表評論

Want to join the discussion?
Feel free to contribute!

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。