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

相关文章

AJAX请求上传下载进度监控实现方式

《AJAX请求上传下载进度监控实现方式》在日常Web开发中,AJAX(AsynchronousJavaScriptandXML)被广泛用于异步请求数据,而无需刷新整个页面,:本文主要介绍AJAX请... 目录1. 前言2. 基于XMLHttpRequest的进度监控2.1 基础版文件上传监控2.2 增强版多

Python基础文件操作方法超详细讲解(详解版)

《Python基础文件操作方法超详细讲解(详解版)》文件就是操作系统为用户或应用程序提供的一个读写硬盘的虚拟单位,文件的核心操作就是读和写,:本文主要介绍Python基础文件操作方法超详细讲解的相... 目录一、文件操作1. 文件打开与关闭1.1 打开文件1.2 关闭文件2. 访问模式及说明二、文件读写1.

揭秘Python Socket网络编程的7种硬核用法

《揭秘PythonSocket网络编程的7种硬核用法》Socket不仅能做聊天室,还能干一大堆硬核操作,这篇文章就带大家看看Python网络编程的7种超实用玩法,感兴趣的小伙伴可以跟随小编一起... 目录1.端口扫描器:探测开放端口2.简易 HTTP 服务器:10 秒搭个网页3.局域网游戏:多人联机对战4.

用js控制视频播放进度基本示例代码

《用js控制视频播放进度基本示例代码》写前端的时候,很多的时候是需要支持要网页视频播放的功能,下面这篇文章主要给大家介绍了关于用js控制视频播放进度的相关资料,文中通过代码介绍的非常详细,需要的朋友可... 目录前言html部分:JavaScript部分:注意:总结前言在javascript中控制视频播放

Java并发编程必备之Synchronized关键字深入解析

《Java并发编程必备之Synchronized关键字深入解析》本文我们深入探索了Java中的Synchronized关键字,包括其互斥性和可重入性的特性,文章详细介绍了Synchronized的三种... 目录一、前言二、Synchronized关键字2.1 Synchronized的特性1. 互斥2.

Python基于wxPython和FFmpeg开发一个视频标签工具

《Python基于wxPython和FFmpeg开发一个视频标签工具》在当今数字媒体时代,视频内容的管理和标记变得越来越重要,无论是研究人员需要对实验视频进行时间点标记,还是个人用户希望对家庭视频进行... 目录引言1. 应用概述2. 技术栈分析2.1 核心库和模块2.2 wxpython作为GUI选择的优

C#基础之委托详解(Delegate)

《C#基础之委托详解(Delegate)》:本文主要介绍C#基础之委托(Delegate),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. 委托定义2. 委托实例化3. 多播委托(Multicast Delegates)4. 委托的用途事件处理回调函数LINQ

Python异步编程中asyncio.gather的并发控制详解

《Python异步编程中asyncio.gather的并发控制详解》在Python异步编程生态中,asyncio.gather是并发任务调度的核心工具,本文将通过实际场景和代码示例,展示如何结合信号量... 目录一、asyncio.gather的原始行为解析二、信号量控制法:给并发装上"节流阀"三、进阶控制

Java实现数据库图片上传与存储功能

《Java实现数据库图片上传与存储功能》在现代的Web开发中,上传图片并将其存储在数据库中是常见的需求之一,本文将介绍如何通过Java实现图片上传,存储到数据库的完整过程,希望对大家有所帮助... 目录1. 项目结构2. 数据库表设计3. 实现图片上传功能3.1 文件上传控制器3.2 图片上传服务4. 实现

使用mvn deploy命令上传jar包的实现

《使用mvndeploy命令上传jar包的实现》本文介绍了使用mvndeploy:deploy-file命令将本地仓库中的JAR包重新发布到Maven私服,文中通过示例代码介绍的非常详细,对大家的学... 目录一、背景二、环境三、配置nexus上传账号四、执行deploy命令上传包1. 首先需要把本地仓中要