依据 Dioxus 0.7 optimizing 指南做两项改进: - 为数据驱动列表渲染补全显式 key(13 处,9 个文件): home/archives/tags/search 文章与标签列表、post_card/post_footer 标签、header 桌面/移动导航、admin dashboard/posts/write 列表。 使用各类型稳定唯一字段(post.id / tag / tag.name / item.label / err.id / year_group.year / month_group.month_en)作为 key, 让 Dioxus diff 正确识别元素身份。骨架屏 for _ in 0..N 静态占位 循环与已带 key 的评论树/admin 行不动。 - [profile.release] 加 panic = "abort":WASM 去掉 unwind 元数据减小 体积;server 端错误处理走 Result+?(见 error.rs),不依赖 panic unwind,无副作用。 其余文件为本机格式化(单行折叠/多行展开),一并提交。 验证:dx check 通过、cargo test 405 passed。
94 lines
3.1 KiB
Rust
94 lines
3.1 KiB
Rust
//! 表单控件组件
|
||
//!
|
||
//! 提供登录、注册、评论等页面共享的输入框、按钮与提示框样式常量与组件。
|
||
|
||
use dioxus::prelude::*;
|
||
|
||
/// 输入框基础 CSS 类,统一文本框、邮箱框、URL 框等样式。
|
||
pub const INPUT_CLASS: &str = "w-full px-4 py-2 border border-paper-border rounded-lg bg-paper-entry text-paper-primary placeholder:text-paper-tertiary focus:outline-none focus:border-paper-accent focus:ring-1 focus:ring-paper-accent/30 transition-colors duration-200";
|
||
|
||
/// 主按钮 CSS 类,用于表单提交等主操作按钮。
|
||
pub const BUTTON_PRIMARY_CLASS: &str = "w-full py-2.5 px-4 bg-paper-accent text-white font-medium rounded-full hover:brightness-110 active:scale-[0.98] transition-all duration-200 cursor-pointer";
|
||
|
||
/// 表单输入框组件。
|
||
///
|
||
/// Props:
|
||
/// - `id`:input 元素 id,用于与 label 关联
|
||
/// - `r#type`:input 类型(如 `"text"`、`"email"`、`"password"`)
|
||
/// - `placeholder`:占位提示文本
|
||
/// - `value`:当前值
|
||
/// - `disabled`:是否禁用
|
||
/// - `oninput`:输入事件回调,返回新的字符串值
|
||
/// - `onkeydown`:可选的键盘事件回调
|
||
#[component]
|
||
pub fn FormInput(
|
||
id: Option<String>,
|
||
r#type: &'static str,
|
||
placeholder: &'static str,
|
||
value: String,
|
||
disabled: bool,
|
||
oninput: EventHandler<String>,
|
||
onkeydown: Option<EventHandler<KeyboardEvent>>,
|
||
) -> Element {
|
||
let disabled_class = if disabled {
|
||
"opacity-60 cursor-not-allowed"
|
||
} else {
|
||
""
|
||
};
|
||
rsx! {
|
||
input {
|
||
id: id.unwrap_or_default(),
|
||
class: "{INPUT_CLASS} {disabled_class}",
|
||
r#type: "{r#type}",
|
||
placeholder: "{placeholder}",
|
||
value: "{value}",
|
||
disabled,
|
||
oninput: move |e| oninput.call(e.value()),
|
||
onkeydown: move |e| {
|
||
if let Some(ref handler) = onkeydown {
|
||
handler.call(e);
|
||
}
|
||
},
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 表单标签组件。
|
||
///
|
||
/// Props:
|
||
/// - `label`:标签文本
|
||
/// - `html_for`:关联的 input id
|
||
#[component]
|
||
pub fn FormLabel(label: &'static str, html_for: Option<String>) -> Element {
|
||
rsx! {
|
||
label {
|
||
class: "block text-sm font-medium text-paper-secondary mb-1",
|
||
r#for: html_for.unwrap_or_default(),
|
||
"{label}"
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 提示框组件,用于显示成功、错误等状态消息。
|
||
///
|
||
/// Props:
|
||
/// - `message`:提示文本
|
||
/// - `variant`:风格类型,支持 `"error"`、`"success"` 与其他默认类型
|
||
#[component]
|
||
pub fn AlertBox(message: String, variant: &'static str) -> Element {
|
||
let (bg_class, text_class) = match variant {
|
||
"error" => (
|
||
"bg-red-100 dark:bg-red-900/30",
|
||
"text-red-700 dark:text-red-300",
|
||
),
|
||
"success" => (
|
||
"bg-green-100 dark:bg-green-900/30",
|
||
"text-green-700 dark:text-green-300",
|
||
),
|
||
_ => ("bg-paper-code-bg", "text-paper-secondary"),
|
||
};
|
||
rsx! {
|
||
div { class: "mb-4 p-3 {bg_class} {text_class} rounded-lg text-center", "{message}" }
|
||
}
|
||
}
|