> 文章列表 > 前端预览文件总结(表格、图片、文本、视频)

前端预览文件总结(表格、图片、文本、视频)

前端预览文件总结(表格、图片、文本、视频)

文件在线预览

最近有个需求要在浏览器上能够查看文件。就是拿到文件的链接,实现文件在线预览的功能,在经过不断地查资料,试错后终于完成了下列文件格式的在线预览功能,暂时没有做大文件的处理(不知道咋做)。

  • 图片类(jpg|jpeg|png|gif)
  • 文本类 (txt|svg|log|sh|out|dat|mat|pdb|msg|pdbq|prt|sta|skf|shear|hhr|a3m|pbs|com|info)
  • 视频类(mp4|avi|mkv|mov|webm|wmv)
  • 表格类(xsl|xslx|xls|xlsx|csv)
  • 。。。

图片类、视频类

这两种是最简单的,直接使用标签就可以。图片类使用 img,视频类使用 video

文本类

文本类有两种方法在线预览,

  • 第一种直接使用 iframe 标签,一般文本类型的文件都可以在 iframe 中显示出来
<iframe:src="previewUrl"title="文件预览"allowTransparency>当前文件不支持预览,请直接下载
</iframe>
  • 第二种是直接发请求,拿到文件内容,然后显示到页面上
//html
<template><div v-html="preHtml"></div>
</template>// js
<script setup>
import { onMounted, ref } from 'vue';
import { string, nullable } from 'vue-types';
import axios from 'axios';const props = defineProps({previewUrl: oneOfType([string(), nullable()]),
});const preHtml = ref('');const getPreviewFile = () => {axios({method: 'get',responseType: 'blob',url: props.previewUrl,}).then(({ data }) => {data.text().then(res => {preHtml.value = `<pre>${res}</pre>`;}});});
};
onMounted(() => {getPreviewFile();
});
</script>

表格类文件

表格类的预览采用了两个第三方的库,x-data-spreadsheetxlsx,特别要注意的是 csv 文件会有中文乱码问题,需要特殊处理,代码中有提到

xlsxOptions中的配置

<template><div id="xlsxPreviewId"></div>
</template><script setup>
import { watch, ref } from 'vue';
import { string, nullable } from 'vue-types';
import * as XLSX from 'xlsx'; // 预览excel文件
import axios from 'axios';
import Spreadsheet from 'x-data-spreadsheet';
import zhCN from 'x-data-spreadsheet/dist/locale/zh-cn';import { stox, xlsxOptions, isUTF8 } from './utils';Spreadsheet.locale('zh-cn', zhCN);const props = defineProps({previewUrl: oneOfType([string(), nullable()]),
});const previewExcel = url => {axios({url,method: 'GET',responseType: 'arraybuffer',}).then(res => {let grid = new Spreadsheet('#xlsxPreviewId', xlsxOptions);// 判断文件格式是否是utf-8,不是给转化下const buf = new Uint8Array(res.data);let enc = new TextDecoder('utf-8');let workbook;if (isUTF8(buf)) {// csv格式的文件会有中文乱码问题,在这里需要特殊处理workbook = XLSX.read(enc.decode(buf), {type: 'string',codepage: 936,});} else {workbook = XLSX.read(res.data);}grid.loadData(stox(workbook));})
};watch(() => props.previewUrl,newVal => {if (newVal) {previewExcel(newVal);}},{immediate: true,}
);
</script>

utils 文件代码

import * as XLSX from 'xlsx'; // 预览excel文件
function stox(wb) {var out = [];wb.SheetNames.forEach(function(name) {var o = { name: name, rows: {} };var ws = wb.Sheets[name];if (!ws || !ws['!ref']) return;var range = XLSX.utils.decode_range(ws['!ref']);range.s = { r: 0, c: 0 };var aoa = XLSX.utils.sheet_to_json(ws, { raw: false, header: 1, range: range });aoa.forEach(function(r, i) {var cells = {};r.forEach(function(c, j) {cells[j] = { text: c };var cellRef = XLSX.utils.encode_cell({ r: i, c: j });if (ws[cellRef] != null && ws[cellRef].f != null) {cells[j].text = '=' + ws[cellRef].f;}});o.rows[i] = { cells: cells };});o.merges = [];(ws['!merges'] || []).forEach(function(merge, i) {if (o.rows[merge.s.r] == null) {o.rows[merge.s.r] = { cells: {} };}if (o.rows[merge.s.r].cells[merge.s.c] == null) {o.rows[merge.s.r].cells[merge.s.c] = {};}o.rows[merge.s.r].cells[merge.s.c].merge = [merge.e.r - merge.s.r, merge.e.c - merge.s.c];o.merges[i] = XLSX.utils.encode_range(merge);});out.push(o);});return out;
}
function xtos(sdata) {var out = XLSX.utils.book_new();sdata.forEach(function(xws) {var ws = {};var rowobj = xws.rows;var minCoord = { r: 0, c: 0 },maxCoord = { r: 0, c: 0 };for (var ri = 0; ri < rowobj.len; ++ri) {var row = rowobj[ri];if (!row) continue;Object.keys(row.cells).forEach(function(k) {var idx = +k;if (isNaN(idx)) return;var lastRef = XLSX.utils.encode_cell({ r: ri, c: idx });if (ri > maxCoord.r) maxCoord.r = ri;if (idx > maxCoord.c) maxCoord.c = idx;var cellText = row.cells[k].text,type = 's';if (!cellText) {cellText = '';type = 'z';} else if (!isNaN(Number(cellText))) {cellText = Number(cellText);type = 'n';} else if (cellText.toLowerCase() === 'true' || cellText.toLowerCase() === 'false') {cellText = Boolean(cellText);type = 'b';}ws[lastRef] = { v: cellText, t: type };if (type == 's' && cellText[0] == '=') {ws[lastRef].f = cellText.slice(1);}if (row.cells[k].merge != null) {if (ws['!merges'] == null) ws['!merges'] = [];ws['!merges'].push({s: { r: ri, c: idx },e: { r: ri + row.cells[k].merge[0], c: idx + row.cells[k].merge[1] },});}});}ws['!ref'] = minCoord ? XLSX.utils.encode_range({ s: minCoord, e: maxCoord }) : 'A1';XLSX.utils.book_append_sheet(out, ws, xws.name);});return out;
}const xlsxOptions = {mode: 'read', // edit | readshowToolbar: false,showGrid: true,showContextmenu: false,view: {height: () => document.getElementById('xlsxPreviewId').clientHeight,width: () => document.getElementById('xlsxPreviewId').clientWidth,},row: {len: 99999,height: 25,},col: {len: 9999,width: 100,indexWidth: 60,minWidth: 60,},style: {bgcolor: '#ffffff',align: 'left',valign: 'middle',textwrap: false,strike: false,underline: false,color: '#0a0a0a',font: {name: 'Helvetica',size: 10,bold: false,italic: false,},},
};function isUTF8(bytes) {var i = 0;while (i < bytes.length) {if (// ASCIIbytes[i] == 0x09 ||bytes[i] == 0x0a ||bytes[i] == 0x0d ||(0x20 <= bytes[i] && bytes[i] <= 0x7e)) {i += 1;continue;}if (// non-overlong 2-byte0xc2 <= bytes[i] &&bytes[i] <= 0xdf &&0x80 <= bytes[i + 1] &&bytes[i + 1] <= 0xbf) {i += 2;continue;}if (// excluding overlongs(bytes[i] == 0xe0 &&0xa0 <= bytes[i + 1] &&bytes[i + 1] <= 0xbf &&0x80 <= bytes[i + 2] &&bytes[i + 2] <= 0xbf) || // straight 3-byte(((0xe1 <= bytes[i] && bytes[i] <= 0xec) || bytes[i] == 0xee || bytes[i] == 0xef) &&0x80 <= bytes[i + 1] &&bytes[i + 1] <= 0xbf &&0x80 <= bytes[i + 2] &&bytes[i + 2] <= 0xbf) || // excluding surrogates(bytes[i] == 0xed &&0x80 <= bytes[i + 1] &&bytes[i + 1] <= 0x9f &&0x80 <= bytes[i + 2] &&bytes[i + 2] <= 0xbf)) {i += 3;continue;}if (// planes 1-3(bytes[i] == 0xf0 &&0x90 <= bytes[i + 1] &&bytes[i + 1] <= 0xbf &&0x80 <= bytes[i + 2] &&bytes[i + 2] <= 0xbf &&0x80 <= bytes[i + 3] &&bytes[i + 3] <= 0xbf) || // planes 4-15(0xf1 <= bytes[i] &&bytes[i] <= 0xf3 &&0x80 <= bytes[i + 1] &&bytes[i + 1] <= 0xbf &&0x80 <= bytes[i + 2] &&bytes[i + 2] <= 0xbf &&0x80 <= bytes[i + 3] &&bytes[i + 3] <= 0xbf) || // plane 16(bytes[i] == 0xf4 &&0x80 <= bytes[i + 1] &&bytes[i + 1] <= 0x8f &&0x80 <= bytes[i + 2] &&bytes[i + 2] <= 0xbf &&0x80 <= bytes[i + 3] &&bytes[i + 3] <= 0xbf)) {i += 4;continue;}return false;}return true;
}
function ab2str(buf) {return String.fromCharCode.apply(null, new Uint8Array(buf));
}
export { stox, xtos, xlsxOptions, isUTF8, ab2str };

END

先列举这么多,后续有其他类型的文件需要在线预览会接着更新