原生html+js+css+php多图上传带预览可增删判断图片大小和后缀

原生html+js+css+php多图上传带预览可增删,前后端判断图片大小和后缀

html 复制代码
源码来自AI,有改动,整合亲测可用
html 复制代码
<?php
// 设置允许的最大文件大小为 2MB
$maxFileSize = 2 * 1024 * 1024;
$allowedExtensions = ['jpg', 'jpeg', 'png', 'gif'];

// 上传目录(请确保目录存在并具备写入权限)
$uploadDir = __DIR__ . '/uploads/';

$response = [
    'success' => false,
    'url' => '',
    'error' => ''
];

if (isset($_GET['act']) && $_GET['act'] === 'up') {
if (isset($_FILES['file']) && $_FILES['file']['error'] === UPLOAD_ERR_OK) {
  if (!is_dir($uploadDir)) {  @mkdir($uploadDir, 0755, true); }
        $file = $_FILES['file'];

        // 检查文件大小
        if ($file['size'] > $maxFileSize) {
            $response['error'] = '文件大小不能超过 2MB';
            echo json_encode($response);
            exit;
        }

        // 检查文件扩展名
        $fileExtension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
        if (!in_array($fileExtension, $allowedExtensions)) {
            $response['error'] = '仅支持 jpg, jpeg, png, gif 格式';
            echo json_encode($response);
            exit;
        }

        // 为文件生成唯一名称
        $newFileName = uniqid('img_', true) . '.' . $fileExtension;
        $targetFilePath = $uploadDir . $newFileName;

        // 移动上传文件到目标目录
        if (move_uploaded_file($file['tmp_name'], $targetFilePath)) {
            $response['success'] = true;
            $response['url'] = '/uploads/' . $newFileName;  // 根据实际路径配置返回 URL
        } else {
            $response['error'] = '文件上传失败,请重试';
        }
    } else {
        $response['error'] = '上传文件不存在或上传出错';
    }
header('Content-Type: application/json');
echo json_encode($response);
exit();

}
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>多图片上传带进度条</title>
    <style>
        * {
            box-sizing: border-box;
        }

        body {
            font-family: Arial, sans-serif;
            padding: 20px;
        }

        .form-container {
            max-width: 600px;
            margin: auto;
            background-color: #fff;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
        }

        .form-group {
            margin-bottom: 15px;
        }

        .form-group label {
            display: block;
            font-weight: bold;
            margin-bottom: 5px;
        }

        .form-group input[type="text"] {
            width: 100%;
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 4px;
        }

        .upload-container {
            display: flex;
            flex-wrap: wrap;
            gap: 10px;
            margin-top: 10px;
        }

        .image-preview {
            position: relative;
            width: 120px;
            height: 120px;
            border: 2px solid #ddd;
            border-radius: 4px;
            overflow: hidden;
            background-color: #f5f5f5;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .image-preview img {
            width: 100%;
            height: 100%;
            object-fit: cover;
        }

        .delete-btn {
            position: absolute;
            top: 5px;
            right: 5px;
            background-color: rgba(255, 0, 0, 0.7);
            color: #fff;
            border: none;
            border-radius: 50%;
            cursor: pointer;
            width: 20px;
            height: 20px;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .progress-bar {
            width: 100%;
            background-color: #f3f3f3;
            height: 10px;
            border-radius: 5px;
            overflow: hidden;
            margin-top: 5px;
            display: none;
        }

        .progress-fill {
            height: 100%;
            background-color: #0073e6;
            width: 0;
            transition: width 0.2s;
        }

        .hidden-textarea {
            width: 100%;
            height: 80px;
            margin-top: 10px;
            display: none;
        }

        .upload-btn {
            display: flex;
            align-items: center;
            justify-content: center;
            width: 120px;
            height: 120px;
            border: 2px dashed #0073e6;
            border-radius: 4px;
            cursor: pointer;
            color: #0073e6;
            font-size: 1em;
            background-color: #f9f9f9;
        }

        .upload-btn input {
            display: none;
        }

        .btn-submit {
            width: 100%;
            padding: 10px;
            font-size: 1.1em;
            background-color: #0073e6;
            color: #fff;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            margin-top: 20px;
        }
    </style>
</head>
<body>

<div class="form-container">
    <h2>招聘信息图片上传</h2>

    <!-- 标题输入框 -->
    <div class="form-group">
        <label for="title">标题</label>
        <input type="text" id="title" placeholder="请输入图片标题">
    </div>

    <!-- 图片上传容器 -->
    <div class="upload-container" id="upload-container">
        <div class="upload-btn" onclick="document.getElementById('image-upload-input').click();">
            + 上传图片
            <input type="file" id="image-upload-input" accept="image/*" onchange="prepareImageForUpload(event)">
        </div>
    </div>

    <!-- 已上传图片路径和显示上传图片的URL -->
    <textarea id="uploaded-images-path" class="hidden-textarea" readonly></textarea>
    <textarea id="uploaded-images-url" class="hidden-textarea" placeholder="已传图" readonly></textarea>

    <!-- 提交按钮 -->
    <button class="btn-submit" onclick="uploadAllImages()">提交上传</button>
</div>

<script>
    const MAX_IMAGES = 5; // 最大上传图片数量
    const MAX_FILE_SIZE = 2 * 1024 * 1024; // 文件大小限制为2MB
    const allowedExtensions = ['jpg', 'jpeg', 'png', 'gif']; // 允许的文件格式
    const imagesToUpload = []; // 存储图片文件对象

    // 选择图片准备上传
    function prepareImageForUpload(event) {
        const file = event.target.files[0];
        if (!file) return;

        // 检查文件大小
        if (file.size > MAX_FILE_SIZE) {
            alert("文件大小不能超过2MB");
            return;
        }

        // 检查文件格式
        const fileExtension = file.name.split('.').pop().toLowerCase();
        if (!allowedExtensions.includes(fileExtension)) {
            alert("仅支持jpg, jpeg, png, gif格式");
            return;
        }

        imagesToUpload.push(file);
        displayImagePreview(file);

        // 更新上传按钮显示
        if (imagesToUpload.length >= MAX_IMAGES) {
            document.querySelector('.upload-btn').style.display = 'none';
        }
    }

    // 显示图片预览
    function displayImagePreview(file) {
        const reader = new FileReader();
        reader.onload = function(e) {
            const uploadContainer = document.getElementById('upload-container');
            const imagePreview = document.createElement('div');
            imagePreview.className = 'image-preview';

            const img = document.createElement('img');
            img.src = e.target.result;
            imagePreview.appendChild(img);

            const deleteBtn = document.createElement('button');
            deleteBtn.className = 'delete-btn';
            deleteBtn.innerText = '×';
            deleteBtn.onclick = () => removeImage(imagePreview, file);
            imagePreview.appendChild(deleteBtn);

            const progressBar = document.createElement('div');
            progressBar.className = 'progress-bar';
            const progressFill = document.createElement('div');
            progressFill.className = 'progress-fill';
            progressBar.appendChild(progressFill);
            imagePreview.appendChild(progressBar);

            uploadContainer.insertBefore(imagePreview, uploadContainer.lastElementChild);
        };
        reader.readAsDataURL(file);
    }

    // 删除图片
    function removeImage(imageElement, file) {
        imageElement.remove();
        const index = imagesToUpload.indexOf(file);
        if (index > -1) imagesToUpload.splice(index, 1);

        // 显示上传按钮
        if (imagesToUpload.length < MAX_IMAGES) {
            document.querySelector('.upload-btn').style.display = 'flex';
        }
    }

    // 提交上传所有图片
    function uploadAllImages() {
        if (!imagesToUpload.length) {
            alert("请上传至少一张图片");
            return;
        }

        const uploadedUrls = []; // 用于存储成功上传的图片 URL
        const uploadedImagesPath = document.getElementById('uploaded-images-url');
        uploadedImagesPath.style.display = 'block';

        imagesToUpload.forEach((file, index) => {
            // 模拟上传过程
            const progressFill = document.querySelectorAll('.progress-fill')[index];
            progressFill.style.width = '0%';

            const formData = new FormData();
            formData.append("file", file);

            const xhr = new XMLHttpRequest();
            xhr.open("POST", "?act=up&t=", true);

            xhr.upload.onprogress = function(e) {
                if (e.lengthComputable) {
                    const percentComplete = (e.loaded / e.total) * 100;
                    progressFill.style.width = percentComplete + '%';
                }
            };

            xhr.onload = function() {
                if (xhr.status === 200) {
                    const response = JSON.parse(xhr.responseText);
                    if (response.success) {
                        uploadedUrls.push(response.url);
                        uploadedImagesPath.value = uploadedUrls.join('\n');
                    } else {
                        alert("上传失败:" + response.error);
                    }
                }
            };
            xhr.send(formData);
        });
    }
</script>

</body>
</html>
相关推荐
天天打码21 分钟前
html checkbox和label 文字不对齐解决办法
css·html
小远yyds1 小时前
跨平台使用高德地图服务
前端·javascript·vue.js·小程序·uni-app
weixin_516875652 小时前
使用 axios 拦截器实现请求和响应的统一处理(附常见面试题)
前端·javascript·vue.js
皮卡穆2 小时前
JavaScript 变量作用域与函数调用机制:var 示例详解
javascript
羊小猪~~2 小时前
前端入门一之CSS知识详解
前端·javascript·css·vscode·前端框架·html·javas
哪 吒2 小时前
华为OD机试 - 无重复字符的元素长度乘积的最大值(Python/JS/C/C++ 2024 C卷 100分)
javascript·python·华为od
ReBeX2 小时前
【GeoJSON在线编辑平台】(1)创建地图+要素绘制+折点编辑+拖拽移动
前端·javascript·gis·openlayers·webgis
今天也想MK代码2 小时前
在Swift开发中简化应用程序发布与权限管理的解决方案——SparkleEasy
前端·javascript·chrome·macos·electron·swiftui
V+zmm101343 小时前
社区养老服务小程序ssm+论文源码调试讲解
java·服务器·前端·javascript·小程序·毕业设计·1024程序员节
加油小吃货3 小时前
定义全局键盘监听事件,el-dialog中删除不可用
javascript·vue.js·elementui