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

相关文章

Go语言数据库编程GORM 的基本使用详解

《Go语言数据库编程GORM的基本使用详解》GORM是Go语言流行的ORM框架,封装database/sql,支持自动迁移、关联、事务等,提供CRUD、条件查询、钩子函数、日志等功能,简化数据库操作... 目录一、安装与初始化1. 安装 GORM 及数据库驱动2. 建立数据库连接二、定义模型结构体三、自动迁

从基础到进阶详解Pandas时间数据处理指南

《从基础到进阶详解Pandas时间数据处理指南》Pandas构建了完整的时间数据处理生态,核心由四个基础类构成,Timestamp,DatetimeIndex,Period和Timedelta,下面我... 目录1. 时间数据类型与基础操作1.1 核心时间对象体系1.2 时间数据生成技巧2. 时间索引与数据

安装centos8设置基础软件仓库时出错的解决方案

《安装centos8设置基础软件仓库时出错的解决方案》:本文主要介绍安装centos8设置基础软件仓库时出错的解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录安装Centos8设置基础软件仓库时出错版本 8版本 8.2.200android4版本 javas

Linux基础命令@grep、wc、管道符的使用详解

《Linux基础命令@grep、wc、管道符的使用详解》:本文主要介绍Linux基础命令@grep、wc、管道符的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录grep概念语法作用演示一演示二演示三,带选项 -nwc概念语法作用wc,不带选项-c,统计字节数-

python操作redis基础

《python操作redis基础》Redis(RemoteDictionaryServer)是一个开源的、基于内存的键值对(Key-Value)存储系统,它通常用作数据库、缓存和消息代理,这篇文章... 目录1. Redis 简介2. 前提条件3. 安装 python Redis 客户端库4. 连接到 Re

GitLab文件的上传与下载方式

《GitLab文件的上传与下载方式》:本文主要介绍GitLab文件的上传与下载方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录GitLab 项目拉取到本地GitLab 项目上传方法方法 1:本地项目未初始化Git方法 2:本地项目已初始化GitGitLab 上

Nginx 413修改上传文件大小限制的方法详解

《Nginx413修改上传文件大小限制的方法详解》在使用Nginx作为Web服务器时,有时会遇到客户端尝试上传大文件时返回​​413RequestEntityTooLarge​​... 目录1. 理解 ​​413 Request Entity Too Large​​ 错误2. 修改 Nginx 配置2.1

SpringBoot基础框架详解

《SpringBoot基础框架详解》SpringBoot开发目的是为了简化Spring应用的创建、运行、调试和部署等,使用SpringBoot可以不用或者只需要很少的Spring配置就可以让企业项目快... 目录SpringBoot基础 – 框架介绍1.SpringBoot介绍1.1 概述1.2 核心功能2

Java应用如何防止恶意文件上传

《Java应用如何防止恶意文件上传》恶意文件上传可能导致服务器被入侵,数据泄露甚至服务瘫痪,因此我们必须采取全面且有效的防范措施来保护Java应用的安全,下面我们就来看看具体的实现方法吧... 目录恶意文件上传的潜在风险常见的恶意文件上传手段防范恶意文件上传的关键策略严格验证文件类型检查文件内容控制文件存储

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

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