2022抛弃js ,拥抱Yew框架(三) - HTML

547 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情

HTML

html!

html! 宏允许你为组件编写声明式的 HTML 和 SVG。语法跟React的jsx极其相似 重点

  • 该html! 宏只能有一个根节点,可以使用*<></>*包裹,后面会讲到咱们再说
  • 空的 html! {} 会被调用,但是不渲染内容
  • 常量必须用 html! { "Hello, World" } 包裹
   fn view(&self, _context: &Context<Self>) -> Html {
        html! {
         <>
          <h1 >{"我想做个好人"}</h1> //简单的字面量值也需要使用{}包一下
          <h1 >{"我想做个好人"}</h1>
         </>
        }
    }

html!宏可以轻松达到编译器的默认递归限制。如果遇到编译错误,建议增大其值。在根 crate 使用这样的属性#![recursion_limit="1024"]lib.rsmain.rs 也是同理)处理这个问题。

Components

只要是实现了 Component trait 都可以在 html! 宏中使用

use yew::{Component, Html, html, Context, Properties};

struct MyComponent;

impl Component for MyComponent {
    type Message = ();
    type Properties = ();

    fn create(_ctx: &Context<Self>) -> Self {
        Self
    }

    fn view(&self, _ctx: &Context<Self>) -> Html {
        html! {
            { "This component has no properties!" }
        }
    }
}

#[derive(Clone, PartialEq, Properties)]
struct Props {
    prop1: String,
    prop2: String,
}

struct MyComponentWithProps;

impl Component for MyComponentWithProps {
    type Message = ();
    type Properties = Props;

    fn create(_ctx: &Context<Self>) -> Self {
        Self
    }

    fn view(&self, ctx: &Context<Self>) -> Html {
        html! {
            {
                format!(
                    "prop1: {} and prop2: {}",
                    ctx.props().prop1,
                    ctx.props().prop2
                )
            }
        }
    }
}

let props = Props {
    prop1: "Hello".to_owned(),
    prop2: "World".to_owned(),
};


html!{
    <>
        // 没有 properties
        <MyComponent />

        // 有 Properties
        <MyComponentWithProps prop1="lorem" prop2="ipsum" />

        // 同时设定整个 props provided
        <MyComponentWithProps ..props.clone() />

        // 变量的属性和特定值被覆盖
        <MyComponentWithProps prop2="lorem" ..props />
    </>
};

如果 Properties 中包含children,则可以访问和更改嵌套组件的属性

use yew::{Children, Component, Context, html, Html, Properties};

#[derive(PartialEq, Properties)]
struct Props {
    id: String,
    children: Children,
}

struct Container;

impl Component for Container {
    type Message = ();
    type Properties = Props;

    fn create(_ctx: &Context<Self>) -> Self {
        Self
    }

    fn view(&self, ctx: &Context<Self>) -> Html {
        html! {
            <div id={ctx.props().id.clone()}>
                { ctx.props().children.clone() }
            </div>
        }
    }
}

html! {
    <Container id="container">
        <h4>{ "Hi" }</h4>
        <div>{ "Hello" }</div>
    </Container>
};

html!宏可以使用表达式,..props把全部属性补充到属性上,此表达式必须在单独属性之后. html!中的children 会覆盖props 中的children;代码如下

use yew::{Children, Component, Context, html, Html, props, Properties};

#[derive(PartialEq, Properties)]
struct Props {
    id: String,
    children: Children,
}

struct Container;

impl Component for Container {
    type Message = ();
    type Properties = Props;

    fn create(_ctx: &Context<Self>) -> Self {
        Self
    }

    fn view(&self, ctx: &Context<Self>) -> Html {
        html! {
            <div id={ctx.props().id.clone()}>
                { ctx.props().children.clone() }
            </div>
        }
    }
}

let props = yew::props!(Container::Properties {
    id: "container-2",
    children: Children::default(),
});

html! {
    <Container ..props>
        // props.children 会被下面这一行覆盖
        <span>{ "I am a child, as you can see" }</span>
    </Container>
};

嵌套Children 的Props

如果包含组件标注了 children 的类型,则可以访问和更改嵌套组件的属性, 在下面的示例中,List 组件可以包含 ListItem 组件

use std::rc::Rc;
use yew::{html, ChildrenWithProps, Component, Context, Html, Properties};

#[derive(Clone, PartialEq, Properties)]
pub struct ListItemProps {
    value: String,
}

pub struct ListItem;

impl Component for ListItem {
    type Message = ();
    type Properties = ListItemProps;

    fn create(_ctx: &Context<Self>) -> Self {
        Self
    }

    fn view(&self, ctx: &Context<Self>) -> Html {
        html! {
            <span>
                { ctx.props().value.clone() }
            </span>
        }
    }
}

#[derive(PartialEq, Properties)]
pub struct Props {
    pub children: ChildrenWithProps<ListItem>,
}

pub struct List;
impl Component for List {
    type Message = ();
    type Properties = Props;

    fn create(_ctx: &Context<Self>) -> Self {
        Self
    }

    fn view(&self, ctx: &Context<Self>) -> Html {
        html! {{
            for ctx.props().children.iter().map(|mut item| {
                let mut props = Rc::make_mut(&mut item.props);
                props.value = format!("item-{}", props.value);
                item
            })
        }}
    }
}
html! {
    <List>
        <ListItem value="a" />
        <ListItem value="b" />
        <ListItem value="c" />
    </List>
};