Skip to content

Textarea 文本域 ​

用于多行文本输入,适合备注、描述、评论等较长内容。

何时使用 ​

  • 需要输入多行内容,例如备注、描述、审批意见、评论。
  • 需要限制或提示字数,并在输入时展示统计。
  • 需要根据内容自动调整高度。
  • 需要在表单中展示禁用、只读、错误等状态。

基础用法 ​

vue
<template>
  <x-textarea v-model="value" placeholder="请输入描述" />
</template>

<script setup lang="ts">
import { ref } from 'vue';

const value = ref('用于搭建业务系统的 Vue 3 组件库');
</script>

可清除 ​

vue
<template>
  <x-textarea v-model="value" allow-clear placeholder="请输入内容" />
</template>

<script setup lang="ts">
import { ref } from 'vue';

const value = ref('这段内容可以一键清空');
</script>

字数统计 ​

20/80
vue
<template>
  <x-textarea
    v-model="value"
    :max-length="80"
    show-word-limit
    allow-clear
    placeholder="请输入不超过 80 个字符"
  />
</template>

<script setup lang="ts">
import { ref } from 'vue';

const value = ref('Textarea 支持字数统计和清除操作');
</script>

仅提示错误 ​

19/20
vue
<template>
  <x-textarea
    v-model="value"
    :max-length="{ length: 20, errorOnly: true }"
    show-word-limit
    allow-clear
  />
</template>

<script setup lang="ts">
import { ref } from 'vue';

const value = ref('这段内容允许超出限制,但会进入错误状态');
</script>

自适应高度 ​

自适应高度会随内容增长,并在达到 maxRows 后出现滚动条。继续输入更多内容可以观察高度变化。
49/160
vue
<template>
  <x-textarea
    v-model="value"
    :auto-size="{ minRows: 2, maxRows: 5 }"
    :max-length="160"
    show-word-limit
    allow-clear
  />
</template>

<script setup lang="ts">
import { ref } from 'vue';

const value = ref('自适应高度会随内容增长,并在达到 maxRows 后出现滚动条。');
</script>

动态切换自适应高度 ​

vue
<template>
  <x-checkbox v-model="enabled">启用自动高度(2 至 4 行)</x-checkbox>
  <x-textarea v-model="value" :auto-size="enabled ? { minRows: 2, maxRows: 4 } : false" allow-clear />
</template>

<script setup lang="ts">
import { ref } from 'vue';
const enabled = ref(false);
const value = ref('第一行\n第二行\n第三行\n第四行');
</script>

开启后立即按内容计算高度;关闭后恢复手动纵向拉伸。修改 minRows、maxRows 或 size 时会重新计算。

尺寸 ​

各尺寸档会同时调整最小高度、字号与内边距;size 变化后自适应高度会重新计算。

vue
<template>
  <x-textarea v-model="value" size="mini" />
  <x-textarea v-model="value" size="small" />
  <x-textarea v-model="value" size="medium" />
  <x-textarea v-model="value" size="large" />
</template>

<script setup lang="ts">
import { ref } from 'vue';

const value = ref('四种尺寸的文本域');
</script>

禁用与状态 ​

12/20
vue
<template>
  <x-textarea v-model="disabledValue" disabled />
  <x-textarea v-model="readonlyValue" :textarea-attrs="{ readonly: true }" />
  <x-textarea v-model="errorValue" error show-word-limit :max-length="20" />
</template>

<script setup lang="ts">
import { ref } from 'vue';

const disabledValue = ref('禁用状态不可编辑');
const readonlyValue = ref('只读状态通过 textareaAttrs 透传给原生 textarea');
const errorValue = ref('错误状态用于校验失败提示');
</script>

后缀内容 ​

备注
14/80
vue
<template>
  <x-textarea v-model="value" :max-length="80" show-word-limit>
    <template #suffix>
      <span>备注</span>
    </template>
  </x-textarea>
</template>

<script setup lang="ts">
import { ref } from 'vue';

const value = ref('审批备注需要更明确的填写状态');
</script>

原生属性 ​

vue
<template>
  <x-textarea
    v-model="value"
    :textarea-attrs="{ rows: 4, name: 'description', required: true, autocomplete: 'off' }"
  />
</template>

<script setup lang="ts">
import { ref } from 'vue';

const value = ref('内部 textarea 可以接收 rows、name、required 等原生属性');
</script>

自定义长度计算 ​

22/20
vue
<template>
  <x-textarea
    v-model="value"
    :max-length="20"
    show-word-limit
    :word-length="getMixedLength"
    :word-slice="sliceMixedLength"
    allow-clear
  />
</template>

<script setup lang="ts">
import { ref } from 'vue';

const value = ref('中文算 2,English 算 1');

const getMixedLength = (value: string) =>
  Array.from(value).reduce((total, char) => total + (char.charCodeAt(0) > 255 ? 2 : 1), 0);

const sliceMixedLength = (value: string, maxLength: number) => {
  let total = 0;
  let result = '';

  for (const char of Array.from(value)) {
    const next = total + (char.charCodeAt(0) > 255 ? 2 : 1);
    if (next > maxLength) break;
    total = next;
    result += char;
  }

  return result;
};
</script>

事件 ​

17/80
vue
<template>
  <x-textarea
    v-model="value"
    allow-clear
    :max-length="80"
    show-word-limit
    @input="(value) => pushLog(`input: ${value.length}`)"
    @change="(value) => pushLog(`change: ${value.length}`)"
    @clear="() => pushLog('clear')"
    @focus="() => pushLog('focus')"
    @blur="() => pushLog('blur')"
  />
  <div>
    <div v-for="(log, index) in logs" :key="`${index}-${log}`">{{ log }}</div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';

const value = ref('修改内容后失焦会触发 change');
const logs = ref<string[]>([]);

const pushLog = (message: string) => {
  logs.value = [message, ...logs.value].slice(0, 5);
};
</script>

在 Form 中校验 ​

组件放进 x-form-item 后会自动继承 Form 的尺寸与禁用状态,并按 FormItem 的校验规则展示错误。默认 validateTrigger 为 change,即值变化时触发校验。

vue
<template>
  <x-form ref="formRef" :model="formState" :rules="formRules">
    <x-form-item field="description" label="描述">
      <x-textarea v-model="formState.description" placeholder="请输入描述" allow-clear />
    </x-form-item>
    <x-form-item>
      <x-space>
        <x-button type="primary" @click="handleValidate">校验</x-button>
        <x-button @click="handleReset">重置</x-button>
      </x-space>
    </x-form-item>
  </x-form>
  <p role="status">{{ validateResult }}</p>
</template>

<script setup lang="ts">
import { reactive, ref } from 'vue';
import type { FormInstance, FieldRule } from 'x-next';

const formState = reactive({ description: "" });
const formRules: Record<string, FieldRule[]> = {
  description: [{ required: true, message: '请输入描述' }],
};
const formRef = ref<FormInstance>();
const validateResult = ref('');

const handleValidate = async () => {
  const errors = await formRef.value!.validate();
  validateResult.value = errors
    ? `校验失败:${Object.values(errors).map((error) => error.message).join(';')}`
    : '校验通过';
};
const handleReset = () => {
  formRef.value!.resetFields();
  validateResult.value = '已重置';
};
</script>

按需导入 ​

ts
import { Textarea } from 'x-next';

样式按需引入(base.css 为共享基础层,多个组件只需引入一次):

ts
import 'x-next/style/base.css';
import 'x-next/style/form-textarea.css';

Props ​

参数说明类型默认值
modelValue绑定值string-
defaultValue默认值,非受控模式string''
placeholder占位提示string-
disabled是否禁用booleanfalse
error是否为错误状态booleanfalse
maxLength最大长度;传入 errorOnly 时仅展示错误状态,不截断输入number | { length: number; errorOnly?: boolean }0
showWordLimit是否显示字数统计booleanfalse
allowClear是否允许清空booleanfalse
autoSize是否自适应高度,可配置最小和最大行数boolean | { minRows?: number; maxRows?: number }false
wordLength自定义字符长度计算方法(value: string) => number-
wordSlice自定义超长截取方法,通常与 wordLength 一起使用(value: string, maxLength: number) => string-
size组件尺寸'mini' | 'small' | 'medium' | 'large'跟随全局配置
textareaAttrs透传给内部 textarea 的原生属性Record<string, any>-

Events ​

事件名说明回调参数
update:modelValue值更新时触发value: string
input用户输入时触发value: string, event: Event
change文本域失焦且值变化时触发value: string, event: Event
clear点击清除按钮时触发event: MouseEvent
focus获取焦点时触发event: FocusEvent
blur失去焦点时触发event: FocusEvent

Slots ​

插槽名说明
suffix后缀内容

Methods ​

方法说明
focus使文本域获取焦点
blur使文本域失去焦点