组件 API
本文档介绍了组件系统的核心 API,包括组件的导入、属性声明、事件管理等,帮助开发者更高效地构建和管理自定义组件。
import!
import! 宏用于引入自定义组件,使其可以在当前作用域内使用。
用法
1import! {
2    crate::moudle::to::component;
3}
 
示例
在结构中使用 import! 引入 Rust 组件:
1<template>
2    <component name="MyView2">
3        <Header></Header>
4        <MyView1></MyView1>
5    </component>
6</template>
7
8<script>
9import! {
10    crate::views::my_view1::*;
11    crate::components::header::*;
12}
13</script>
 
#[component]
对于自定义组件,我们需要使用#[component]宏进行组件的属性声明,但并不是所有的类型都是允许的,能够在属性中使用的类型需要实现Defaulttrait,
自定义struct和enum则需要使用#[prop]进行标注。
1<script>
2#[component]
3pub struct MyView{
4    name: String
5}
6</script>
 
#[prop]
#[prop] 宏用于定义组件的属性(Props)。我们需要使用 #[prop] 宏来声明属性,以便实例化组件时进行赋值。
限制
不是所有的类型都可以作为 prop 使用,只有实现了 Default trait 的类型才能用于属性声明。
示例
1<script>
2#[component]
3pub struct MyView{
4    user: User,
5    auth: Auth
6}
7
8#[prop]
9#[derive(Debug, Clone)]
10pub struct User{
11    name: String
12}
13
14impl Default for User{
15    fn default() -> Self{
16        Self{ name: "John" }
17    }
18}
19
20#[prop]
21#[derive(Default, Clone, Copy, Debug)]
22pub enum Auth{
23    #[default]
24    Custom,
25    User,
26    Remote,
27    Other
28}
29</script>
 
get|set 方法
所有组件内声明的并在模版中进行绑定的属性都会自动生成对应的 get 和 set 方法。请使用 get|set 方法来访问和修改属性值,否则会导致双向绑定失效。
例如,上述 MyView 结构体会自动生成以下方法:
fn get_user(&self) -> User; 
fn set_user(&mut self, value: User) -> (); 
fn get_auth(&self) -> Auth; 
fn set_auth(&self, value: Auth) -> (); 
Default trait
Default trait 用于初始化组件实例的属性值。
示例
1<script>
2#[component]
3pub struct MyView {
4    name: String,
5}
6
7impl Default for MyView{
8    fn default() -> Self{
9        Self{
10            name: "John".to_string(),
11        }
12    }
13}
14</script>
 
在后续的代码中,您可以像实现impl一样实现组件方法和回调函数,例如:
1impl MyView{
2    fn click_btn(&mut self) -> (){
3        let name = self.get_name();
4        self.set_name("Alice".to_string());
5    }
6}
 
#[event]
自定义组件默认情况下不会触发任何事件,若要使用事件系统,需要使用 #[event] 宏进行事件声明。
要求
- 事件必须使用 
#[event] 进行标记。 
- 事件类型必须派生 
Debug 和 Clone trait。 
示例
1#[event]
2#[derive(Debug, Clone)]
3pub enum MyViewEvent {
4    Clicked,
5    Changed(String),
6}
 
在上述示例中,我们定义了 MyViewEvent 事件类型,其中:
Clicked:无参数的点击事件。 
Changed(String):携带 String 参数的变更事件。 
c_ref!
c_ref! 宏用于根据组件 id 获取组件引用,便于直接操作组件实例的引用。
示例
1<template>
2    <component name="MyView">
3        <label id="my_label" text="'Hello'"></label>
4        <button id="my_btn" @clicked="get_label_text()">
5            <label as_prop="slot" text="'get my label text'"></label>
6        </button>
7    </component>
8</template>
9
10<script>
11#[component]
12struct MyView{}
13
14impl MyView{
15    fn get_label_text(&mut self) {
16        let label = c_ref!(my_label);
17        let label_text = label.get_text();
18        println!("label text is: {}", label_text);
19    }
20}
21</script>
 
active!
active! 宏用于触发组件内部定义的事件,并将其传递给外部组件进行回调处理。
示例
组件MyView
1#[event]
2#[derive(Debug, Clone)]
3pub enum MyViewEvent {
4    Clicked,
5    Changed(String),
6}
7
8impl MyView{
9    fn click_view(&self) {
10        let _ = active!(MyViewEvent::Clicked);
11    }
12
13    fn change_view(&self) {
14        active!(MyViewEvent::Changed, "changed!".to_string());
15    }
16}
 
组件FatherView
FatherView 组件监听 MyView 的事件:
1<template>
2    <component name="FatherView">
3        <MyView 
4            @clicked="my_view_clicked()" 
5            @changed="my_view_changed()">
6        </MyView>
7    </component>
8</template>
9
10<script>
11#[component]
12struct FatherView{}
13
14impl FatherView{
15    fn my_view_clicked(&self) {
16        dbg!("my_view_clicked!");
17    }
18
19    fn my_view_changed(&self, param: impl EventParam) {
20        dbg!(param);
21    }
22}
23</script>
 
#[computed]
计算属性(Computed Property)是基于现有属性动态计算出的值,在 GenUI 中,计算属性不会存储状态,而是根据其依赖项的变化自动更新。
| 特性 | 计算属性 (Computed) | 双向绑定 (Two-way Binding) | 
|---|
| 是否存储状态 | ❌ 否 | ✅ 是 | 
| 是否可变 | ✅ 依赖项变化时更新 | ✅ 是 | 
| 是否可手动修改 | ✅ 但不能使用 set_xxx 方法 | ✅ 通过 set_xxx 修改 | 
| 依赖数据 | ✅ 需要依赖项 | ✅ 组件状态 | 
用法
#[computed]需要被声明在方法上 
#[computed]依赖于组件中声明的字段,可以是多个 
- 计算属性的返回值需要和组件绑定一致
 
- 计算属性相当于将对值的处理交给开发者,所以在计算属性的方法中不可以使用
set_xxx()对组件字段进行更改,取而代之的是更灵活的赋值更改 
1impl Hello{
2    #[computed([$(arg)*])]
3    fn $computed_fn($[&self|&mut self]?) -> $return_value_type{
4        // ...
5    }   
6}
 
$(arg)*: 依赖参数列表, 表示可以有一个或多个 
$computed_fn: 计算属性处理函数 
$[&self|&mut self]?: 表示可以是&self或&mut self这由您来决定 
$return_value_type: 返回值类型 
示例
计算属性的写法为在属性绑定时使用方法进行声明:
1<template>
2    <component name="Hello" class="hello_view" spacing="12.0">
3        <label :text="fmt_count()"></label>
4    </component>
5</template>
6
7<script>
8#[component]
9pub struct Hello{
10    count: u32,
11}
12
13impl Hello{
14    #[computed([count])]
15    fn fmt_count(&self) -> String{
16        format!("count: {}", self.count)
17    }   
18}
19</script>
 
nav_to!
用于从路由管理的子页面中跳转至其他子页面中。
用法
router.toml
1[bar_pages]
2login = { path = "crate::views::login::*", component = "Login" }
 
在router.toml中配置的login这个key就是页面id
示例
1impl Hello{
2    pub fn to_register(&mut self) {
3        nav_to!(register);
4    }
5}
 
nav_back!
通过压栈的方式让路由返回上一个页面,如果有的话。
用法
示例
impl Hello{
    pub fn back(&mut self) {
        nav_back!();
    }
}