Flutter未知功能插件deact的介绍与使用

发布于 1周前 作者 yibo5220 来自 Flutter

Flutter未知功能插件Deact的介绍与使用

1. Deact简介

Deact 是一个受 React 启发的 Web UI 框架。它通过组件和 DOM 元素构建用户界面。组件可以是无状态的或有状态的。

2. 快速上手

Deact 应用程序的入口点是 deact() 函数。该函数需要一个选择器字符串和一个返回应用程序根节点的函数。选择器字符串用于从 DOM 中查询主机元素。

所有主机元素下的元素都将被删除并替换为提供的根节点。节点可以是 DOM 元素、文本或组件。

import 'package:deact/deact.dart';
import 'package:deact/deact_html52.dart';

void main() {
  deact(
    '#root', // 选择器字符串,用于查询主机元素
    div(children: [txt('Hello World')]), // 根节点
  );
}

在上面的例子中,一个 div 元素包含文本 “Hello World” 被添加到 ID 为 root 的 DOM 元素下。

3. 组件

当应用程序变得复杂时,将 UI 分割成更小的可重用部分是有益的。这里,组件就派上用场了。组件是一个返回节点的函数。像普通的 Dart 函数一样,组件可以接受参数以配置组件。

要创建一个 Deact 组件,必须使用 fc() 函数。fc() 函数的唯一参数是一个构建函数,该函数必须返回一个节点,并接受一个 ComponentContext。这允许使用 Deact 的组件特定功能。

import 'package:deact/deact.dart';
import 'package:deact/deact_html52.dart';

void main() {
  deact(
      '#root',
      fragment([
        coloredText('I am blue.', 'blue'),
        coloredText('I am red.', 'red'),
      ]));
}

DeactNode coloredText(String text, String color) => fc((_) {
      return div(style: 'color: $color', children: [txt(text)]);
    });

在上面的例子中,定义了一个名为 coloredText 的组件。组件名称对 Deact 无关紧要,只是帮助给组件一个有意义的描述。

4. 状态

4.1 本地状态

组件可以具有状态。要访问组件的状态,使用 ComponentContextstate() 函数。状态具有名称和类型。

DeactNode statefulComponent() => fc((ctx) {
      final counter = ctx.state<int>('counter', 0); // 创建一个名为 'counter' 的状态,初始值为 0
      return div(
        onclick: (_) => counter.set((c) => c + 1), // 点击时增加计数器
        children: [txt('Counter: ${counter.value}')], // 显示计数器的值
      );
    });

在上面的例子中,创建了一个名为 counter 的状态,初始值为 0。状态由 State 类的实例表示。可以通过 value 获取器访问状态的实际值。要设置新值,可以使用 set() 函数或 value 设置器。如果状态的值是复杂类型且只需更新部分值,可以使用 update() 函数。在这两种情况下,组件及其所有子组件将在状态值更新后重新渲染。

4.2 全局状态

通过 state() 函数创建的状态是局部的。如果需要在多个组件之间共享状态,可以使用 GlobalStateProviderComponent。全局状态提供者是一个节点,因此可以放置在节点层次结构中的任何位置。每个位于全局状态提供者之下的组件都可以使用 ComponentContextglobalState() 方法读取或更新状态,就像处理本地状态一样。

void main() {
  deact(
      '#root',
      (_) => globalState<int>(
          name: 'counter',
          initialValue: 0,
          children: [
            incrementor(),
            display(),
          ],
        ));
}

DeactNode incrementor() => fc((ctx) {
      final counter = ctx.globalState<int>('counter'); // 访问全局状态
      return button(
        onclick: (_) => counter.set((c) => c + 1), // 增加计数器
        children: [txt('Click me to increment the counter')],
      );
    });

DeactNode display() => fc((ctx) {
      final counter = ctx.globalState<int>('counter'); // 访问全局状态
      return div(children: [txt('Counter: ${counter.value}')]); // 显示计数器的值
    });

在上面的例子中,在节点层次结构的顶层引入了一个名为 counter 的全局状态,初始值为 0。incrementordisplay 组件是提供者的子组件。incrementor 组件更新状态,而 display 组件读取状态。

5. 副作用(Effects)

副作用是在以下情况下可能被调用的函数:

  • 组件被添加到节点层次结构中
  • 组件被重新渲染
  • 组件的状态发生变化

组件可以有多个副作用,每个副作用都可以配置在哪些事件触发时执行。副作用可以有一个清理函数,清理函数的调用取决于副作用的配置。

如果副作用在组件被添加到节点层次结构时调用,清理函数将在组件从层次结构中移除时调用。如果副作用在每次重新渲染或状态变化后调用,清理函数将在下次调用副作用之前执行。

DeactNode componentWithEffect() => fc((ctx) {
      final counter = ctx.state<int>('counter', 0);
      ctx.effect('myEffect', () {
          // 执行某些操作...
          ...

          return () {
            // 执行一些清理操作...
            ...
          };
      }, [counter]); // 依赖于 'counter' 状态

      ...
    });

在上面的例子中,副作用 myEffect 在每次 counter 状态发生变化时执行。副作用依赖于 counter 状态。副作用函数返回的函数是清理函数,清理函数在下次执行副作用之前调用。

如果副作用依赖于空列表,则仅在组件被添加到节点层次结构时执行。清理函数在组件从层次结构中移除时调用。

如果提供 null 作为依赖项列表,则每次组件重新渲染时都会执行副作用。清理函数在下次执行副作用之前调用(但在第一次执行副作用之前不会调用)。

副作用的使用示例包括:

  • 执行 HTTP 请求
  • 获取和释放资源

6. 引用(References)

引用持有对值的引用。引用可以是局部的或全局的。引用会一直存在,直到创建引用的组件从节点层次结构中移除。更改引用的值不会强制组件重新渲染。

6.1 局部引用

通过调用 ComponentContextref() 方法创建局部引用。引用具有名称和可选的初始值。可以通过 value 成员访问引用的值。

一种特殊的设置引用值的方式是将引用提供给元素节点的 ref 参数。

DeactNode refs() => fc((ctx) {
      final inputRef = ctx.ref<InputElement?>('input'); // 创建一个引用,初始值为 null

      return fragment([
        button(
          onclick: (_) => inputRef.value?.focus(), // 点击按钮时聚焦输入框
          children: [txt('Click me to focus the input element!')],
        ),
        input(ref: inputRef), // 将引用传递给 input 元素
      ]);
    });

在上面的例子中,创建了一个对 InputElement 的引用,初始值为 null。引用作为参数传递给 input() 函数。当底层 DOM 元素创建时,它会被赋值给引用的 value

6.2 全局引用

使用 globalRef() 函数创建全局引用,该函数创建一个 GlobalRefProviderComponent 组件。该组件的所有子组件可以通过调用 ComponentContextglobalRef<T>(String) 方法访问全局引用。查找全局状态的规则同样适用于这里。

void main() {
  deact(
      '#root',
      (_) => globalRef<int>(
          name: 'counter',
          initialValue: 0,
          children: [
            incrementor(),
            display(),
          ],
        ));
}

DeactNode incrementor() => fc((ctx) {
      final counter = ctx.globalRef<int>('counter'); // 访问全局引用
      return button(
        onclick: (_) => counter.value = counter.value + 1, // 增加计数器
        children: [txt('Click me to increment the counter')],
      );
    });

DeactNode display() => fc((ctx) {
      final counter = ctx.state<int>('counter', 0);
      ctx.effect('init', () {
        // 监听 'counter' 引用的值变化事件
        ctx.globalRef<int>('counter').onChange.listen((c) {
          // 更新显示组件的内部状态
          // 这会强制组件重新渲染
          counter.value = c;
        });
        return null;
      }, dependsOn: []);
      return div(children: [txt('Counter: ${counter.value}')]);
    }, key: 'display');

如你所见,引用提供了一个值变化事件的流。

7. 实验性功能

Deact 尚未发布稳定版本。功能尚未完全实现,API 可能会发生变化,甚至可能是破坏性的。

目前,Deact 正在一个内部项目中进行测试。

如果你尝试使用 Deact:欢迎反馈!

8. 完整示例 Demo

下面是一个完整的 Deact 示例,展示了如何使用组件、状态、副作用和引用。

import 'package:deact/deact.dart';
import 'package:deact/deact_html52.dart';

void main() {
  deact(
    '#root',
    (_) => globalState<int>(
      name: 'counter',
      initialValue: 0,
      children: [
        incrementor(),
        display(),
        refs(),
      ],
    ),
  );
}

// 增加计数器的组件
DeactNode incrementor() => fc((ctx) {
      final counter = ctx.globalState<int>('counter');
      return button(
        onclick: (_) => counter.set((c) => c + 1),
        children: [txt('Click me to increment the counter')],
      );
    });

// 显示计数器的组件
DeactNode display() => fc((ctx) {
      final counter = ctx.globalState<int>('counter');
      ctx.effect('init', () {
        ctx.globalState<int>('counter').onChange.listen((c) {
          counter.value = c;
        });
        return null;
      }, dependsOn: []);
      return div(children: [txt('Counter: ${counter.value}')]);
    }, key: 'display');

// 使用引用的组件
DeactNode refs() => fc((ctx) {
      final inputRef = ctx.ref<InputElement?>('input');

      return fragment([
        button(
          onclick: (_) => inputRef.value?.focus(),
          children: [txt('Click me to focus the input element!')],
        ),
        input(ref: inputRef),
      ]);
    });

更多关于Flutter未知功能插件deact的介绍与使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter未知功能插件deact的介绍与使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


Flutter 未知功能插件 deact 的介绍与使用

在 Flutter 生态系统中,插件(Packages)扮演着至关重要的角色,它们扩展了 Flutter 的功能,使其能够轻松集成各种服务和特性。然而,需要注意的是,deact 并非一个广为人知的 Flutter 官方插件或常见社区插件。在 Flutter 的官方包管理器 Pub.dev 上也没有直接名为 deact 的插件。

不过,基于你的请求,我将假设 deact 是一个假设的或特定项目中的自定义插件,用于实现某些“未知功能”。由于无法确切知道 deact 的具体功能,我将提供一个假设性的插件实现示例,并展示如何在 Flutter 应用中使用它。

假设的 deact 插件功能

假设 deact 插件提供了一个简单的功能:在屏幕上显示一个可激活/停用状态的按钮,当按钮被点击时,它会改变其状态并显示相应的文本。

插件实现(伪代码)

由于无法直接创建实际的 Flutter 插件包,这里提供一个假设的插件实现思路,以及如何在 Flutter 应用中使用它的示例代码。

插件代码(假设性)

在实际情况下,插件代码会放在单独的包中,并包含 Dart 代码和原生平台代码(如果需要)。但在这里,我们仅展示 Dart 部分。

// 假设的 deact_plugin.dart 文件
class DeactButtonController {
  bool isActive = false;

  void toggle() {
    isActive = !isActive;
  }

  String getText() {
    return isActive ? 'Active' : 'Inactive';
  }
}
Flutter 应用代码

现在,让我们看看如何在 Flutter 应用中使用这个假设的 deact 插件。

import 'package:flutter/material.dart';
import 'deact_plugin.dart'; // 假设这个文件存在

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Deact Plugin Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final DeactButtonController _controller = DeactButtonController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Deact Plugin Demo'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            setState(() {
              _controller.toggle();
            });
          },
          child: Text(_controller.getText()),
        ),
      ),
    );
  }
}

解释

  1. 插件代码:我们假设了一个 DeactButtonController 类,它有一个 isActive 属性来跟踪按钮的状态,以及 togglegetText 方法来改变状态和获取相应的文本。

  2. Flutter 应用代码:在 MyHomePage 中,我们创建了一个 _MyHomePageState 类,并在其中实例化了一个 DeactButtonController 对象。然后,我们创建了一个 ElevatedButton,其 onPressed 回调调用 _controller.toggle() 方法来改变按钮状态,并使用 setState 方法来重建按钮以显示新的文本。

请注意,由于 deact 并非一个真实存在的 Flutter 插件,上述代码仅作为展示如何在 Flutter 应用中集成和使用自定义插件的示例。在实际项目中,你需要根据具体的插件文档和功能来实现和使用插件。

回到顶部