Flutter样式管理插件style_dart的使用

Flutter样式管理插件style_dart的使用

style_dart简介

style_dart 是一个基于Flutter编码风格编写的后端框架。你可以通过这篇文章了解我们的主要动机、目的以及它的一般外观。文档和网站将在不久后开发完成。

加入Discord社区

插件图标


开始使用

1)创建一个简单的命令行Dart应用

首先,你需要创建一个简单的Dart命令行应用。

2)添加依赖

pubspec.yaml文件中添加以下依赖:

dependencies:
  style_dart: latest

3)创建一个服务器

类似于Flutter,“一切皆组件”的结构在Style中也被广泛使用。通过调用runService(MyComponent())方法可以运行一个Style应用程序。

定义一个组件

有一个组件用于创建简单的服务器:Server。它是“MaterialApp”或“CupertinoApp”在Flutter中的等价物。

Server是一个ServiceOwnerServiceOwner持有状态、定时任务和组件树。目前尚未实现,但诸如MicroServiceServiceServer(用于在服务器/微服务之间共享日志记录器等服务)这样的组件也是ServiceOwner

Server接收并持有主网关(children)、默认服务(如httpService)、根端点(rootEndpoint)、异常端点等。

现在让我们创建一个简单的HTTP服务器:

class MyServer extends StatelessComponent {
  const MyServer({Key? key}) : super(key: key);

  @override
  Component build(BuildContext context) {
    return Server(
      /// 默认监听localhost:80
      httpService: DefaultHttpServiceHandler(
        host: "localhost",
        port: 8080,
      ),
      children: [
        // 主网关
      ],
    );
  }
}

启动服务器

void main() {
  runService(MyServer());
}

现在,服务器已经准备好从本地主机启动,但我们还需要定义端点。


4)创建一个端点

端点用于处理客户端请求的函数。
“Endpoint”是一个组件,它可以作为组件参数放置。但是,组件树中的所有终点都必须以Endpoint结尾,并且端点不能有子节点。

端点示意图

方框是Component,圆圈是Endpoint

现在让我们创建一个返回“Hello World!”的端点。

class HelloEndpoint extends Endpoint {
  @override
  FutureOr<Object> onCall(Request request) {
    return "Hello World!";
  }
}

5)将端点放在路由上

处理请求的主要GatewayServerchildren值。

在所有Endpoint与它们之上的Gateway之间必须有一个Route。否则,在构建服务器时会报错。

现在让我们将端点放在响应“http://localhost/hello”请求的路由上。

class MyServer extends StatelessComponent {
  const MyServer({Key? key}) : super(key: key);

  @override
  Component build(BuildContext context) {
    return Server(
      httpService: DefaultHttpServiceHandler(
        host: "localhost",
        port: 8080,
      ),
      children: [
        Route("hello", root: HelloEndpoint())
      ],
    );
  }
}

Route接受一个root和一个child

root处理以输入路径段结尾的请求。

在这个例子中,HelloEndpoint处理请求“http://localhost/hello”。

如果我们要处理“hello/*”及其子路由,必须定义child参数。

如果我们要使用HelloEndpoint处理“hello/*”及其子路由,则需要设置handleUnknownAsRoot为true。


请求

现在通过dart run或IDE的运行命令启动服务器。

然后访问“http://localhost/hello”。


5)添加中间件(Gate)

我将创建中间件函数的组件命名为Gate

GateonRequest函数处理请求并等待请求或响应。

如果返回值是Request,请求将继续。这可以用来操纵请求内容。

如果返回值是Response,响应将发送给客户端。

此外,如果你想发送错误消息,此函数中抛出的异常将由上下文的ExceptionWrapper处理。

示例中的Gate仅适用于“host/api/users/*”。

第二个示例中的AuthFilterGate是一个Gate实现,可选地只接受经过身份验证的用户。

由于Style具有模块化结构,它将有许多开发者贡献的现成组件。

以下示例还展示了Gateway和路径段参数(“name”)的用法示例。

class MyServer extends StatelessComponent {
  const MyServer({Key? key}) : super(key: key);

  @override
  Component build(BuildContext context) {
    return Server(
      children: [
        // host/api/
        Route(
          "api",
          child: Gateway(
            children: [
              /// 中间件在这里 :)
              Gate(
                onRequest: (request) {
                  // 进行一些操作
                  return request; // 返回 Request 或 Response
                },
                // host/api/users/
                child: Route("users",
                    // host/api/users/{name}
                    child: Route("{name}",
                        root: SimpleEndpoint((req, c) {
                          // 使用此上下文的数据访问处理请求
                          return Create(
                            collection: "greeters",
                            data: {"greeter": req.arguments["name"]},
                          );
                        }))),
              ),
              // host/api/posts
              Route("posts",
                  root: AuthFilterGate(
                      child: SimpleEndpoint.static("Hi"))),
            ],
          ),
        ),
      ],
    );
  }
}

第一个Gate示例处理“/api/users”的根段及其所有子段。

在第二个示例中,它仅处理“api/posts”的根段。


6)添加自定义异常消息

你可以自定义处理异常的端点。

可以通过确切类型(例如下面的例子)或超类型(例如ClientErrorException)进行定制。除非重新包装,否则适用于所有子组件。

确定处理异常的端点时,检查顺序为:确切类型 -> (如果是实现)超类型(例如ClientError) -> Exception

异常处理图示

class MyStyleExEndpoint extends ExceptionEndpoint<BadRequest> {
  MyStyleExEndpoint() : super();

  @override
  FutureOr<Object> onError(Message message, BadRequest exception, StackTrace stackTrace) {
    return "Will always be bad !!!";
  }
}

// 在你的组件树中添加该组件。
Component getExceptionWrapper() {
  return ExceptionWrapper<BadRequest>(
      child: Route("always_throw", root: Throw(BadRequest())),
      exceptionEndpoint: MyExceptionEndpoint());
}

Throw是一个始终发送异常的端点。


7)添加你的数据访问

对于后端应用,访问数据是必需的。

在Style中,有一些我称之为基本服务的结构。

当前可用的服务包括:DataAccessHttpServiceLoggerAuthorizationCryptoWebSocketService

每个服务都有其特定的功能。

定义服务

所有服务都可以作为Server的默认服务分配。

class MyServer extends StatelessComponent {
  const MyServer({Key? key}) : super(key: key);

  @override
  Component build(BuildContext context) {
    return Server(
        httpService: DefaultHttpServiceHandler(),
        webSocketService: StyleTicketBaseWebSocketService(),
        logger: MyLogger(),
        dataAccess: DataAccess(MongoDbDataAccessImplementation()),
        children: [
          Route("hello", root: HelloEndpoint())
        ]);
  }
}

MongoDB实现可通过style_mongo包获得。

服务包装器

你可以为组件树的一部分使用不同的服务。只要不重新包装,这些包装就是有效的。

class MyServer extends StatelessComponent {
  const MyServer({Key? key}) : super(key: key);

  @override
  Component build(BuildContext context) {
    return Server(
      // 服务器默认
      dataAccess: DataAccess(MongoDbDataAccessImplementation()),
      children: [
        Route("hello", root: HelloEndpoint()),
        // 为“/other/*”使用不同的服务
        ServiceWrapper<DataAccess>(
          child: Route("other", root: HelloEndpoint()),
          service: DataAccess(SimpleCacheDataAccess()),
        ),
      ],
    );
  }
}

使用服务

你可以通过这种方式访问所有服务:

DataAccess.of(context)

8)访问数据

有许多方式可以访问你的数据。一种是在端点的onCall函数中返回一个Event

你也可以直接访问函数:DataAccess.of(context).read(...)

以下端点被放置在“/greet/{name}”路由上。

创建问候者

class HelloEndpoint extends Endpoint {
  @override
  FutureOr<Object> onCall(Request request) {
    return Create(
      collection: "greeters",
      data: {"greeter": request.arguments["name"]},
    );
  }
}

读取所有问候者

class GreetersEndpoint extends Endpoint {
  @override
  FutureOr<Object> onCall(Request request) {
    return ReadMultiple(collection: "greeters");
  }
}

自动化访问

你可以通过单一端点处理所有数据操作。

你可以完全自己处理,也可以使用现成的组件。

AccessPoint

AccessPoint接受一个回调函数,该函数运行并返回。这个AccessEvent由上下文的DataAccess处理。

class MyServer extends StatelessComponent {
  const MyServer({Key? key}) : super(key: key);

  @override
  Component build(BuildContext context) {
    return Server(
      httpService: DefaultHttpServiceHandler(),
      children: [
        Route("col",
            // AccessEvent
            root: AccessPoint((req, ctx) {
              return AccessEvent(
                  access: Access(
                    type: _getAccessType(req),
                    collection: req.arguments["col"],
                    // 可选参数
                    // query
                    // identifier
                    // data
                    // pipeline
                    // settings
                  ),
                  request: req);
            })),
      ],
    );
  }
}
RestApi

根据REST API标准工作的现成访问点,既可以在核心包中使用,也可以由开发者开发。

RestAccessPoint("route")

更多关于Flutter样式管理插件style_dart的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter样式管理插件style_dart的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


style_dart 是一个用于 Flutter 的样式管理插件,它允许开发者将样式集中管理,从而提高代码的可维护性和可读性。通过 style_dart,你可以将颜色、字体、边距等样式定义在一个地方,并在整个应用中重复使用。

安装 style_dart

首先,你需要在 pubspec.yaml 文件中添加 style_dart 依赖:

dependencies:
  flutter:
    sdk: flutter
  style_dart: ^1.0.0 # 请使用最新版本

然后运行 flutter pub get 来安装依赖。

基本用法

  1. 创建样式文件

    创建一个 Dart 文件(例如 app_styles.dart)来定义你的样式。

    import 'package:style_dart/style_dart.dart';
    
    final appStyles = StyleSheet({
      'colors': {
        'primary': Colors.blue,
        'secondary': Colors.green,
        'background': Colors.white,
      },
      'textStyles': {
        'heading': TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
        'body': TextStyle(fontSize: 16, color: Colors.black),
      },
      'spacing': {
        'small': 8.0,
        'medium': 16.0,
        'large': 24.0,
      },
    });
    
  2. 在应用中使用样式

    在 Flutter 应用中,你可以通过 StyleProvider 来提供样式,并在需要的地方使用它们。

    import 'package:flutter/material.dart';
    import 'app_styles.dart'; // 导入样式文件
    
    void main() {
      runApp(
        StyleProvider(
          styleSheet: appStyles,
          child: MyApp(),
        ),
      );
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: MyHomePage(),
        );
      }
    }
    
    class MyHomePage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        final style = Style.of(context);
    
        return Scaffold(
          backgroundColor: style.colors['background'],
          appBar: AppBar(
            title: Text('Style Dart Example'),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text(
                  'Heading',
                  style: style.textStyles['heading'],
                ),
                SizedBox(height: style.spacing['medium']),
                Text(
                  'Body Text',
                  style: style.textStyles['body'],
                ),
              ],
            ),
          ),
        );
      }
    }
    

样式嵌套和覆盖

style_dart 允许你嵌套样式表,并且可以在需要时覆盖父样式。

final nestedStyles = StyleSheet({
  'colors': {
    'primary': Colors.red,
  },
}, parent: appStyles);

在使用 nestedStyles 时,primary 颜色将被覆盖为红色,而其他样式(如 secondarybackground 等)将继承自 appStyles

动态样式

你还可以根据应用程序的状态动态生成样式。

final dynamicStyles = StyleSheet({
  'colors': {
    'primary': (context) => Theme.of(context).primaryColor,
  },
});
回到顶部