在Flutter Web中创建一个上传文件的页面
第一种:flutter html库操作
(2024.5.9测试)
pubspec.yaml引入包:
environment:
sdk: '>=2.19.1 <3.0.0'
dependencies:
flutter:
sdk: flutter
http: 0.13.6
http_parser: 4.0.2
get: 4.6.5
dart页面:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'dart:html' as html;
import 'dart:typed_data';
import 'dart:async';
import 'dart:convert';
import 'package:http_parser/http_parser.dart';
import 'package:http/http.dart' as http;
class FileUploadWeb extends StatefulWidget {
const FileUploadWeb({super.key});
State<FileUploadWeb> createState() => _FileUploadWebState();
}
class _FileUploadWebState extends State<FileUploadWeb> {
late List<int> _selectedFile;
late Uint8List _bytesData;
late String _base64Encoded; // 文件base64编码
void _handleResult(Object result) {
setState(() {
_bytesData = const Base64Decoder().convert(result.toString().split(",").last);
_base64Encoded = const Base64Encoder().convert(_bytesData);
_selectedFile = _bytesData;
});
}
Future<void> _startWebFilePicker() async { // 选取文件
html.FileUploadInputElement uploadInput = html.FileUploadInputElement();
uploadInput.multiple = true;
uploadInput.draggable = true;
uploadInput.onChange.listen((e) {
final files = uploadInput.files;
final file = files![0];
final reader = html.FileReader();
reader.onLoadEnd.listen((e) {
if (reader.result != null) {
_handleResult(reader.result!);
} else {
print('选取文件失败');
}
});
reader.readAsDataUrl(file);
});
uploadInput.click();
}
Future<void> _makeRequestByGetHttp() async { // get库
var file = MultipartFile(_selectedFile, filename: "file.jpg");
var data = FormData({
'xxx1':'yyy1',
'_base64Encoded':_base64Encoded,
'file':file,
});
await GetConnect().post("http://127.0.0.1/savefile/",data);
}
Future<void> _makeRequestByHttp() async { // http库
var url = Uri.parse("http://127.0.0.1/savefile/");
var request = http.MultipartRequest("POST", url);
var file = http.MultipartFile.fromBytes('file', _selectedFile,
contentType: MediaType('application', 'octet-stream'),
filename: "file_up"
);
request.files.add(file);
request.send().then((response) {
print("test");
print(response.statusCode);
if (response.statusCode == 200) {
print("Uploaded!");
};
});
}
Widget build(BuildContext context) {
// TODO: implement build
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: const Text('file upload webpage'),
),
body: Form(
child: Padding(
padding: const EdgeInsets.only(top: 16.0, left: 28),
child: SizedBox(
width: 350,
child: Column(
children: [
MaterialButton(
color: Colors.pink,
elevation: 8,
highlightElevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8)),
textColor: Colors.white,
onPressed: _startWebFilePicker,
child: const Text('select a file'),
),
const Divider(
color: Colors.teal,
),
MaterialButton(
color: Colors.pink,
elevation: 8,
highlightElevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8)),
textColor: Colors.white,
onPressed: _makeRequestByHttp,
child: const Text('send file to server by http'),
),
const Divider(
color: Colors.teal,
),
MaterialButton(
color: Colors.pink,
elevation: 8,
highlightElevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8)),
textColor: Colors.white,
onPressed: _makeRequestByGetHttp,
child: const Text('send file to server by gethttp'),
),
]
)
),
),
),
),
);
}
}
效果图:
第二种:可以结合Flutter的UI组件和JavaScript互操作来实现文件上传功能。
以下是一个基本的步骤指南,用于在Flutter Web应用中创建一个文件上传页面:
-
创建Flutter UI:
使用Flutter的UI组件(如Button
、Text
等)来创建你的上传页面。你可以使用Button
来触发文件选择对话框和上传过程。 -
添加文件选择逻辑:
由于Flutter的Dart代码本身不直接支持文件选择对话框,你需要使用JavaScript来实现这一功能。你可以通过dart:html
库的window
对象来调用JavaScript函数。 -
使用JavaScript选择文件:
在index.html
文件中添加一个隐藏的<input type="file">
元素,并通过JavaScript代码来触发其点击事件,从而打开文件选择对话框。然后,你可以读取选定的文件内容,并将其发送到Flutter Dart代码中。 -
文件上传到服务器:
一旦你在Dart代码中接收到文件内容,你可以使用HTTP请求(如dart:http
库或第三方库如dio
)将文件上传到服务器。注意,由于Flutter Web的限制,你可能需要使用JavaScript的fetch
API或XMLHttpRequest来执行HTTP请求。 -
错误处理和用户反馈:
在整个过程中添加适当的错误处理逻辑,并向用户提供有关上传进度的反馈。
下面是一个简化的示例代码片段,展示了如何在Flutter Web中结合Dart和JavaScript来实现文件上传:
Flutter Dart代码(main.dart):
import 'dart:html' as html;
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
// 监听来自JavaScript的消息
html.window.onMessage.listen((event) {
// 处理从JavaScript发送过来的文件内容或上传结果
// ...
});
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('File Upload')),
body: Center(
child: ElevatedButton(
onPressed: () {
// 调用JavaScript函数来触发文件选择对话框
html.window.callMethod('triggerFileSelect', []);
},
child: Text('Select File'),
),
),
),
);
}
}
index.html(添加JavaScript代码):
<!DOCTYPE html>
<html>
<head>
<!-- ... 其他头部信息 ... -->
<script defer src="main.dart.js" type="application/javascript"></script>
<script>
function triggerFileSelect() {
// 创建一个隐藏的input元素来触发文件选择对话框
var input = document.createElement('input');
input.type = 'file';
input.click();
input.onchange = function(e) {
var file = e.target.files[0];
if (file) {
// 使用FileReader读取文件内容,或使用FormData上传文件
// 然后将文件内容或上传结果发送到Flutter Dart代码
// ...
}
};
}
</script>
</head>
<body>
<!-- Flutter应用的根元素 -->
<div id="flutter-app"></div>
<script>
// 初始化Flutter应用
// ...
</script>
</body>
</html>
请注意,上述代码只是一个概念性示例,并未包含完整的文件上传逻辑。你需要根据实际需求来实现文件读取、上传到服务器以及处理结果等逻辑。此外,由于Flutter Web的限制和不断发展,某些功能可能不如原生Web开发那样直接可用,因此你可能需要更深入地了解Web开发和JavaScript编程来充分利用Flutter Web的功能。