Эта статья используется для записи реализации функции экспорта в различных бизнес-сценариях, встречающихся в проекте. Добро пожаловать лайк и избранное
1. Экспорт спины возврата
Этот вид экспорта мой любимый, бэкэнд более добросовестный, а фронтенд очень легкий. Конечно, в этом сценарии есть две ситуации.
- ссылка с доменным именем
if (res.code == 200) {
window.location.href = res.data;
}
-
ссылка без домена
Доменное имя — это доменное имя серверной части запроса, а не доменное имя страницы внешнего интерфейса. Проект обычно используется несколькими клиентами, поэтому внутреннее доменное имя обычно передается для эксплуатации и обслуживания для настройки. Это сделано в проекте.
Создайте файл config.js и файл config.js.example в общей папке статических ресурсов.Файл config.js загружается в git.Среда разработки может настроить доменное имя серверной части.В производственной среде , эксплуатация и обслуживание В нем настраивается доменное имя бэкенда, потому что оно было загружено на git, и конфигурация эксплуатации и обслуживания не будет перезаписана при обновлении кода. Файл config.js.example является примером, в котором рассказывается о том, как настраивать работу и техническое обслуживание.
config.js имеет то же содержимое, что и config.js.example.
/* 配置文件示列: 配置文件路径 public/config.js */ window.apiConfig = { baseUrl: '后端的域名', };Затем импортируйте config.js из public/index.html.
<script> var script = document.createElement('script'); var num = Math.floor(Math.random() * 10000); script.src = 'config.js?a=' + num; document.getElementsByTagName('head')[0].appendChild(script); script = document.getElementById('scriptConfig'); script.parentNode.removeChild(script); script = null; </script>Наконец, используйте это
if (res.code == 200) { window.location.href = window.apiConfig.baseUrl+res.data; }
Во-вторых, серверная часть возвращает экспорт бинарных данных.
- Во-первых, нам нужно настроить axios, потому что тип данных ответа сервера по умолчанию — json, который нужно изменить на blob.
export function export(data){ return service.get('接口地址',{ params:data, responseType:'blob' }) } - затем используйте
new Blob()для обработки двоичных данных, создания файла, а затем использованияcreateObjectURL()После создания ссылки используйте ссылку для ее автоматической загрузки. Давайте инкапсулируем метод и повесим его на цепочку прототипов Vue.
const install = function(Vue,opts){
* 处理二进制数据导出
* @param blob 二进制流
* @param name 文件名
*/
Vue.prototype.exportExcels = function(blob,name){
// type 为需要导出的文件类型,此处为xls表格类型
const file = new Blob([blob], { type: 'application/vnd.ms-excel' });
// 兼容不同浏览器的URL对象
const url = window.URL || window.webkitURL || window.moxURL;
// 创建下载链接
const downloadHref = url.createObjectURL(file);
// 创建a标签并为其添加属性
let downloadLink = document.createElement('a');
downloadLink.setAttribute('href', downloadHref);
downloadLink.setAttribute('download', name);
//将a标签添加到body中
document.body.appendChild(downloadLink);
// 触发a标签的点击,自动下载
downloadLink.click();
//下载完成后移除a标签
document.body.removeChild(downloadLink);
//释放下载链接
url.revokeObjectURL(downloadHref);
}
}
export default{
install
}
-
в
new Blob()Первый параметр — массив, каждый из которых — бинарный поток, а второй параметр — необязательный атрибут, гдеtypeАтрибут представляет собой MIME-тип файла, который определяется серверной частью.Обычно используемые типы MIME:
суффикс MIME-имя *.csv text/csv *.doc application/msword *.dot application/msword *.xls application/vnd.ms-excel *.xlsx application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
3. Добавьте параметры в адрес интерфейса экспорта, чтобы напрямую открыть загрузку.
В приведенных выше двух сценариях сначала необходимо запросить сервер, а возвращенные данные обработать, а затем загрузить. В этом сценарии добавьте параметры к адресу интерфейса экспорта, чтобы напрямую открыть загрузку, например:
window.location.href = '导出接口地址'?user='lhy'&date='2020-05';
Вышеупомянутый метод запроса эквивалентен методу get, но при запросе интерфейса экспорта слишком много параметров, а запрос с использованием метода get приведет к отсутствию параметров. В это время я думаю о способе использования почтового метода для запроса.
Поскольку этот сценарий заключается в непосредственном открытии адреса интерфейса экспорта для загрузки, использовать метод post немного сложно, поэтому в настоящее время нам нужно использовать HTML.<form>теги и объекты формы DOM для разрешения.
Мы инкапсулируем компонент для достижения.
<template>
<form :action="action" :target="target" :method="method" ref="exports">
<template v-if="data.length">
<input type="hidden" autocomplete="off" v-for="(item,i) in data" :name="item.name" :value="item.value"/>
</template>
<input type="hidden" autocomplete="off" readonly name="token" :value="token"/>
</form>
</template>
<script>
export default {
name: 'formExport',
props: {
action: {
type: String,
default: '',
},
target: {
type: String,
default: '_blank',
},
method: {
type: String,
default: 'post',
},
token:{
type: String,
default: '',
},
data: {
type: Array,
default() {
return [];
}
}
},
methods: {
submit() {
return new Promise((resoleve,reject) =>{
if (this.token) {
this.$refs.exports.submit();
resolv()
}else{
reject()
}
}
}
}
}
</script>
Документация по компонентам
- параметр
параметр иллюстрировать Типы необязательное значение По умолчанию action Обязательно, адрес интерфейса экспорта String — — target Указывает, где открыть адрес интерфейса экспорта String _blank: открыть в новом окне
_self: открыть в текущем окне_blank method метод запроса String post/get post token Требуется, аутентификация String — — data Обязательный, параметры передаются на сервер
{имя: имя параметра, значение: значение параметра}String — — - метод
название события иллюстрировать параметр обратного вызова submit представить форму Объект обещания - Пример
<template> <formExport ref="export" :action="exportData.url" :data="exportData.url" :token="exportData.token"></formExport> <el-button @click="handleExport">导出</el-button> </template> <script> export default { data(){ return{ exportData:{ url:'导出接口地址', data:{ user:'lds', page:1, pageSize:20, statTime:'2020-04', endTime:'2020-05' }, token:'12334f' } } }, components:{ formExport: () =>import('./formExport.vue') }, methods:{ handleExport(){ setTimeout(() => { this.$refs.export.submit(); }, 500); } } } </script>
4. Серверная часть возвращает только данные в формате JSON, а передняя часть генерирует загрузку в формате Excel.
Этого можно добиться с помощью двух плагинов xlsx и file-saver. Где xlsx предназначен для создания файла Excel, а файл-сохранение — для сохранения и загрузки файла Excel.
- Установите плагины xlsx и File-Saver с помощью npm, выполните команду
npm install xlsx --save
npm install file-saver --save
- Внести в сервисную папкуExport2Excel.js, инкапсулируйте методы в подключаемых модулях xlsx и сохранения файлов в этом скрипте.
-
Давайте инкапсулируем метод и повесим его на цепочку прототипов Vue.
- документация по параметрам
параметр иллюстрировать Типы По умолчанию необязательное значение Пример header данные заголовка таблицы array — — ['Клиент первого уровня', 'клиент подачи заявки', 'счет Alipay', 'сумма снятия', 'заявитель', 'время подачи заявки'] data Табличные данные array — — [{},{}] filename Имя файла Excel string — — 'excle1' opition Дополнительная конфигурация object — — {} - документация по параметрам
параметр иллюстрировать Типы По умолчанию необязательное значение Пример filterVal Фильтровать данные таблицы array — — ['id','name'] multiHeader Данные заголовка таблицы, за исключением последней строки данных заголовка таблицы, являются двумерными данными. Если их недостаточно, используйте '' для их заполнения. Это допустимо только в том случае, если bookType имеет значение xlsx или xls. array — — [['серийный номер', 'информация о клиенте', '', '', '', ''], ['', 'имя клиента', 'информация о снятии средств', '', '', '']] merges Правило объединения заголовков таблиц действует только в том случае, если bookType имеет значение xlsx или xls. array — — ['A1:A3', 'B1:F1', 'B2:B3', 'C2:F2'] autoWidth Адаптируется ли содержимое таблицы к ширине boolean true true/false — bookType Создать тип файла string xlsx xlsx/xls/csv —
const install = function(Vue,opts){
/**
* json数据生成Excel并下载
* @param header 表格头数据
* @param data 表格数据
* @param filename Excel文件名称
* @param opition 额外配置
*/
Vue.prototype.downloadExcels = function (header, data, filename, opition) {
let defaultOpition = {
filterVal: [],
multiHeader: [],
merges: [],
autoWidth: true,
bookType: 'xlsx',
}
if (header && Object.prototype.toString.call(header) != '[object Array]') {
throw new Error('header请传入数组');
}
if (data && Object.prototype.toString.call(data) != '[object Array]') {
throw new Error('data请传入数组');
}
if (opition && Object.prototype.toString.call(opition) == '[object Object]') {
defaultOpition = Object.assign({}, defaultOpition, opition);
}
if (Object.prototype.toString.call(defaultOpition.filterVal) != '[object Array]') {
throw new Error('filterVal请传入数组');
}
if (Object.prototype.toString.call(defaultOpition.multiHeader) != '[object Array]') {
throw new Error('multiHeader请传入数组');
}
if (Object.prototype.toString.call(defaultOpition.merges) != '[object Array]') {
throw new Error('merges请传入数组');
}
const formatJson = function (filterVal, jsonData) {
if (filterVal.length == 0) {
return jsonData;
} else {
return jsonData.map(v => filterVal.map(j => v[j]));
}
}
data = formatJson(defaultOpition.filterVal, data);
if (data[0].length > header.length) {
throw new Error('data中每项数据长度大于头部长度');
}
defaultOpition['data'] = data;
defaultOpition['header'] = header;
defaultOpition['filename'] = filename;
import('./Export2Excel').then(res => {
res.export_json_to_excel(defaultOpition);
})
}
}
export default{
install
}
- Пример
handleExport() {
const header = ['一级客户', '申请客户', '支付宝账号', '提现金额', '申请人', '申请时间'];
const option = {
bookType: 'xlsx',
filterVal: ['firstCustomName', 'custom_name', 'withdrawals_bank', 'withdrawals_amount', 'do_username', 'add_time'],
multiHeader: [
['序号', '客户信息', '', '', '', ''],
['', '客户姓名', '提现信息', '', '', '']
],
merges: ['A1:A3', 'B1:F1', 'B2:B3', 'C2:F2']
}
this.downloadExcels(header, this.tableData, '审核记录', option)
},
5. Экспорт через PDF
Этот экспорт подходит для визуальных сценариев данных
- Введите скрипт для создания PDF в index.html.jspdf.js.
- Добавьте сценарий скриншота в index.html.html2canvas.js.
- Давайте инкапсулируем метод и повесим его на цепочку прототипов Vue.
const install = function(Vue,opts){
* 将页面导出成pdf文件
* @param id 要生成PDF文件DOM区域的id
* @param fileName 导出的文件名称
* @param height 导出的pdf高度不够,需要设置额外高度,默认80
*/
Vue.prototype.exportPDF= function(id, fileName, height = 80){
//html2canvas只截取dom的可视区域,将dom的可视区域设置大解决导出视图不全的问题
document.getElementById(id).ownerDocument.defaultView.innerHeight = document.getElementById(id).scrollHeight + height;
html2canvas(document.getElementById(id), {
scale: 2,//按比例增加分辨率 (2=双倍).
dpi: 1080,//导出pdf清晰度 将分辨率提高到特定的DPI(每英寸点数)
background: "#fff", //背景设为白色(默认为黑色)
onrendered: function (canvas) {
let contentWidth = canvas.width;
let contentHeight = canvas.height;
//一页pdf显示html页面生成的canvas高度;
//a4纸的尺寸[595.28,841.89]
let pageHeight = contentWidth / 592.28 * 841.89;
//未生成pdf的html页面高度
let leftHeight = contentHeight;
//pdf页面偏移
let position = 0;
//html页面生成的canvas在pdf中图片的宽高
let imgWidth = 595.28;
let imgHeight = 592.28 / contentWidth * contentHeight;
let pageData = canvas.toDataURL('image/jpeg', 1.0);
let pdf = new jsPDF('', 'pt', 'a4');
//有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
//当内容未超过pdf一页显示的范围,无需分页
if (leftHeight < pageHeight) {
pdf.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight);
} else {
while (leftHeight > 0) {
pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight);
leftHeight -= pageHeight;
position -= 841.89;
//避免添加空白页
if (leftHeight > 0) {
pdf.addPage();
}
}
}
pdf.save(fileName);
}
)
}
}
export default{
install
}