元素

Input

<Input> 是原生文本输入框:iOS 和 Mac Catalyst 上是 UITextField(单行)或 UITextView(multiline),Android 上是 EditText。输入、光标、选区、自动更正和自动填充都由平台自己处理。

el-input.tsx 在线编辑 在新标签页打开
import { Input, mount, signal, Text, View, type YNode } from "nsh";

function App() {
  const name = signal("");
  const password = signal("");
  const notes = signal("");
  const submitted = signal("");
  let passwordInput!: YNode;
  const field = {
    fontSize: 16,
    color: "#1f2328",
    backgroundColor: "#ffffff",
    borderWidth: 1,
    borderColor: "#d0d7de",
    borderRadius: 10,
    paddingHorizontal: 12,
    paddingVertical: 10,
  } as const;
  return (
    <View style={{ flex: 1, backgroundColor: "#f6f8fa", padding: 20, paddingTop: 24, gap: 10 }}>
      <Text style={{ fontSize: 22, fontWeight: "700", color: "#1f2328" }}>input</Text>

      <Text style={{ color: "#57606a" }}>Name (controlled, maxLength 20)</Text>
      <Input
        style={field}
        value={name()}
        onChangeText={(text) => name.set(text)}
        placeholder="Ada Lovelace"
        placeholderTextColor="#8c959f"
        autoCapitalize="words"
        maxLength={20}
        returnKeyType="next"
        onSubmitEditing={() => passwordInput.focus()}
      />
      <Text style={{ fontSize: 12, color: "#6e7781" }}>{name().length} / 20</Text>

      <Text style={{ color: "#57606a" }}>Password</Text>
      <Input
        ref={passwordInput}
        style={field}
        value={password()}
        onChangeText={(text) => password.set(text)}
        secureTextEntry
        autoComplete="current-password"
        returnKeyType="done"
        onSubmitEditing={() => submitted.set(`Signed in as ${name() || "nobody"}`)}
      />

      <Text style={{ color: "#57606a" }}>Notes (multiline)</Text>
      <Input
        style={{ ...field, height: 100 }}
        multiline
        value={notes()}
        onChangeText={(text) => notes.set(text)}
        placeholder="Anything else?"
        placeholderTextColor="#8c959f"
      />

      <View
        onPress={() => submitted.set(`Signed in as ${name() || "nobody"}`)}
        activeOpacity={0.7}
        disabled={password().length === 0}
        class="disabled:opacity-40"
        style={{ backgroundColor: "#1f883d", borderRadius: 10, padding: 14, alignItems: "center", marginTop: 6 }}
      >
        <Text style={{ color: "#ffffff", fontSize: 16, fontWeight: "600" }}>Sign in</Text>
      </View>
      <Text style={{ color: "#1a7f37" }}>{submitted()}</Text>
    </View>
  );
}

mount(App);
import { Input, signal } from "nsh";

function NameField() {
  const name = signal("");
  return (
    <Input
      value={name()}
      onChangeText={(text) => name.set(text)}
      placeholder="你的名字"
      autoCapitalize="words"
      returnKeyType="done"
      style={{ fontSize: 16, padding: 12, borderWidth: 1, borderColor: "#d0d7de", borderRadius: 8 }}
    />
  );
}

#受控与非受控

  • 受控:传入 value,并在 onChangeText 中更新它。JS 可以改写用户的输入(去掉空白、格式化):输入框会立即显示用户的编辑,新的 value 到达后再被修正。每次原生编辑都带有一个计数,只有基于最新一次编辑的 value 才会被应用,因此即使某一轮 JS 执行较慢,也不会覆盖用户更新的输入。
  • 非受控:传入 defaultValue(或不传),从 onChangeText 或 onSubmitEditing 读取文本。

用户输入过程中必须遵守的规则以属性形式给出,由原生侧直接判断而不询问 JS:maxLength 限制长度,blurOnSubmit 决定回车键的行为。参见表单与键盘。

#属性

除通用属性外(style 的类型为 TextStyle:字体、颜色、对齐方式和视图样式都适用):

#文本

属性类型默认值说明
valuestring由 JS 控制的文本。
defaultValuestring初始文本。
placeholderstring输入框为空时显示的提示。
placeholderTextColorColorValue提示文字的颜色。
multilinebooleanfalse多行;回车插入换行。
maxLengthnumber用户最多能输入的字符数。
editablebooleantrue用户可以修改文本。
secureTextEntrybooleanfalse隐藏文本(密码)。
allowFontScalingbooleantrue跟随系统文字大小。
maxFontSizeMultipliernumber0系统缩放的上限(0 表示不限)。

#键盘

属性类型默认值说明
keyboardType"default" | "number-pad" | "numeric" | "decimal-pad" | "email-address" | "phone-pad" | "url""default"键盘布局。
returnKeyType"default" | "done" | "go" | "next" | "search" | "send""default"回车键的标签。
autoCapitalize"none" | "sentences" | "words" | "characters""sentences"自动大写。
autoCorrectbooleantrue系统自动更正。
autoCompleteAutoComplete | TextContentType输入框内容的类型,用于自动填充:"username"、"current-password"、"new-password"、"one-time-code"、"email"、"tel"、"postal-code"、"cc-number"、"off" 等。
blurOnSubmitbooleantrue回车让单行输入框失去焦点;设为 false 时键盘保持弹出(例如连续发送多条消息)。
autoFocusbooleanfalse出现时自动获得焦点。

#光标与选区

属性类型说明
caretHiddenboolean不绘制光标。
selectionColorColorValue光标和选区的颜色。
selection{ start: number; end?: number }受控选区,以 UTF-16 为单位;end 默认等于 start(即光标)。

#iOS

ios 键类型说明
textContentTypeAutoComplete | TextContentTypeautoComplete 在 iOS 上的名称("oneTimeCode"、"newPassword" 等)。
inputAccessoryViewIDstring一个 InputAccessoryView(nsh/ios)的 nativeID,输入框获得焦点时显示在键盘上方。
<Input autoComplete="one-time-code" keyboardType="number-pad" ios={{ textContentType: "oneTimeCode" }} />

#事件

事件载荷触发时机
onChangeText(text: string)用户修改了文本。
onSubmitEditing{ text }按下了回车键(单行)。
onFocus / onBlur无输入框获得 / 失去焦点。
onSelectionChange{ start, end }光标或选区移动(UTF-16 单位)。
onKeyPress{ key }文本变化之前:key 是输入的文本、"Backspace" 或 "Enter"。
onContentSizeChange{ width, height }文本尺寸变化(多行时按输入框宽度计算)。

随文本增高的多行输入框:

const height = signal(40);
<Input
  multiline
  onContentSizeChange={(e) => height.set(Math.min(120, Math.max(40, e.height + 16)))}
  style={{ height: height(), paddingHorizontal: 12, paddingVertical: 8 }}
/>;

#ref 方法

方法说明
focus()让输入框获得焦点并弹出键盘。
blur()让它失去焦点。
setSelection(start, end?)选中 start..end(UTF-16 单位);省略 end 时为光标。

按回车把焦点移到下一个输入框:

let password!: YNode;
<>
  <Input returnKeyType="next" onSubmitEditing={() => password.focus()} />
  <Input ref={password} secureTextEntry autoComplete="current-password" />
</>;

无论哪个输入框持有键盘,nsh/ui/mobile 的 Keyboard.dismiss() 都能把它收起。

#平台说明

  • <Scroll> 中的输入框会在原生侧自动避开键盘。其他位置请使用 KeyboardAvoidingView。
  • disabled 除了应用 disabled: 类,还会禁用输入框。
  • inputAccessoryViewID 在 Android 上无效,因为 Android 没有键盘附件栏。