在经过了长达两周的放假学习和带薪学习后, 我终于做出了人生中第一个前端应用 (虽然甚至现在我都没搞明白 Dart 有几种数据类型), 项目地址在这里
,演示地址在这里
下面我将介绍一下本项目使用的一些依赖, 设计结构和具体的实现.
项目依赖
总体上使用 Flutter 框架, 其他框架列表如下:
- dio: 网络请求
- date_format: 日期格式化
- get: Getx 状态管理
- logger: 日志框架
- sp_util: 对 shared_preferences 框架的封装, 用于在内存中存储一些数据
- intl: 时间戳和日期转换
设计结构
因为设计初期的原因多加了层 common 目录, 这个可以忽略
- pages:
- controller: 页面内请求的逻辑
- view: 画页面的代码
- binding: Getx 依赖注入
- component:
- body: 一些组件, 被 view 中的代码使用
- constants: 一些常量内容, 比如 token 的名字等
- http: 封装 dio 的 http 请求
- middleware: 中间件, 如页面跳转鉴权等
- models: 传输模型, 请求值和返回值的数据结构
- routes: 页面路由
- service: 向后端发送请求的代码, 可能会涉及到一些其他逻辑, 被 controller 调用, 调用 http 的代码发送请求; 有本地数据库时也可以将本地数据库的操作逻辑写在这里 (或者也可以单开一个 repository 目录也可以)
- config: 放一些配置文件
具体实现
重点截取一些代码
定义页面路由, 中间件 和 binding:
GetPage(
name: AppRoutes.task,
page: () => const TaskListView(),
binding: TaskBinding(),
middlewares: [
RouteAuthMiddleware(),
],
)
binding 依赖注入:
class LoginBinding implements Bindings {
static final Logger _logger = Logger();
@override
void dependencies() {
_logger.i('依赖注入');
Get.lazyPut(() => UserService());
Get.lazyPut<LoginController>(() => LoginController());
}
}
controller:
class LoginController extends GetxController {
// 这里就是具体的逻辑
}
view, 使用 controller 和 body:
class LoginView extends StatelessWidget {
const LoginView({super.key});
@override
Widget build(BuildContext context) {
return GetBuilder<LoginController>(
builder: (controller) => const Scaffold(
body: LoginBody(),
));
}
}
body:
class LoginBody extends GetView<LoginController> {
const LoginBody({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
// 这里就是正常的写页面
// 因为继承了GetView所以可以不用Get.find()直接使用controller
);
}
}
全局配置类 (注意不要使用 GetMaterialApp 中 onInit 初始化一些变量, 可能会有问题):
class GlobalConfig {
static final Logger _logger = Logger();
static Future init() async {
_logger.i('开始全局初始化');
await SpUtil.getInstance();
Get.put<UserService>(UserService());
_logger.i('全局初始化结束');
}
}
启动类:
Future<void> main() async {
await GlobalConfig.init();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return GetMaterialApp(
debugShowCheckedModeBanner: false,
enableLog: true,
initialRoute: AppPages.initial,
getPages: AppPages.routes,
);
}
}
本地调试命令:
# 防止CORS报错
flutter run -d chrome --web-renderer html --web-browser-flag "--disable-web-security"
打包成 Web 应用:
flutter build web --web-renderer html