文章大綱
這是我想要實現的樣子:在一個卡片中點擊上傳檔案,上傳後的照片不能超出我設定的框框,太高就左右留白,太長就上下留白。
這邊有兩個重點:
- 上傳檔案的 input 原本樣式很醜,所以我們要直接寫一個蓋掉它 XD。
- css 要設定圖片不管怎樣都要自動適應卡片大小。
- 上傳後的檔案轉成圖片然後顯示。
- 點選刪除要刪掉照片。
我使用的是 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包起來的區塊都可以點選。
當選擇好檔案上傳之後,會把資料放到叫做fileSrc的state裡,等等要把它放到img的src來顯示預覽圖。
//...
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-width和max-height是100%。
//...
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中,所以會有氣泡事件,等於刪除後又馬上點了上傳檔案,所以加上這行阻止冒泡。






發表評論
想要加入討論嗎?請盡情發表您的想法!