Raf*_* K. 38 javascript flux reactjs reactjs-flux
这是代码 actions.js
export function exportRecordToExcel(record) {
return ({fetch}) => ({
type: EXPORT_RECORD_TO_EXCEL,
payload: {
promise: fetch('/records/export', {
credentials: 'same-origin',
method: 'post',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(data)
}).then(function(response) {
return response;
})
}
});
}
Run Code Online (Sandbox Code Playgroud)
返回的响应是一个.xlsx
文件.我希望用户能够将其保存为文件,但没有任何反应.我假设服务器正在返回正确类型的响应,因为它在控制台中说
Content-Disposition:attachment; filename="report.xlsx"
Run Code Online (Sandbox Code Playgroud)
我错过了什么?我该怎么做减速机?
小智 45
浏览器技术目前不支持直接从Ajax请求下载文件.解决方法是添加隐藏的表单并在幕后提交,以使浏览器触发"保存"对话框.
我正在运行标准的Flux实现,所以我不确定Redux(Reducer)代码应该是什么,但我刚刚为文件下载创建的工作流程就像这样......
FileDownload
.所有这个组件都会渲染一个隐藏的表单,然后在里面componentDidMount
立即提交表单并调用它的onDownloadComplete
prop.Widget
带有下载按钮/图标(实际上很多......一个表中的每个项目都有一个).Widget
有相应的动作和存储文件.Widget
进口FileDownload
.Widget
有两种与下载相关的方法:handleDownload
和handleDownloadComplete
.Widget
商店有一个叫做的房产downloadPath
.它null
默认设置为.当它的值设置为时null
,没有正在进行的文件下载,并且该Widget
组件不会呈现该FileDownload
组件.Widget
调用handleDownload
触发downloadFile
操作的方法.该downloadFile
操作不会发出Ajax请求.它将一个DOWNLOAD_FILE
事件发送到商店,随之发送downloadPath
文件以供下载.商店保存downloadPath
并发出更改事件.downloadPath
,Widget
将渲染FileDownload
传递必要的道具包括downloadPath
以及作为handleDownloadComplete
值的方法onDownloadComplete
.FileDownload
渲染并提交表单method="GET"
(POST也应该工作)action={downloadPath}
,服务器响应现在将触发浏览器的目标下载文件的保存对话框(在IE 9/10中测试,最新的Firefox和Chrome).onDownloadComplete
/ handleDownloadComplete
.这会触发另一个调度DOWNLOAD_FILE
事件的操作.但是,此时间downloadPath
设置为null
.商店保存downloadPath
as null
并发出更改事件.downloadPath
该FileDownload
组件没有渲染Widget
和世界是一个快乐的地方.Widget.js - 仅部分代码
import FileDownload from './FileDownload';
export default class Widget extends Component {
constructor(props) {
super(props);
this.state = widgetStore.getState().toJS();
}
handleDownload(data) {
widgetActions.downloadFile(data);
}
handleDownloadComplete() {
widgetActions.downloadFile();
}
render() {
const downloadPath = this.state.downloadPath;
return (
// button/icon with click bound to this.handleDownload goes here
{downloadPath &&
<FileDownload
actionPath={downloadPath}
onDownloadComplete={this.handleDownloadComplete}
/>
}
);
}
Run Code Online (Sandbox Code Playgroud)
widgetActions.js - 仅部分代码
export function downloadFile(data) {
let downloadPath = null;
if (data) {
downloadPath = `${apiResource}/${data.fileName}`;
}
appDispatcher.dispatch({
actionType: actionTypes.DOWNLOAD_FILE,
downloadPath
});
}
Run Code Online (Sandbox Code Playgroud)
widgetStore.js - 仅部分代码
let store = Map({
downloadPath: null,
isLoading: false,
// other store properties
});
class WidgetStore extends Store {
constructor() {
super();
this.dispatchToken = appDispatcher.register(action => {
switch (action.actionType) {
case actionTypes.DOWNLOAD_FILE:
store = store.merge({
downloadPath: action.downloadPath,
isLoading: !!action.downloadPath
});
this.emitChange();
break;
Run Code Online (Sandbox Code Playgroud)
FileDownload.js
- 完整,功能齐全的代码,可以复制和粘贴
- 用Babel 6.x反映0.14.7 ["es2015","反应","阶段0"]
- 表单需要display: none
是哪个"隐藏" " className
是为了
import React, {Component, PropTypes} from 'react';
import ReactDOM from 'react-dom';
function getFormInputs() {
const {queryParams} = this.props;
if (queryParams === undefined) {
return null;
}
return Object.keys(queryParams).map((name, index) => {
return (
<input
key={index}
name={name}
type="hidden"
value={queryParams[name]}
/>
);
});
}
export default class FileDownload extends Component {
static propTypes = {
actionPath: PropTypes.string.isRequired,
method: PropTypes.string,
onDownloadComplete: PropTypes.func.isRequired,
queryParams: PropTypes.object
};
static defaultProps = {
method: 'GET'
};
componentDidMount() {
ReactDOM.findDOMNode(this).submit();
this.props.onDownloadComplete();
}
render() {
const {actionPath, method} = this.props;
return (
<form
action={actionPath}
className="hidden"
method={method}
>
{getFormInputs.call(this)}
</form>
);
}
}
Run Code Online (Sandbox Code Playgroud)
小智 31
您可以使用这两个库来下载文件http://danml.com/download.html https://github.com/eligrey/FileSaver.js/#filesaverjs
例
// for FileSaver
import FileSaver from 'file-saver';
export function exportRecordToExcel(record) {
return ({fetch}) => ({
type: EXPORT_RECORD_TO_EXCEL,
payload: {
promise: fetch('/records/export', {
credentials: 'same-origin',
method: 'post',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(data)
}).then(function(response) {
return response.blob();
}).then(function(blob) {
FileSaver.saveAs(blob, 'nameFile.zip');
})
}
});
// for download
let download = require('./download.min');
export function exportRecordToExcel(record) {
return ({fetch}) => ({
type: EXPORT_RECORD_TO_EXCEL,
payload: {
promise: fetch('/records/export', {
credentials: 'same-origin',
method: 'post',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(data)
}).then(function(response) {
return response.blob();
}).then(function(blob) {
download (blob);
})
}
});
Run Code Online (Sandbox Code Playgroud)
Sta*_*lav 10
我也遇到过同样的问题。我通过在空链接上创建一个引用来解决它,如下所示:
linkRef = React.createRef();
render() {
return (
<a ref={this.linkRef}/>
);
}
Run Code Online (Sandbox Code Playgroud)
在我的 fetch 函数中,我做了这样的事情:
fetch(/*your params*/)
}).then(res => {
return res.blob();
}).then(blob => {
const href = window.URL.createObjectURL(blob);
const a = this.linkRef.current;
a.download = 'Lebenslauf.pdf';
a.href = href;
a.click();
a.href = '';
}).catch(err => console.error(err));
Run Code Online (Sandbox Code Playgroud)
基本上,我已将 blob url(href) 分配给链接,设置下载属性并强制单击链接。据我所知,这是@Nate 提供的答案的“基本”想法。我不知道这样做是否是个好主意……我做到了。
小智 6
这对我有用。
const requestOptions = {
method: 'GET',
headers: { 'Content-Type': 'application/json' }
};
fetch(`${url}`, requestOptions)
.then((res) => {
return res.blob();
})
.then((blob) => {
const href = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = href;
link.setAttribute('download', 'config.json'); //or any other extension
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
})
.catch((err) => {
return Promise.reject({ Error: 'Something Went Wrong', err });
})
Run Code Online (Sandbox Code Playgroud)
小智 5
我设法使用这种在我的本地运行良好的代码更轻松地下载其余 API URL 生成的文件:
import React, {Component} from "react";
import {saveAs} from "file-saver";
class MyForm extends Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(event) {
event.preventDefault();
const form = event.target;
let queryParam = buildQueryParams(form.elements);
let url = 'http://localhost:8080/...whatever?' + queryParam;
fetch(url, {
method: 'GET',
headers: {
// whatever
},
})
.then(function (response) {
return response.blob();
}
)
.then(function(blob) {
saveAs(blob, "yourFilename.xlsx");
})
.catch(error => {
//whatever
})
}
render() {
return (
<form onSubmit={this.handleSubmit} id="whateverFormId">
<table>
<tbody>
<tr>
<td>
<input type="text" key="myText" name="myText" id="myText"/>
</td>
<td><input key="startDate" name="from" id="startDate" type="date"/></td>
<td><input key="endDate" name="to" id="endDate" type="date"/></td>
</tr>
<tr>
<td colSpan="3" align="right">
<button>Export</button>
</td>
</tr>
</tbody>
</table>
</form>
);
}
}
function buildQueryParams(formElements) {
let queryParam = "";
//do code here
return queryParam;
}
export default MyForm;
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
73957 次 |
最近记录: |