shadcn-vue Textarea 组件完全指南:安装、属性解析与表单集成实战
【免费下载链接】shadcn-vueVue port of shadcn-ui项目地址: https://gitcode.com/gh_mirrors/sh/shadcn-vue
导读
Textarea 是 shadcn-vue 中用于展示多行文本输入的表单组件,它在原生<textarea>之上封装了完整的主题样式与受控值绑定能力,开箱即用地支持占位符、禁用态、焦点环以及 v-model 双向绑定。本文以 textarea.md 为骨架,结合仓库中default与new-york两套风格的源码实现,完整讲解安装方式、核心 API、六种常用场景的示例代码,并深入剖析其基于useVModel的受控原理与配合 vee-validate 表单校验的落地写法。
Textarea 是什么
Textarea 组件是对原生<textarea>元素的样式化封装,核心目标有两个:
- 统一样式:通过 Tailwind CSS 类组合出与 shadcn-vue 其他表单组件(Input、Select 等)一致的视觉体系;
- 简化受控逻辑:通过
modelValue/update:modelValue实现 Vue 标准的v-model双向绑定,无需开发者手动维护value事件。
在仓库中,Textarea 的组件源码位于 Textarea.vue(default 风格)与 Textarea.vue(new-york 风格),两套实现的脚本逻辑完全相同,仅样式类存在差异。配套的示例代码位于 examples 目录 下,覆盖文档中列出的全部场景。
安装
文档提供了两种安装方式:CLI 自动安装与手动复制。
方式一:CLI 安装(推荐)
在项目根目录执行:
npx shadcn-vue@latest add textarea该命令会自动完成依赖安装、组件文件生成与路径别名配置。shadcn-vue 的 CLI 是 Vue 生态中 shadcn-ui 的命令行实现,add子命令会从组件注册表拉取 Textarea 组件及其依赖。
方式二:手动安装
手动安装分两步:
第一步,安装运行依赖:
npm install reka-ui从源码 Textarea.vue 可以看到,Textarea 实际还依赖@vueuse/core(提供useVModel)与项目内的cn工具函数(通常位于src/lib/utils.ts),因此完整的依赖还包括:
npm install reka-ui @vueuse/core同时需要保证项目中存在基于clsx与tailwind-merge的cn工具函数(cn用于合并默认样式与外部传入的class)。
第二步,复制组件代码:
将 Textarea.vue 复制到项目的src/components/ui/textarea/Textarea.vue,并确认路径别名@指向src(Vite 或 Nuxt 配置中通常已定义)。
基本用法
安装完成后,在组件中按如下方式引入使用:
<script setup lang="ts"> import { Textarea } from '@/components/ui/textarea' </script> <template> <Textarea /> </template>Textarea支持原生<textarea>的全部标准属性,包括placeholder、disabled、id、rows、maxlength等,均会透传到内部的原生元素上。
组件 API 与源码解析
完整阅读 Textarea.vue 的<script setup>部分,可以提炼出该组件的完整公开 API:
Props
| Prop | 类型 | 说明 |
|---|---|---|
class | HTMLAttributes["class"] | 追加到组件根元素上的自定义样式类,经cn合并 |
modelValue | string \| number | v-model绑定的值 |
defaultValue | string \| number | 非受控模式下的初始默认值 |
Emits
| 事件 | 载荷类型 | 说明 |
|---|---|---|
update:modelValue | string \| number | v-model更新事件 |
受控绑定原理
源码中的关键逻辑是useVModel的使用:
const modelValue = useVModel(props, "modelValue", emits, { passive: true, defaultValue: props.defaultValue, })这是@vueuse/core提供的v-model封装,其作用:
- 双向绑定:内部
v-model="modelValue"直接绑定到原生<textarea>,用户输入会自动触发update:modelValue事件,实现与props.modelValue的同步; - 受控/非受控双模式:当外部传入
modelValue时为受控模式;未传入时回退到defaultValue,成为非受控组件,与 React 生态中 defaultValue 的设计思路一致; - passive 优化:
passive: true表示组件不会在外部主动同步 props,而是依赖 Vue 的响应式系统,减少不必要的性能开销。
两套风格差异
对比 default 版 与 new-york 版 的类名,可以看到:
- default:
min-h-20(80px 最小高度)、bg-background(不透明背景)、focus-visible:ring-2(双层焦点环); - new-york:
min-h-[60px](60px 最小高度)、bg-transparent(透明背景)、focus-visible:ring-1(单层焦点环)并附带shadow-sm。
两套风格共享的基础样式包括flex w-full rounded-md border border-input px-3 py-2 text-sm placeholder:text-muted-foreground以及禁用态样式disabled:cursor-not-allowed disabled:opacity-50。选择哪套风格取决于你初始化项目时指定的样式选项,可在 shadcn-vue 初始化时配置。
示例详解
文档列出的六个示例在仓库中均有完整实现,以下逐一讲解。
默认示例(Default)
源码:TextareaDemo.vue
<script setup lang="ts"> import { Textarea } from "@/registry/default/ui/textarea" </script> <template> <Textarea placeholder="Type your message here." /> </template>最基础的用法,仅通过placeholder属性给出输入提示文案。
禁用态(Disabled)
源码:TextareaDisabled.vue
<template> <Textarea placeholder="Type your message here." disabled /> </template>通过原生disabled属性禁用输入。从源码类名disabled:cursor-not-allowed disabled:opacity-50可知,禁用态会自动呈现不可点击光标并降低 50% 透明度。
带标签(With Label)
源码:TextareaWithLabel.vue
<template> <div class="grid w-full gap-1.5"> <Label for="message">Your message</Label> <Textarea id="message" placeholder="Type your message here." /> </div> </template>配合 shadcn-vue 的 Label 组件使用。关键在于Label的for与Textarea的id必须一致,点击标签文本即可聚焦输入框,这也是无障碍(a11y)的最佳实践。
带说明文本(With Text)
源码:TextareaWithText.vue
<template> <div class="grid w-full gap-1.5"> <Label for="message-2">Your message</Label> <Textarea id="message-2" placeholder="Type your message here." /> <p class="text-sm text-muted-foreground"> Your message will be copied to the support team. </p> </div> </template>在标签与输入框下方追加一段辅助说明文字,使用text-sm text-muted-foreground样式呈现为弱化的次级文案,适合描述输入规则或用途。
带按钮(With Button)
源码:TextareaWithButton.vue
<template> <div class="grid w-full gap-2"> <Textarea placeholder="Type your message here." /> <Button>Send message</Button> </div> </template>典型的"输入 + 提交"组合布局,常用于消息发送、评论表单等场景。注意这里 Button 未显式设置type,在实际表单中如需提交应写为type="submit"。
表单集成(Form)
源码:TextareaForm.vue(new-york 风格同款见 TextareaForm.vue)
这是最完整的实战示例,演示了 Textarea 与vee-validate + zod的深度集成:
<script setup lang="ts"> import { toTypedSchema } from "@vee-validate/zod" import { useForm } from "vee-validate" import { h } from "vue" import * as z from "zod" import { Button } from "@/registry/default/ui/button" import { FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from "@/registry/default/ui/form" import { Textarea } from "@/registry/default/ui/textarea" import { toast } from "@/registry/default/ui/toast" const formSchema = toTypedSchema(z.object({ bio: z .string() .min(10, { message: "Bio must be at least 10 characters." }) .max(160, { message: "Bio must not be longer than 30 characters." }), })) const { handleSubmit } = useForm({ validationSchema: formSchema }) const onSubmit = handleSubmit((values) => { toast({ title: "You submitted the following values:", description: h("pre", { class: "mt-2 w-[340px] rounded-md bg-slate-950 p-4" }, h("code", { class: "text-white" }, JSON.stringify(values, null, 2))), }) }) </script> <template> <form class="w-full space-y-6" @submit="onSubmit"> <FormField v-slot="{ componentField }" name="bio"> <FormItem> <FormLabel>Bio</FormLabel> <FormControl> <Textarea placeholder="Tell us a little bit about yourself" class="resize-none" v-bind="componentField" /> </FormControl> <FormDescription> You can <span>@mention</span> other users and organizations. </FormDescription> <FormMessage /> </FormItem> </FormField> <Button type="submit"> Submit </Button> </form> </template>该示例的关键要点:
- zod schema 定义校验规则:
bio字段要求 10~160 个字符,toTypedSchema将 zod schema 转换为 vee-validate 的类型化 schema; v-bind="componentField"打通表单绑定:FormField提供的componentField包含了modelValue、onUpdate:modelValue等事件,通过v-bind一次性透传给 Textarea,无需手动编写绑定代码;resize-none禁用拖拽缩放:给class传入 Tailwind 类即可覆盖默认样式,体现了cn合并机制的灵活性;- 完整表单反馈:
FormDescription展示辅助说明,FormMessage自动渲染校验错误信息,toast展示提交结果。
整个流程清晰展示了 Textarea 在真实表单场景中的标准姿势:FormField负责取字段状态,FormControl包裹控件,componentField完成值绑定,错误信息由FormMessage自动呈现。
样式定制建议
Textarea 的默认样式通过cn()与props.class合并,因此自定义样式有两种途径:
- 直接传
class:如示例中的class="resize-none",追加的 Tailwind 类会覆盖同属性默认值(tailwind-merge保证后传入的类优先); - 修改组件源码:直接编辑 Textarea.vue 中的默认类名,例如调整最小高度
min-h-20、圆角rounded-md或焦点环样式。
若想全局统一调整 Textarea 风格,建议通过修改components/ui/textarea/Textarea.vue并配合设计系统的 CSS 变量(如--input、--ring、--background、--muted-foreground)实现主题联动。
小结
Textarea 组件虽然代码量不大,但集中体现了 shadcn-vue 的设计哲学:样式与逻辑分离、开箱即用的受控绑定、以及与表单体系的平滑集成。掌握本文内容后,你可以:
- 通过 CLI 或手动方式快速集成 Textarea 组件;
- 理解
modelValue/defaultValue/class三个核心属性及useVModel的底层绑定原理; - 灵活组合 Label、Button、Form 等组件搭建完整的多行文本输入场景;
- 使用 vee-validate + zod 为多行文本添加校验逻辑。
如需进一步了解相关组件,可继续阅读 input.md、form.md 与 label.md 等文档。
【免费下载链接】shadcn-vueVue port of shadcn-ui项目地址: https://gitcode.com/gh_mirrors/sh/shadcn-vue
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考