Ajax 编程基础——FormData——视频上传(二)

2024-04-12 21:32

本文主要是介绍Ajax 编程基础——FormData——视频上传(二),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

模板引擎

node.js 基础学习时就已经接触过模板引擎的概念,但那是为了在服务器端对数据和 HTML 结构进行拼接并响应给客户端。现在使用的是 ajax 技术,因此是需要在客户端对数据和模板进行拼接并直接更新在页面中。

原理是相同的原理,因此使用的步骤也大致相同。既然在服务器端使用的是 art-template 模板引擎,在客户端我们也选择这款模板引擎。因为它们的模板语法是一摸一样的,这就节省了再重新学习其他模板引擎的语法的时间精力。

1、art-template 官网 下载 art-template 模板引擎库文件并在 HTML 页面中引入库文件。

<script src="/js/template-web.js"></script>

2、准备 art-template 模板,art-template 模板是 html 文件中的一些代码片段,使用 script 标签包裹。使用 id 属性标识不同的模板,为了提高模板代码的可读性,可以为其设置 type 属性。

<script id="tpl" type="text/html"><div class="box"></div>
</script>

3、告诉模板引擎需要拼接哪个模板和数据

<script>var html = template('tpl', {userName: 'tkop', age: 18});
</script>

4、将拼接好的 html 字符串更新至页面中

// 将拼接好的字符串作为dom元素的内容
document.getElementById('container').innerHTML = html;

5、使用模板语法对数据和模板进行拼接操作

<script id="tpl" type="text/html"><div class="box">{{ userName }}</div>
</script>

有关 art-template 模板语法在 node.js 基础部分学习 express 框架时已经有所了解在此不重复笔记,笔记链接:Express 框架基础 。

FormData 对象

在我们需要发送的 ajax 请求需要携带大量的表单信息时, 逐个获取表单控件元素并将它们的值组合成需要的参数格式显然比较繁琐。前面学习过一个有关的表单方法 serializeArray() 可以方便我们获取表单控件中的数据,但是对于需求的实现还是不够理想。此时 ES6 中提供的 FormData 对象可以完美解决我们遇到的问题,但是 IE10 以下的浏览器不支持。

FormData 对象是一类用于模拟 HTML 表单,相当于将 HTML 表单映射成为表单对象(通过 js 使用键值对的形式表示表单控件的 name 和 value)。它自动将表单对象中的数据拼接成请求参数的格式。还具有异步上传二进制文件的功能。

FormData 对象的使用

1、准备 HTML 表单

<form id="form"><input type="text" name="username" /><input type="password" name="password" /><input type="button" />
</form>

不需要为表单设置请求方式和请求地址,也不需要提交按钮(当然可以设置一个 button 表单控件并为其绑定点击事件,点击后发送 ajax 请求提交表单),因为此时需要发送的是 ajax 请求。

2、将 HTML 表单转换为 formData 对象

利用表单元素和 FormData 构造函数创建表单对象。当然也可以创建一个空的表单对象,再根据需要使用表单对象的 set() 和 append() 方法为其添加数据。

var form = focument.getElementById('form');
var formData1 = new FormData(form);// 也可以创建空的表单对象、
var formData2 = new FormData();

3、提交表单对象

提交表单时 ajax 请求不需要设置请求头(FormData 自带请求头),所以不要存在为什么发送 ajax 请求前不去设置请求头信息的疑惑。例如以前我们发送请求前需要指明参数格式 xhr.setRequestHeader = '参数格式' ,现在不需要设置,直接发送即可。

xhr.send(formData1);

注意:

  • FormData 对象不能直接用于 get 请求,因为 get 请求方式的请求参数只能放在请求地址的后面,对象需要被传递到 send 方法中。
  • 服务器端 bodyParser 模块无法解析 formData 对象表单数据,我们需要使用 formidable 模块进行解析。
  • 在表单中并没有设置属性 enctype=“multipart/form-data” 来明确规定使用二进制形式表示表单数据,但是在后面可以直接进行二进制文件的上传功能和使用 formidable 模块解析。这说明 formData 对象在表示表单数据时使用的就是二进制形式。
  • 只有 bodyParser 模块在解析数据时需要配置以什么格式解析参数,使用 formData 模块不需要。这一点在以前的学习中没有去明确,现在补上。

在此明确一些题外知识:

  1. 表单传统方式提交时请求头信息中表示参数格式的字段内容为 Content-Type: application/x-www-form-urlencoded
  2. Formdate 对象自带的请求头信息中表示参数格式的字段内容为Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryxCZ0XYGrKJwqGsJw 。其数据在请求体中具体的形式与以前接触过的哪两种类型差异很大,如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EsA9CcN2-1618660512078)(https://z3.ax1x.com/2021/04/17/c5iGND.png)]

FormData 对象具有的方法

// 1、获取表单对象中属性的值formData.get('key');
formData1.get('name');
// 2、设置表单对象中的值formData.set('key', 'value');
formData1.set('name', '扬尘');
// 3、删除表单对象中属性的值formData.delete('key');
formData1.delete('age');
// 4、向表单对象中追加属性值formData.append('key', 'value');
formData1.append('hobbies', '敲代码');

注意:set 方法和 append 方法的区别是。在属性名已经存在的情况下,set 会覆盖已有的键名的值,append 会保留两个值(但是服务器使用的是最后的那个参数值)。

二进制文件上传

在利用 FormData 对象实现二进制文件上传功能前首先了解以下几个知识。

  1. 文件选择控件如果设置 multiple 属性是可以一次选择多个文件的,这些文件会保存在控件元素对象的 files 属性中。files 属性是保存文件的一个数组(无论用户选择几个文件)。

  2. ajax 请求对象 xhr 有一个 upload(上传)对象,上传相关的事件都会存储在这个对象中。

  3. 文件上传过程中会持续触发 upload 对象下的 progress(进度)事件,并且该事件的事件对象中存储了上传文件的总大小和已上传数据大小。事件对象的 total、loaded 属性分别保存了文件总大小和已上传数据的大小。

图片预览功能是在我们将图片上传至服务器后,服务器通常都会将图片地址作为响应数据传递到客户端。客户端可以从响应数据中获取图片地址,然后将图片显示在页面中(与前面还未上传前的预览不同)。未上传前的预览当时使用的是 js 内置的 FileReader 对象(存在兼容性问题)在客户端直接读取和显示图片。

<body><form action=""><input type="file" name="file" id="file" multiple><input type="button" value="上传" id="btn"><div id="prev"><!-- <video src="" muted="muted" autoplay="autoplay" loop="loop"></video> --></div><div class="progress" id="progress" style='display:none;'><div class="progress-bar" style="width: 0%;" id="progress-bar">0%</div></div></form>
</body><script>// 各dom元素的获取var file = document.getElementById('file');var btn = document.getElementById('btn');var progressBar = document.getElementById('progress-bar');var progress = document.getElementById('progress');var prev = document.getElementById('prev');// 上传按钮点击事件btn.onclick = function() {// 需要先将上次的上传预览清除掉prev.innerHTML = '';var xhr = new XMLHttpRequest();xhr.open('post', 'http://localhost:3000/formdata');// 创建表单对象并将各二进制文件追加至表单对象中var formdata = new FormData();for (let i = 0; i < file.files.length; i++) {// 这里的文件名称是自定义的formdata.append('video' + i, file.files[i]);}// 进度条功能实现xhr.upload.onprogress = function(e) {progress.style.display = 'block';var result = Math.round((e.loaded / e.total) * 100) + '%';progressBar.style.width = result;progressBar.innerHTML = result;}// 上传成功在获取到响应数据后预览文件(视频)xhr.onload = function() {if (xhr.status == 200) {var result = JSON.parse(xhr.responseText);// 已经上传完成可以将进度条隐藏progress.style.display = 'none';// 服务器端响应的数据 result={vide0path:'文件0路径', vide1path:'文件1路径', ...}for (var k in result) {var video = document.createElement('video');video.src = result[k];video.muted = "muted";video.autoplay = "autoplay";video.loop = "loop";prev.appendChild(video);}}}xhr.send(formdata);}
</script>

在这里插入图片描述如上图是上传多个文件(一个也一样)后在服务器端的 files 对象的内容,图中的内容可以帮我们捋清获取各个文件保存路径并响应给客户端的思路。

// 服务器端的代码
const express = require('express');
const formidable = require('formidable');
const path = require('path');
const app = express();
app.use(express.static(path.join(__dirname, 'public')));
// 实现文件上传的路由
app.post('/formdata', (req, res) => {const form = new formidable.IncomingForm();// 配置文件保存路径form.uploadDir = path.join(__dirname, 'public', 'upload');// 保留文件后缀名form.keepExtensions = true;form.parse(req, (err, fiels, files) => {var result = {};for (let k in files) {// 处理前端上传的文件的保存路径result[k + 'path'] = files[k].path.split('public')[1];}// 将路径信息响应给浏览器用于实现预览功能res.send(result);})
})

最后实现的结果如下:

在这里插入图片描述
可能你在自己实现进度条功能时由于文件太小或者网速太快导致进度条一下子就满了。为了更加确定进度条功能没有问题,可以将浏览器的网络状态设置为 slow 3G ,你会发现此时上传速度相当慢。

在这里插入图片描述

设置网络后上传文件(注意此时不能关闭开发者工具,不然浏览器的网络还是 No throttling )

在这里插入图片描述

这篇关于Ajax 编程基础——FormData——视频上传(二)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/898292

相关文章

Spring Boot集成SLF4j从基础到高级实践(最新推荐)

《SpringBoot集成SLF4j从基础到高级实践(最新推荐)》SLF4j(SimpleLoggingFacadeforJava)是一个日志门面(Facade),不是具体的日志实现,这篇文章主要介... 目录一、日志框架概述与SLF4j简介1.1 为什么需要日志框架1.2 主流日志框架对比1.3 SLF4

Spring Boot集成Logback终极指南之从基础到高级配置实战指南

《SpringBoot集成Logback终极指南之从基础到高级配置实战指南》Logback是一个可靠、通用且快速的Java日志框架,作为Log4j的继承者,由Log4j创始人设计,:本文主要介绍... 目录一、Logback简介与Spring Boot集成基础1.1 Logback是什么?1.2 Sprin

Java实现MinIO文件上传的加解密操作

《Java实现MinIO文件上传的加解密操作》在云存储场景中,数据安全是核心需求之一,MinIO作为高性能对象存储服务,支持通过客户端加密(CSE)在数据上传前完成加密,下面我们来看看如何通过Java... 目录一、背景与需求二、技术选型与原理1. 加密方案对比2. 核心算法选择三、完整代码实现1. 加密上

在React聊天应用中实现图片上传功能

《在React聊天应用中实现图片上传功能》在现代聊天应用中,除了文字和表情,图片分享也是一个重要的功能,本文将详细介绍如何在基于React的聊天应用中实现图片上传和预览功能,感兴趣的小伙伴跟着小编一起... 目录技术栈实现步骤1. 消息组件改造2. 图片预览组件3. 聊天输入组件改造功能特点使用说明注意事项

Python 异步编程 asyncio简介及基本用法

《Python异步编程asyncio简介及基本用法》asyncio是Python的一个库,用于编写并发代码,使用协程、任务和Futures来处理I/O密集型和高延迟操作,本文给大家介绍Python... 目录1、asyncio是什么IO密集型任务特征2、怎么用1、基本用法2、关键字 async1、async

MySQL复合查询从基础到多表关联与高级技巧全解析

《MySQL复合查询从基础到多表关联与高级技巧全解析》本文主要讲解了在MySQL中的复合查询,下面是关于本文章所需要数据的建表语句,感兴趣的朋友跟随小编一起看看吧... 目录前言:1.基本查询回顾:1.1.查询工资高于500或岗位为MANAGER的雇员,同时还要满足他们的姓名首字母为大写的J1.2.按照部门

Java并发编程之如何优雅关闭钩子Shutdown Hook

《Java并发编程之如何优雅关闭钩子ShutdownHook》这篇文章主要为大家详细介绍了Java如何实现优雅关闭钩子ShutdownHook,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起... 目录关闭钩子简介关闭钩子应用场景数据库连接实战演示使用关闭钩子的注意事项开源框架中的关闭钩子机制1.

SpringMVC 通过ajax 前后端数据交互的实现方法

《SpringMVC通过ajax前后端数据交互的实现方法》:本文主要介绍SpringMVC通过ajax前后端数据交互的实现方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价... 在前端的开发过程中,经常在html页面通过AJAX进行前后端数据的交互,SpringMVC的controll

springboot上传zip包并解压至服务器nginx目录方式

《springboot上传zip包并解压至服务器nginx目录方式》:本文主要介绍springboot上传zip包并解压至服务器nginx目录方式,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录springboot上传zip包并解压至服务器nginx目录1.首先需要引入zip相关jar包2.然

Android Mainline基础简介

《AndroidMainline基础简介》AndroidMainline是通过模块化更新Android核心组件的框架,可能提高安全性,本文给大家介绍AndroidMainline基础简介,感兴趣的朋... 目录关键要点什么是 android Mainline?Android Mainline 的工作原理关键