组件

TextField

TextField 是一个单行文本输入框:上方可以有标签,聚焦时边框变色,并带有清除按钮。它基于 <Input> 元素构建。

ui-text-field.tsx 在线编辑 在新标签页打开
// TextField: labels, placeholders, controlled and uncontrolled text, secure entry.
import { mount, signal, Text, View } from "nsh";
import { Button, TextField } from "nsh/ui/mobile";

function App() {
  const name = signal("Ada");
  const submitted = signal("");
  const locked = signal(false);
  return (
    <View style={{ flex: 1, backgroundColor: "#ffffff", padding: 16, paddingTop: 24, gap: 16 }}>
      <Text style={{ fontSize: 22, fontWeight: "700" }}>TextField</Text>
      <TextField
        label="Name (controlled)"
        placeholder="Your name"
        value={name()}
        onChange={(v) => name.set(v)}
        onSubmit={(v) => submitted.set(v)}
        disabled={locked()}
      />
      <Text style={{ color: "#737373" }}>{`Hello, ${name() || "nobody"}`}</Text>
      <TextField label="Password" placeholder="At least 8 characters" secure />
      <TextField label="Notes (no clear button)" defaultValue="Uncontrolled" clearable={false} />
      <Button
        variant="secondary"
        title={locked() ? "Enable the name" : "Disable the name"}
        onPress={() => locked.set(!locked())}
      />
      <Text style={{ color: "#737373" }}>{submitted() ? `Submitted: ${submitted()}` : "Press return to submit."}</Text>
    </View>
  );
}

mount(App);
import { TextField } from "nsh/ui/mobile";

#用法

import { mount, signal, Text, View } from "nsh";
import { TextField } from "nsh/ui/mobile";

function App() {
  const name = signal("");
  return (
    <View style={{ flex: 1, padding: 16, paddingTop: 48, gap: 12 }}>
      <TextField label="Name" placeholder="Your name" value={name()} onChange={(v) => name.set(v)} />
      <Text>{`Hello, ${name() || "nobody"}`}</Text>
    </View>
  );
}

mount(App);

#受控与非受控

  • 受控:传入 value 并在 onChange 中更新它,输入框显示 value。
  • 非受控:不传 value。输入框自己保存文本,从 defaultValue 开始,并通过 onChange 报告变化。
<TextField label="Notes" defaultValue="Draft" onChange={(text) => save(text)} />

#变体

<TextField label="Password" placeholder="At least 8 characters" secure />
<TextField label="Code" clearable={false} />
<TextField label="Account" value="ada@example.com" disabled />
  • secure 隐藏输入的内容,用于密码。
  • clearable(默认开启)在有文本时于末尾显示一个 × 按钮。按下后清空文本,通过 onChange 报告 "",并保持输入框聚焦,方便用户重新输入。
  • disabled 让输入框只读,以 50% 不透明度显示,并隐藏清除按钮。

#提交

用户按下键盘的回车键时,会以当前文本调用 onSubmit:

<TextField
  placeholder="Search"
  value={query()}
  onChange={(v) => query.set(v)}
  onSubmit={(text) => search(text)}
/>

#属性

属性类型默认值说明
labelstring | null无显示在输入框上方。
placeholderstring | null无输入框为空时显示。
valuestring | null无(非受控)由应用控制时的文本。
defaultValuestring""不由应用控制时的初始文本。
securebooleanfalse隐藏输入的内容(密码)。
clearablebooleantrue有文本时显示清除按钮。
disabledbooleanfalse不可编辑,50% 不透明度。
class、classList、style、testID、onLayout、ref作用于输入框的根视图(包含标签和输入框的那一列)。

#事件

事件参数触发时机
onChangestring:新文本用户输入、删除或按下清除按钮。
onSubmitstring:文本用户按下回车键。

#主题

部位主题键
标签muted.foreground,小号文字
输入框background,圆角为 radius,至少 44 pt 高
边框input.border;聚焦时为 ring
文本foreground
占位文字muted.foreground
选中文本primary.background
清除按钮muted.background;按下时为 secondary.active.background

参见主题。

#无障碍

输入框是原生文本框,屏幕阅读器会把它播报为可编辑文本。清除按钮的角色是 button,标签为 “Clear”,其触摸区域在 24 pt 的圆形之外再向外扩展 8 pt。label 是输入框上方的一段独立文本,不会作为输入框的无障碍标签。

#相关