GPUI焦点管理与键盘导航技能Skill gpui-focus-handle

这个技能用于在GPUI框架中实现焦点管理和键盘导航功能,使Web或应用程序界面元素能够通过键盘操作,提升用户体验和可访问性。关键词:GPUI,焦点管理,键盘导航,UI开发,前端开发,可访问性,FocusHandle,键盘驱动界面。

前端开发 0 次安装 0 次浏览 更新于 3/23/2026

name: gpui-focus-handle description: GPUI中的焦点管理和键盘导航。用于处理焦点、焦点句柄或键盘导航。启用键盘驱动的接口,具有正确的焦点跟踪和可聚焦元素之间的导航。

概述

GPUI的焦点系统启用键盘导航和焦点管理。

关键概念:

  • FocusHandle:可聚焦元素的引用
  • 焦点跟踪:当前聚焦的元素
  • 键盘导航:使用Tab/Shift-Tab在元素之间导航
  • 焦点事件:on_focus, on_blur

快速入门

创建焦点句柄

struct FocusableComponent {
    focus_handle: FocusHandle,
}

impl FocusableComponent {
    fn new(cx: &mut Context<Self>) -> Self {
        Self {
            focus_handle: cx.focus_handle(),
        }
    }
}

使元素可聚焦

impl Render for FocusableComponent {
    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
        div()
            .track_focus(&self.focus_handle)
            .on_action(cx.listener(Self::on_enter))
            .child("可聚焦内容")
    }

    fn on_enter(&mut self, _: &Enter, cx: &mut Context<Self>) {
        // 当聚焦时处理Enter键
        cx.notify();
    }
}

焦点管理

impl MyComponent {
    fn focus(&mut self, cx: &mut Context<Self>) {
        self.focus_handle.focus(cx);
    }

    fn is_focused(&self, cx: &App) -> bool {
        self.focus_handle.is_focused(cx)
    }

    fn blur(&mut self, cx: &mut Context<Self>) {
        cx.blur();
    }
}

焦点事件

处理焦点变化

impl Render for MyInput {
    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
        let is_focused = self.focus_handle.is_focused(cx);

        div()
            .track_focus(&self.focus_handle)
            .on_focus(cx.listener(|this, _event, cx| {
                this.on_focus(cx);
            }))
            .on_blur(cx.listener(|this, _event, cx| {
                this.on_blur(cx);
            }))
            .when(is_focused, |el| {
                el.bg(cx.theme().focused_background)
            })
            .child(self.render_content())
    }
}

impl MyInput {
    fn on_focus(&mut self, cx: &mut Context<Self>) {
        // 处理获得焦点
        cx.notify();
    }

    fn on_blur(&mut self, cx: &mut Context<Self>) {
        // 处理失去焦点
        cx.notify();
    }
}

键盘导航

Tab顺序

使用track_focus()的元素自动参与Tab导航。

div()
    .child(
        input1.track_focus(&focus1)  // Tab顺序:1
    )
    .child(
        input2.track_focus(&focus2)  // Tab顺序:2
    )
    .child(
        input3.track_focus(&focus3)  // Tab顺序:3
    )

容器内的焦点

impl Container {
    fn focus_first(&mut self, cx: &mut Context<Self>) {
        if let Some(first) = self.children.first() {
            first.update(cx, |child, cx| {
                child.focus_handle.focus(cx);
            });
        }
    }

    fn focus_next(&mut self, cx: &mut Context<Self>) {
        // 自定义焦点导航逻辑
    }
}

常见模式

1. 挂载时自动聚焦

impl MyDialog {
    fn new(cx: &mut Context<Self>) -> Self {
        let focus_handle = cx.focus_handle();

        // 创建时聚焦
        focus_handle.focus(cx);

        Self { focus_handle }
    }
}

2. 焦点陷阱(模态框)

impl Modal {
    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
        div()
            .track_focus(&self.focus_handle)
            .on_key_down(cx.listener(|this, event: &KeyDownEvent, cx| {
                if event.key == Key::Tab {
                    // 保持焦点在模态框内
                    this.focus_next_in_modal(cx);
                    cx.stop_propagation();
                }
            }))
            .child(self.render_content())
    }
}

3. 条件性焦点

impl Searchable {
    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
        div()
            .track_focus(&self.focus_handle)
            .when(self.search_active, |el| {
                el.on_mount(cx.listener(|this, _, cx| {
                    this.focus_handle.focus(cx);
                }))
            })
            .child(self.search_input())
    }
}

最佳实践

✅ 在交互式元素上跟踪焦点

// ✅ 好:为键盘交互跟踪焦点
input()
    .track_focus(&self.focus_handle)
    .on_action(cx.listener(Self::on_enter))

✅ 提供视觉焦点指示器

let is_focused = self.focus_handle.is_focused(cx);

div()
    .when(is_focused, |el| {
        el.border_color(cx.theme().focused_border)
    })

❌ 不要:忘记跟踪焦点

// ❌ 坏:没有track_focus,键盘导航无法工作
div()
    .on_action(cx.listener(Self::on_enter))

参考文档

  • API参考:参见api-reference.md
    • FocusHandle API,焦点管理
    • 事件,键盘导航
    • 最佳实践