You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Yew创建类型安全的纯无状态输入组件?

Yew 纯无状态类型安全输入组件实现方案

以下是完全符合你需求的实现方式:组件纯无状态、所有配置通过Props传递、无内置验证逻辑,且通过Rust的类型系统保证不同输入类型只能传入对应合法属性。

1. 基础定义与类型枚举

首先定义输入类型枚举,确保类型安全的同时,方便转换为原生input的type属性值:

use yew::prelude::*;

#[derive(Clone, PartialEq, Debug)]
pub enum InputType {
    Text,
    Number,
    File,
    Password,
    Email,
}

impl ToString for InputType {
    fn to_string(&self) -> String {
        match self {
            InputType::Text => "text".into(),
            InputType::Number => "number".into(),
            InputType::File => "file".into(),
            InputType::Password => "password".into(),
            InputType::Email => "email".into(),
        }
    }
}

2. 分类型定义属性结构体

为每种输入类型定义专属的Props结构体,仅包含该类型支持的属性:

#[derive(Clone, PartialEq, Properties)]
pub struct TextInputProps {
    #[prop_or_default]
    pub placeholder: Option<String>,
    #[prop_or_default]
    pub value: Option<String>,
    #[prop_or_default]
    pub on_change: Option<Callback<InputEvent>>,
    #[prop_or_default]
    pub disabled: bool,
    #[prop_or_default]
    pub class: Option<String>,
}

#[derive(Clone, PartialEq, Properties)]
pub struct NumberInputProps {
    #[prop_or_default]
    pub placeholder: Option<String>,
    #[prop_or_default]
    pub value: Option<String>,
    #[prop_or_default]
    pub on_change: Option<Callback<InputEvent>>,
    #[prop_or_default]
    pub disabled: bool,
    #[prop_or_default]
    pub class: Option<String>,
    #[prop_or_default]
    pub max: Option<f64>,
    #[prop_or_default]
    pub min: Option<f64>,
    #[prop_or_default]
    pub step: Option<f64>,
}

#[derive(Clone, PartialEq, Properties)]
pub struct FileInputProps {
    #[prop_or_default]
    pub accept: Option<String>,
    #[prop_or_default]
    pub multiple: bool,
    #[prop_or_default]
    pub on_change: Option<Callback<InputEvent>>,
    #[prop_or_default]
    pub disabled: bool,
    #[prop_or_default]
    pub class: Option<String>,
}

3. 统一Props枚举

用枚举封装所有输入类型的属性,确保编译时就能检查属性与输入类型的匹配性:

#[derive(Clone, PartialEq, Properties)]
pub enum InputProps {
    Text(TextInputProps),
    Number(NumberInputProps),
    File(FileInputProps),
}

4. 实现纯无状态组件

组件为纯函数组件,无内部状态,仅根据Props渲染对应的原生input元素:

#[function_component(Input)]
pub fn input(props: &InputProps) -> Html {
    match props {
        InputProps::Text(text_props) => html! {
            <input
                type={InputType::Text.to_string()}
                placeholder={&text_props.placeholder}
                value={&text_props.value}
                disabled={text_props.disabled}
                class={&text_props.class}
                on_change={text_props.on_change.clone()}
            />
        },
        InputProps::Number(num_props) => html! {
            <input
                type={InputType::Number.to_string()}
                placeholder={&num_props.placeholder}
                value={&num_props.value}
                disabled={num_props.disabled}
                class={&num_props.class}
                on_change={num_props.on_change.clone()}
                max={num_props.max.map(|v| v.to_string())}
                min={num_props.min.map(|v| v.to_string())}
                step={num_props.step.map(|v| v.to_string())}
            />
        },
        InputProps::File(file_props) => html! {
            <input
                type={InputType::File.to_string()}
                accept={&file_props.accept}
                multiple={file_props.multiple}
                disabled={file_props.disabled}
                class={&file_props.class}
                on_change={file_props.on_change.clone()}
            />
        },
    }
}

5. 示例用法

完全符合你需求的文本输入框使用方式,以及其他类型的示例:

// 文本输入框(对应你要求的示例)
html! {
    <Input props={InputProps::Text(TextInputProps {
        placeholder: Some("search:".into()),
        ..Default::default()
    })} />
}

// 带max/min限制的数字输入框
html! {
    <Input props={InputProps::Number(NumberInputProps {
        placeholder: Some("Enter age".into()),
        min: Some(0.0),
        max: Some(120.0),
        ..Default::default()
    })} />
}

// 限制图片类型的多文件输入框
html! {
    <Input props={InputProps::File(FileInputProps {
        accept: Some("image/*".into()),
        multiple: true,
        ..Default::default()
    })} />
}

核心特性说明

  • 纯无状态:组件无内部状态,所有行为完全由Props驱动
  • 类型安全:编译时检查属性与输入类型的匹配性,比如File类型无法传入max/min属性
  • 无业务逻辑:组件仅负责渲染,验证、数据处理等逻辑完全由父组件通过on_change回调实现

内容的提问来源于stack exchange,提问作者dmn28

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 02:35:58