【asp】web做文件上传,需要在表单用上 <form Enctype="multipart/form-data"/>

本文深入解析了Web开发中文件上传时enctype属性的重要性,详细阐述了不同编码类型(如application/x-www-form-urlencoded、multipart/form-data、text/plain)在文件上传过程中的作用及适用场景。重点强调了multipart/form-data编码类型在完整传递文件数据方面的独特优势。

web做文件上传,需要 <form Enctype="multipart/form-data"/>


enctype这个属性管理的是表单的MIME编码。共有三个值可选:

1、application/x-www-form-urlencoded
2、multipart/form-data
3、text/plain


application/x-www-form-urlencoded是默认值,默认的HTML表单是这种传输编码类型的;

multipart/form-data是用来制定传输数据的特殊类型的,主要就是我们上传的非文本的内容;
text/plain是纯文本传输的意思,在发邮件的时候要设置这种编码类型,否则会出现接收时编码混乱的问题。网络上经常拿text/plain和 text/html做比较,其实这两个很好区分,前者用来传输纯文本文件,后者则是传递html代码的编码类型,在发送头文件时才用得上。①和③都不能用于上传文件,只有multipart/form-data才能完整的传递文件数据
<div class="mainbody "> <span>暂无任务</span> <!--任务列表--> <div class="task-list"> <!-- 任务卡会通过JS动态生成,这里预留容器 --> <div id="taskCardsContainer"> <!-- 加载提示(初始状态) --> <div class="loading-hint">加载任务中...</div> </div> </div> </div> <!--任务编辑弹窗--> <div class="modal" id="task-modal"> <div class="modal-content"> <span class="close-btn">×</span> <!--关闭按钮--> <h2 id="modal-title">新建任务</h2> <form id="task-form" method="post" action="@Url.Action("AddTask", "CalendarHome")" enctype="multipart/form-data"> <input type="hidden" id="task-id" name="id"> <!--标题行--> <div class="form-group"> <label for="title">*任务标题</label> <input type="text" id="title" name="title" required maxlength="100" placeholder="请输入任务标题(最多100字)" value="打扫卫生"> <div class="char-count">0/100</div> </div> <!--内容行--> <div class="form-group"> <label for="content">任务内容</label> <textarea id="content" name="content" rows="4" placeholder="请输入任务详细内容" style="max-width: 600px; max-height: 200px; ">扫地、拖地、擦玻璃、倒垃圾、清理家具、洗衣服</textarea> </div> <!--<input type="datetime-local" id="createtime" name="createtime" style="display: none">--> <!--截止日期行--> <div class="form-group"> <label for="deadline">截止日期</label> <input type="datetime-local" id="deadline" name="deadline"> </div> <!--优先级行--> <div class="form-group"> <label for="priority">重要性★</label> <select id="priority" name="priority"> <option value="1">★☆☆ (低)</option> <option value="2" selected>★★☆ (中)</option> <option value="3">★★★ (高)</option> </select> </div> <!--进展阶段行--> <div class="form-group"> <label for="status">进展阶段</label> <select id="status" name="status"> <option value="0">待处理</option> <option value="1" selected>进行中</option> <option value="2">已完成</option> </select> </div> <!--附件行--> <!--附件id--> <input type="hidden" name="file-id" id="file-id" /> <div class="attachment-uploader"> <button type="button" id="addFileBtn" class="add-file-btn"> <svg t="1755074000661" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4949" width="20" height="20"><path d="M466.916527 223.994525l0.010434 0.010435-279.987944 279.987944c-80.870257 80.870257-80.870257 211.986698 0 292.856955s211.986698 80.870257 292.856955 0l363.810422-363.810422c53.977502-53.977502 53.977502-141.492342 0-195.469844s-141.492342-53.977502-195.469844 0l-351.637033 351.637033c-27.276739 27.276739-27.276739 71.501617 0 98.778355s71.501617 27.276739 98.778356 0l267.814555-267.814555 0.01113 0.01113c12.338947-11.60437 31.752372-11.376206 43.81307 0.684492 12.061394 12.061394 12.289558 31.474819 0.685188 43.813766l0.010434 0.010434-267.814555 267.814555c-51.864202 51.864202-135.953103 51.864897-187.818 0-51.864202-51.864202-51.864202-135.953798 0-187.817999l351.637033-351.637033c78.564965-78.564965 205.944524-78.564965 284.509488 0s78.564965 205.944524 0 284.509488l-363.810421 363.810422c-105.45772 105.45772-276.43888 105.45772-381.8966 0s-105.45772-276.43888 0-381.896599l279.987944-279.987944 0.01113 0.011129c12.338947-11.60437 31.752372-11.376206 43.81307 0.684493 12.061394 12.061394 12.289558 31.474819 0.685188 43.813765z" fill="#D8D8D8" p-id="4950"></path></svg> 添加附件 </button> <!-- 隐藏的文件输入框(multiple支持多选) --> <input type="file" id="fileInput" name="files" multiple style="display: none;"> <!-- 已选附件列表(动态生成) --> <div id="fileList" class="file-list"> <!-- 附件项会动态添加到这里 --> <div class="empty-hint">暂无附件,点击"添加附件"按钮选择文件</div> </div> </div> <!-- 任务预览 --> <div class="preview-section"> <h3>任务预览</h3> <div class="task-preview-card"> <h4 id="preview-title" class="preview-placeholder">任务标题将显示在这里</h4> <span id="preview-img"></span> <p id="preview-content" class="preview-placeholder">任务内容将显示在这里</p> <div class="preview-meta"> <!--<span id="preview-createtime">创建日期: 未设置</span>--> <span id="preview-deadline">截止日期: 未设置</span> <span id="preview-priority">重要性: </span> <span id="preview-status">状态: </span> </div> </div> </div> <div class="form-actions"> <button type="submit" class="save-btn">保存</button> <button type="button" class="cancel-btn">取消</button> </div> </form> </div> </div> <div id="loading-modal" class="modal"> <div class="loader"> <div class="bar1"></div> <div class="bar2"></div> <div class="bar3"></div> <div class="bar4"></div> <div class="bar5"></div> <div class="bar6"></div> <div class="bar7"></div> <div class="bar8"></div> <div class="bar9"></div> <div class="bar10"></div> <div class="bar11"></div> <div class="bar12"></div> </div> </div> <script src="~/Scripts/Script-Home-Index.js"></script> <script src="~/Scripts/Script-TaskAdd-AddTask.js"></script> document.addEventListener('DOMContentLoaded', function () { // -------------------------- 独立函数声明(上部) -------------------------- // 关闭弹窗并重置 function closeModal() { modal.style.display = 'none'; resetForm(); // 关闭时也重置表单 } // 更新预览 function updatePreview() { const title = titleInput.value; const content = document.getElementById('content').value; const deadline = document.getElementById('deadline').value; const priority = document.getElementById('priority').value; const status = document.getElementById('status').value; // 更新标题预览 previewTitle.textContent = title || '任务标题将显示在这里'; previewTitle.classList.toggle('preview-placeholder', !title); // 更新内容预览 previewContent.textContent = content || '任务内容将显示在这里'; previewContent.classList.toggle('preview-placeholder', !content); // 更新截止日期预览 if (deadline) { const date = new Date(deadline); previewDeadline.textContent = `截止日期: ${date.toLocaleString()}`; } else { previewDeadline.textContent = '截止日期: 未设置'; } // 更新优先级预览 const priorityText = priority === '1' ? '低' : (priority === '2' ? '中' : '高'); previewPriority.textContent = `优先级: ${priorityText}`; // 更新状态预览 const statusText = status === '0' ? '待处理' : (status === '1' ? '进行中' : '已完成'); previewStatus.textContent = `状态: ${statusText}`; // 更新预览卡片的优先级颜色 const previewCard = document.querySelector('.task-preview-card'); previewCard.className = 'task-preview-card'; previewCard.classList.add(`priority-${priority}`); } // 创建文件预览项 function createFileItem(file, index, fileId) { const fileItem = document.createElement('div'); fileItem.className = 'file-item'; fileItem.dataset.index = index; fileItem.dataset.fileId = fileId; // 图片预览(仅图片文件) let previewContent = ''; const isImage = file.type.startsWith('image/'); if (isImage) { const reader = new FileReader(); reader.onload = (e) => { // 更新文件项中的图片 const itemImg = fileItem.querySelector('img'); if (itemImg) { itemImg.src = e.target.result; itemImg.style.maxWidth = '200px'; } // 在preview-img容器中添加预览图 const previewImgElement = document.createElement('img'); previewImgElement.src = e.target.result; previewImgElement.alt = `预览图: ${file.name}`; previewImgElement.style.maxWidth = '200px'; previewImgElement.style.margin = '5px'; previewImgElement.dataset.fileId = fileId; // 关联文件ID previewImg.appendChild(previewImgElement); }; reader.readAsDataURL(file); previewContent = `<img src="" alt="预览图" data-file-id="${fileId}">`; } else { // 非图片文件显示图标 previewContent = ` <svg width="40" height="40" viewBox="0 0 24 24" fill="#ccc"> <path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8z"/> <polyline points="14 2 14 8 20 8"/> <line x1="16" y1="13" x2="8" y2="13"/> <line x1="16" y1="17" x2="8" y2="17"/> <polyline points="10 9 9 9 8 9"/> </svg> `; } // 格式化文件大小 const fileSize = formatFileSize(file.size); // 组装文件项HTML fileItem.innerHTML = ` ${previewContent} <div class="file-info"> <div class="file-name">${file.name}</div> <div class="file-size">${fileSize} · ${file.type || '未知类型'}</div> </div> <button class="remove-btn" data-index="${index}"> <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/> </svg> </button> `; // 添加删除事件 fileItem.querySelector('.remove-btn').addEventListener('click', (e) => { const index = parseInt(e.target.closest('.remove-btn').dataset.index); const fileId = fileItem.dataset.fileId; // 从数组中移除 selectedFiles.splice(index, 1); // 从DOM中移除文件项 fileItem.remove(); // 删除对应的预览图(如果是图片) const previewImgToRemove = previewImg.querySelector(`[data-file-id="${fileId}"]`); if (previewImgToRemove) { previewImgToRemove.remove(); } // 更新剩余项的索引 updateFileIndices(); // 如果没有文件了,显示空提示 if (selectedFiles.length === 0 && emptyHint) { emptyHint.style.display = 'block'; } }); // 添加到列表 fileList.appendChild(fileItem); } // 更新文件项的索引(删除后重新编号) function updateFileIndices() { document.querySelectorAll('.file-item').forEach((item, index) => { item.dataset.index = index; item.querySelector('.remove-btn').dataset.index = index; }); } // 格式化文件大小 function formatFileSize(bytes) { if (bytes === 0) return '0 Bytes'; const k = 1024; const sizes = ['Bytes', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; } // 获取所有文件用于上传 function getFilesForUpload() { return selectedFiles.map(item => item.file); } // 重置表单及附件状态 function resetForm() { // 重置表单字段 taskForm.reset(); document.getElementById('task-id').value = ''; document.getElementById('file-id').value = ''; document.getElementById('modal-title').textContent = '新建任务'; charCount.textContent = '0/100'; charCount.style.color = '#666'; // 重置预览 updatePreview(); // 清空附件列表 selectedFiles.length = 0; fileList.innerHTML = ''; if (emptyHint) { emptyHint.style.display = 'block'; } // 清空预览图片 previewImg.innerHTML = ''; // 重置文件ID计数器 fileIdCounter = 0; } // -------------------------- 变量定义与事件绑定(下部) -------------------------- // 获取DOM元素 const modal = document.getElementById('task-modal'); const addTaskBtn = document.querySelector('.add-input'); const closeBtn = document.querySelector('.close-btn'); const cancelBtn = document.querySelector('.cancel-btn'); const taskForm = document.getElementById('task-form'); const taskList = document.getElementById('task-list'); const titleInput = document.getElementById('title'); const charCount = document.querySelector('.char-count'); const previewImg = document.getElementById('preview-img'); // 预览图片容器 // 预览相关元素 const previewTitle = document.getElementById('preview-title'); const previewContent = document.getElementById('preview-content'); const previewDeadline = document.getElementById('preview-deadline'); const previewPriority = document.getElementById('preview-priority'); const previewStatus = document.getElementById('preview-status'); // 设置截止日期默认值 const nowtime = new Date(); const year = nowtime.getFullYear(); const month = String(nowtime.getMonth() + 1).padStart(2, '0'); const day = String(nowtime.getDate()).padStart(2, '0'); const hours = String(nowtime.getHours()).padStart(2, '0'); const minutes = String(nowtime.getMinutes()).padStart(2, '0'); const formattedDateTime = `${year}-${month}-${day}T${hours}:${minutes}`; // 附件相关元素 const addFileBtn = document.getElementById('addFileBtn'); const fileInput = document.getElementById('fileInput'); const fileList = document.getElementById('fileList'); const emptyHint = document.querySelector('.empty-hint'); // 存储已选择的文件及对应的预览图ID(用于删除关联) const selectedFiles = []; let fileIdCounter = 0; // 用于生成唯一ID标识文件 // 打开弹窗 addTaskBtn.addEventListener('click', function () { resetForm(); modal.style.display = 'block'; document.getElementById('deadline').value = formattedDateTime; }); // 关闭弹窗相关事件 closeBtn.addEventListener('click', closeModal); cancelBtn.addEventListener('click', closeModal); // 字符计数 titleInput.addEventListener('input', function () { const length = this.value.length; charCount.textContent = `${length}/100`; charCount.style.color = length > 100 ? '#f44336' : '#666'; updatePreview(); }); // 表单输入更新预览 document.getElementById('title').addEventListener('input', updatePreview); document.getElementById('content').addEventListener('input', updatePreview); document.getElementById('deadline').addEventListener('change', updatePreview); document.getElementById('priority').addEventListener('change', updatePreview); document.getElementById('status').addEventListener('change', updatePreview); // 附件按钮事件 addFileBtn.addEventListener('click', () => { fileInput.click(); }); // 文件选择变化事件 fileInput.addEventListener('change', (e) => { const newFiles = Array.from(e.target.files); if (newFiles.length === 0) return; // 隐藏空提示 if (emptyHint) emptyHint.style.display = 'none'; // 处理新选择的文件(允许重复添加) newFiles.forEach(file => { // 生成唯一ID用于关联文件和预览图 const fileId = `file-${fileIdCounter++}`; // 添加到文件列表 selectedFiles.push({ file: file, id: fileId, isImage: file.type.startsWith('image/') }); // 创建文件预览项 createFileItem(file, selectedFiles.length - 1, fileId); }); // 重置input值,允许重复选择同一文件 fileInput.value = ''; }); }); [HttpPost] public ActionResult AddTask(string title, string content, string deadline, string priority, string status, HttpPostedFileBase file) { // 处理标题 if (string.IsNullOrEmpty(title)) { ModelState.AddModelError("title", "任务标题不能为空"); return View("TaskAdd"); } // 处理截止日期 DateTime? parsedDeadline = null; if (!string.IsNullOrEmpty(deadline)) { if (!DateTime.TryParse(deadline, out DateTime dt)) { ModelState.AddModelError("deadline", "截止日期格式不正确"); return View("TaskAdd"); } parsedDeadline = dt; } // 处理优先级 if (!sbyte.TryParse(priority, out sbyte p) || p < 1 || p > 3) { ModelState.AddModelError("priority", "优先级设置不正确"); return View("TaskAdd"); } // 处理状态 if (!sbyte.TryParse(status, out sbyte s) || s < 0 || s > 2) { ModelState.AddModelError("status", "状态设置不正确"); return View("TaskAdd"); } // 创建实体时使用正确的变量名 var newTask = new task { id = Guid.NewGuid().ToString().Replace("-", ""), title = title, // 对应表单的 name="title" content = content ?? "", create_time = DateTime.Now, deadline = parsedDeadline, priority = p, status = s, }; db.tasks.Add(newTask); db.SaveChanges(); // 若字段名匹配,此处应能正常保存 怎么写controller才能让type="file"的文件上传到数据库
08-16
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值