一、需求:后端返回是base64数据,需要前端处理来展示文件。
二、实现方法:
解释一下这段代码的功能:
-
)
preview(item)
是一个函数,接受一个参数item
,其中包含了文件的相关信息。 -
)首先,通过条件语句
if (item.type == 'pdf')
检查文件类型是否为 'pdf'。 -
)如果文件类型是 'pdf',则执行以下操作:
- 使用
webAPI.server.get()
方法发送一个请求,请求的URL是通过this.previewUrl.format(item.id)
构建的。 - 在请求成功后,使用
then
处理响应数据,将返回的 base64 字符串解码为字节数组。 - 创建一个表示 PDF 文件的
Blob
对象,然后通过URL.createObjectURL(blob)
创建一个用于在浏览器中预览的 URL。 - 最后,调用
parent.layerAPI.openResultWin()
打开一个窗口,显示文件名和预览的文件 URL。(这一步对应第3点的代码)
- 使用
-
)如果文件类型不是 'pdf',则继续检查是否属于图像格式('png', 'gif', 'jpg', 'bmp', 'svg')。
-
)如果文件类型是图像格式,执行以下操作:
- 与 'pdf' 类似,发送一个异步请求获取文件内容,并处理响应数据。
- 解码 base64 字符串为字节数组,创建一个表示图像的
Blob
对象。 - 使用
URL.createObjectURL(blob)
创建用于在浏览器中预览的 URL。 - 使用
this.$nextTick()
来确保在组件更新后执行代码。 - 最后,如果存在
this.$refs.myImg
,将图像的showViewer
属性设置为true
,用于显示图像查看器。 -
<el-image
class="my-img"
v-if="imageUrl"
ref="myImg"
:src="imageUrl"
:preview-src-list="[imageUrl]"
>
</el-image>
-
)如果文件类型既不是 'pdf' 也不是图像格式,则可能会显示一条警告消息,(
// this.$message.warning('暂不支持该格式预览');
)。
总体而言,该函数用于处理文件预览的逻辑,支持预览 'pdf' 文件和一些图像格式。
<iframe
width="100%"
height="604px"
:src="PDFUrl"
v-if="PDFUrl"
/>
handleInitPDF() {
webAPI.server
.get({
url: this.getPdfUrl.format(this.id),
})
.then((res) => {
if (res.code == 0) {
if (res.data) {
const base64Str = res.data;
const byteCharacters = atob(base64Str);
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
const blob = new Blob([byteArray], { type: 'application/pdf' });
this.newurl = URL.createObjectURL(blob);
}
this.PDFUrl = this.newurl;
}
});
this.PDFvisiable = true;
},
三、如果要直接打开弹窗,与预览图片:
通俗的理解为:计算机是无法直接对base64数据进行处理的,不论是其他类型字符串、数字什么的也好,计算机可以理解的语言其实是二进制数据。因此我们需要将信息转化成计算机可以理解的二进制数据,所以需要先解码,此时我们得到的是原始的二进制 数据,但是由于我们最终需要的是一个url,因此我们需要继续对这个原始二进制数据处理。首先使用Unicode 编码,这一步是为了处理一些特殊的文件格式,比如 PDF,可能某些文件格式使用非常规的编码方式,需要在 JavaScript 中进行适当的转换,以便后续处理。接着类型化数组来表示二进制数据,再将类型化数组(如 Uint8Array)转换为 Blob 对象,因为类型化数组处理过的数据会更适合blob方法处理会更高效,Blob 对象是一种表示二进制大对象的标准化方式,此时我们得到的二进制数据就是标准化的我们所需要的二进制计算机可以理解的数据了,就可以使用方法得到url了。
preview(item) {
if (item.type == 'pdf') {
webAPI.server
.get({
url: this.previewUrl.format(item.id),
})
.then((res) => {
const base64Str = res.data;
const byteCharacters = atob(base64Str);
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
const blob = new Blob([byteArray], { type: 'application/pdf' });
this.fileUrl = URL.createObjectURL(blob);
parent.layerAPI.openResultWin( //直接打开弹窗
'查看文件:' + item.fileName,
this.fileUrl
);
});
return;
}
let imgFormat = ['png', 'gif', 'jpg', 'bmp', 'svg'];
if (imgFormat.includes(item.type)) {
webAPI.server
.get({
url: this.previewUrl.format(item.id),
})
.then((res) => {
const base64Str = res.data;
const byteCharacters = atob(base64Str);
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
const blob = new Blob([byteArray]);
this.imageUrl = URL.createObjectURL(blob);
this.$nextTick(() => {
if (this.$refs.myImg) {
this.$refs.myImg.showViewer = true;
}
});
});
return;
}
// this.$message.warning('暂不支持该格式预览');
},
四、详细解释一下具体的使用到的函数方法:
1)atob()
在JavaScript中,atob()
函数用于解码Base64编码的字符串。在这里,const byteCharacters = atob(base64Str);
这一行代码的目的是将Base64编码的字符串 base64Str
解码为原始的二进制数据,存储在 byteCharacters
变量中。
解释一下具体的步骤:
-
atob()
函数是Base64解码函数,它接受一个Base64编码的字符串作为参数,并返回解码后的原始二进制数据。 -
base64Str
是一个包含Base64编码数据的字符串,通常是从服务器端获取的文件内容以Base64编码的形式传输。 -
调用
atob(base64Str)
将Base64编码的字符串解码为原始的二进制数据,并将结果存储在byteCharacters
变量中。
在文件预览的上下文中,这一步是为了将服务器返回的Base64编码的文件内容解码为原始二进制数据,以便后续可以处理和使用这些数据,比如创建Blob对象用于文件预览。
2)new Array()
在这一步 const byteNumbers = new Array(byteCharacters.length);
中,代码创建了一个新的数组 byteNumbers
,其长度为 byteCharacters.length
。这一步的意义和作用:
-
byteCharacters
是之前通过atob()
函数解码得到的原始二进制数据,通常是代表文件内容的字节数据。 -
byteCharacters.length
返回byteCharacters
数组的长度,即字节数。 -
new Array(byteCharacters.length)
创建了一个新的数组,其长度为byteCharacters.length
。这个数组用于存储将字节数据转换为数字的结果。 -
在 JavaScript 中,
new Array(length)
创建一个具有指定长度的新数组。在这里,我们使用byteCharacters.length
作为数组的长度。
这一步的目的是为了准备一个数组,以便后续将字节数据转换为数字。每个元素将用于存储一个字节的数值。这通常是为了进一步处理二进制数据,例如将它们用于创建 Blob 对象、ArrayBuffer 等。后续代码可能会遍历字节数据,将每个字节的数值存储在数组中的相应位置。
3)charCodeAt()
这个循环的目的是遍历 byteCharacters
数组中的每个字符,获取每个字符的 Unicode 编码,并将这些编码存储到 byteNumbers
数组中。意义和作用:
-
for
循环通过变量i
从 0 开始逐步增加,直到byteCharacters.length - 1
。这样可以遍历byteCharacters
数组中的每个字符。 -
byteCharacters.charCodeAt(i)
是一个字符串方法,它返回给定位置(索引i
)的字符的 Unicode 编码。Unicode 编码是一个数字,表示字符在 Unicode 字符集中的位置。 -
对于每个字符,循环将其 Unicode 编码存储在
byteNumbers
数组的相应位置(索引i
)。
这个过程的目的是将原始二进制数据(以字符串形式存在的字符集)转换为对应的数字表示形式。后续代码可能需要使用这些数字,例如用于创建 Uint8Array
或其他二进制数据结构。在这个具体的代码中,这些数字可能被用于创建表示文件内容的二进制数据。
Unicode 编码: 在处理一些特殊的文件格式,比如 PDF,可能会涉及到将二进制数据按照一定规则转换为 Unicode 编码。这是因为某些文件格式可能使用非常规的编码方式,需要在 JavaScript 中进行适当的转换,以便后续处理。
4)Uint8Array()
这行代码的目的是创建一个 Uint8Array
对象,该对象包含了之前收集的字节数据的数值表示。具体的意义和作用:
-
Uint8Array
是 JavaScript 中的一种类型化数组(TypedArray),它表示一个包含 8 位无符号整数的二进制数据缓冲区。 -
byteNumbers
是之前通过遍历byteCharacters
字符串得到的包含每个字符 Unicode 编码的数组。 -
new Uint8Array(byteNumbers)
创建了一个新的Uint8Array
对象,该对象的内容是由byteNumbers
数组提供的数值。 -
这样得到的
byteArray
对象实际上是一个包含了文件内容的二进制数据,其中每个元素都是一个 8 位无符号整数,对应于之前字节数据的数值表示。
这一步的目的是将之前的字符编码数组转换为类型化数组,以便后续可以更方便地进行二进制数据的处理和操作。通常,这样的数组可以用于创建诸如 Blob
对象、ArrayBuffer
等二进制数据结构。在这个具体的代码中,byteArray
可能会用于创建表示文件内容的 Blob
对象,用于文件预览等操作。
5)Blob()
这行代码的目的是创建一个 Blob
对象,用于表示二进制大对象,其中包含了之前转换的文件内容的二进制数据。意义和作用:
-
Blob
是 JavaScript 中的一个对象,用于表示二进制大对象(Binary Large Object)。它通常用于存储二进制数据,比如文件内容。 -
new Blob([byteArray], { type: 'application/pdf' })
创建了一个新的Blob
对象,其中byteArray
是之前创建的Uint8Array
对象,它包含了文件内容的二进制数据。 -
第一个参数
[byteArray]
是一个数组,表示Blob
对象的内容。在这里,我们将byteArray
放入数组中,作为Blob
对象的二进制数据内容。 -
第二个参数
{ type: 'application/pdf' }
指定了Blob
对象的 MIME 类型。在这个具体的例子中,类型被指定为 'application/pdf',表明这是一个 PDF 文件。 -
注意:对于图片而言,浏览器通常可以通过文件扩展名等方式自动识别图像类型,因此在创建
Blob
对象时不强制指定类型是合理的。因为浏览器在处理图像时通常会根据文件的内容自动识别图像格式。 -
而对于预览 PDF 文件的情况,指定了
{ type: 'application/pdf' }
作为 MIME 类型。这是因为 PDF 文件不一定包含文件扩展名等能够让浏览器自动识别的信息,因此通过指定明确的 MIME 类型可以确保正确地将二进制数据解释为 PDF 文件。对于其他类型的文件,你可以根据需要指定适当的 MIME 类型。例如,Word 文档通常使用
'application/msword'
或'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
等类型。指定正确的 MIME 类型有助于确保浏览器正确解释和处理文件内容。如果未指定类型,浏览器将尝试根据文件内容自动确定,但这不总是可靠的。
这一步的目的是创建一个表示文件内容的 Blob
对象,方便后续在浏览器中进行预览。通常,这个 Blob
对象可以被用于创建一个 URL,然后用于打开文件预览窗口或其他相关操作。
6)URL.createObjectURL()
这行代码的目的是使用 URL.createObjectURL()
方法创建一个包含 Blob
对象内容的 URL。具体的意义和作用:
-
URL.createObjectURL(blob)
是一个 Web API 方法,它接受一个Blob
对象作为参数,并返回一个表示该Blob
对象内容的 URL。 -
blob
是之前创建的包含文件内容的Blob
对象。 -
URL.createObjectURL(blob)
将blob
对象转换为一个 URL,该 URL 可以用于在浏览器中访问Blob
对象的内容。 -
this.fileUrl = ...
将生成的 URL 存储在对象的fileUrl
属性中。这个属性可能被后续代码用于在浏览器中进行文件预览。
这一步的目的是为了获得一个用于预览文件内容的 URL,通常用于将文件内容嵌入到页面中或者在新窗口中打开。
7)为什么在这个过程中会选择使用类型化数组(Uint8Array
)
-
二进制数据的表示: 在JavaScript中,通常使用字符串表示文本数据,而不是直接操作二进制数据。但在处理文件、图像等二进制数据时,直接使用字符串可能不够高效。
-
Uint8Array:
Uint8Array
是一种类型化数组,它表示一个包含 8 位无符号整数的二进制数据缓冲区。这意味着每个元素都可以存储一个字节的数据。 -
二进制数据的处理: 将二进制数据存储在
Uint8Array
中,相比于字符串,提供了更直接、更高效的方式来处理二进制数据。你可以方便地遍历、修改、截取等操作,而无需担心字符编码等细节。 -
Blob 构造:
Blob
构造函数通常接受一个类型化数组作为参数,因为它能更好地适应二进制数据的结构。Uint8Array
就是这样的一种类型化数组,可以直接用于创建Blob
对象。 -
二进制数据的标准化: 使用
Uint8Array
作为中间步骤,有助于确保二进制数据在进行Blob构造等操作时,处于一种标准化和易处理的形式。
短而言之,Uint8Array
提供了一种更直接、更高效地处理二进制数据的方式,适合在文件、图像等场景下进行操作。在这个具体的代码中,它有助于确保二进制数据的结构和格式得到正确处理,以便后续的 Blob 构造和 URL 创建。