Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> JavaScript

HTML file input control với capture và accept attributes không hoạt động đúng


Vấn đề thường gặp

Thuộc tính accept và capture trên <input type="file"> đôi khi không hoạt động như mong đợi do hiểu lầm về vai trò của chúng.

Thuộc tính accept

Chỉ định loại file được chấp nhận (MIME type hoặc extension). Chỉ mang tính **gợi ý UI** (lọc file trong dialog), **không validate** phía server.

<!-- Chỉ chấp nhận ảnh -->
<input type="file" accept="image/*">

<!-- Chỉ chấp nhận video -->
<input type="file" accept="video/*">

<!-- Chỉ chấp nhận audio -->
<input type="file" accept="audio/*">

<!-- Chỉ định extension cụ thể -->
<input type="file" accept=".pdf,.doc,.docx">

<!-- Kết hợp MIME type và extension -->
<input type="file" accept="image/png, image/jpeg, .pdf">

Thuộc tính capture

Không thêm tùy chọn "camera" vào dialog chọn file. Nó chỉ **gợi ý ưu tiên** nguồn thu thập media:

  • capture="user": Ưu tiên camera trước (selfie)
  • capture="environment": Ưu tiên camera sau (chính)
  • capture (boolean): Ưu tiên camera/mic mặc định

Trên mobile, khi có capture + accept="image/*", trình duyệt có thể **mở camera trực tiếp** thay vì hiển thị dialog chọn file.

Code đúng chuẩn

<!DOCTYPE html>
<html lang="vi">
<head>
  <meta charset="UTF-8">
  <title>File Input Capture & Accept</title>
  <style>
    .demo { max-width: 400px; margin: 2rem auto; padding: 1.5rem; border: 1px solid #ddd; border-radius: 8px; }
    .form-group { margin-bottom: 1.5rem; }
    label { display: block; margin-bottom: 0.5rem; font-weight: 500; }
    input[type="file"] { width: 100%; padding: 0.5rem; border: 1px solid #ccc; border-radius: 4px; }
    .note { font-size: 0.875rem; color: #666; margin-top: 0.25rem; }
  </style>
</head>
<body>
  <div class="demo">
    <h2>Demo File Input</h2>
    
    <div class="form-group">
      <label>Chụp ảnh từ camera sau (môi trường):</label>
      <input type="file" accept="image/*" capture="environment">
      <p class="note">Trên mobile: mở camera sau trực tiếp. Desktop: dialog chọn file bình thường.</p>
    </div>
    
    <div class="form-group">
      <label>Chụp ảnh từ camera trước (selfie):</label>
      <input type="file" accept="image/*" capture="user">
      <p class="note">Ưu tiên camera trước.</p>
    </div>
    
    <div class="form-group">
      <label>Chỉ chọn ảnh từ thư viện (không camera):</label>
      <input type="file" accept="image/*">
      <p class="note">Không có capture attribute → hiển thị dialog chọn file/ảnh.</p>
    </div>
    
    <div class="form-group">
      <label>Quay video từ camera sau:</label>
      <input type="file" accept="video/*" capture="environment">
    </div>
    
    <div class="form-group">
      <label>Ghi âm từ micro:</label>
      <input type="file" accept="audio/*" capture>
    </div>
  </div>
</body>
</html>

Hành vi trên các nền tảng

Nền tảngaccept="image/*" capture="environment"accept="image/*" (không capture)
iOS SafariMở camera sau trực tiếpHiện menu: "Chụp ảnh", "Thư viện ảnh", "Chọn file"
Android ChromeMở camera sau trực tiếpHiện menu: "Camera", "Tài liệu", "Hình ảnh"
Desktop Chrome/Firefox/EdgeDialog chọn file bình thường (camera là một tùy chọn)Dialog chọn file bình thường

Lỗi thường gặp & Khắc phục

1. accept không lọc được file

Nguyên nhân: `accept` chỉ gợi ý UI, user vẫn có thể chọn "All Files" trong dialog.

Giải pháp: Validate lại phía client (JS) và **bắt buộc validate phía server**.

input.addEventListener('change', (e) => {
  const file = e.target.files[0];
  const allowedTypes = ['image/jpeg', 'image/png', 'image/webp'];
  if (file && !allowedTypes.includes(file.type)) {
    alert('Chỉ chấp nhận JPG, PNG, WebP');
    e.target.value = ''; // Reset input
  }
});

2. capture không mở camera

Nguyên nhân:

  • Trình duyệt không hỗ trợ (desktop thường không mở camera trực tiếp)
  • Quyền camera bị từ chối
  • Không có camera phù hợp (user/environment)
  • Context không secure (HTTP thay vì HTTPS/localhost)

3. Muốn hiển thị preview sau khi chọn

input.addEventListener('change', (e) => {
  const file = e.target.files[0];
  if (file && file.type.startsWith('image/')) {
    const img = document.createElement('img');
    img.src = URL.createObjectURL(file);
    img.onload = () => URL.revokeObjectURL(img.src);
    document.getElementById('preview').appendChild(img);
  }
});

Tóm tắt: Code "đúng" theo câu hỏi gốc

<!-- Chỉ chọn ảnh, không bắt camera -->
<input type="file" accept="image/*">

<!-- Ưu tiên camera sau cho ảnh -->
<input type="file" accept="image/*" capture="environment">

<!-- Ưu tiên camera trước cho ảnh -->
<input type="file" accept="image/*" capture="user">