- 前端
- UI组件
- 移动开发
【免费下载链接】cube-ui
:large_orange_diamond: A fantastic mobile ui lib implement by Vue
导读
本文以 cube-ui(一个基于 Vue 构建的移动端 UI 组件库)中的Textarea多行输入框组件为主线,系统讲解其v-model双向绑定、基于"有内容 / 聚焦"的折叠与展开状态机、indicator计数标识(含remain/negative子配置与具名作用域插槽)以及原生属性透传等能力。读完本文,你将掌握从基础用法到源码级实现原理的完整知识,并可直接在真实表单场景中复刻出可运行的配置代码。
本文对应文档位于 document/components/docs/zh-CN/textarea.md,组件源码位于 src/components/textarea/textarea.vue。
组件概述:多行输入框的折叠与展开
Textarea是 cube-ui 在1.5.0版本新增的多行输入框组件,组件名注册为cube-textarea(注册逻辑见 src/modules/textarea/index.js)。
与普通textarea不同,它内置了一套状态机:根据"是否有内容、是否聚焦"在两个视觉状态间切换——
- 折叠态:默认高度 40px,适合作为一行输入入口;
- 展开态:高度 80px,提供更大的书写区域。
组件通过cube-textarea_expanded与cube-textarea_active两个 class 控制外观,并在样式层使用transition: height 200ms实现平滑的高度过渡动画,相关样式定义见 textarea.vue 的 style 段。
从源码看,折叠 / 展开的核心逻辑集中在 textarea.vue 与 textarea.vue:
data() { return { textareaValue: this.value, // 初始状态:forceExpand 恒展开;autoExpand 且默认有内容则展开 expanded: this.forceExpand ? true : (this.autoExpand ? !!this.value : false), isFocus: false } }聚焦时强制展开(this.expanded = true);失焦时若内容为空则折叠回 40px。而forceExpand为true时组件始终保持展开,这个规则贯穿初始化和失焦两个入口。
基本用法:通过 v-model 双向绑定
cube-textarea使用v-model完成数据双向绑定,这也是文档给出的第一个示例:
<cube-textarea v-model="value"></cube-textarea>export default { data() { return { value: '' } } }底层实现中,组件维护内部状态textareaValue,并通过watch同时监听外部value与内部textareaValue(见 textarea.vue):
watch: { value(newValue) { this.textareaValue = newValue }, textareaValue(newValue) { this.$emit(EVENT_INPUT, newValue) // 触发 input 事件,完成 v-model 更新 // 非 forceExpand 且非聚焦状态下,若曾展开则自动折叠 if (!this.forceExpand && !this.isFocus && this.expanded) { this.expanded = false } } }由此可以看到两个细节:其一,外部数据变化会同步进内部输入框;其二,当程序化地清空输入内容(例如表单重置)且组件未聚焦时,组件会自动回到折叠态——这正呼应了"根据是否有内容决定折叠/展开"的设计。
此外,组件混入了 src/common/mixins/input.js,其中定义了focus()/blur()实例方法及changeHander(透传原生change事件),下方实例方法一节会详细展开。
配置计数标识:indicator 的三种形态
计数标识是Textarea最具特色的能力。文档要求:indicator的值可以是false、true或配置对象,分别对应三种行为:
false:完全不显示右下角的计数标识;true:等同于{ remain: true, negative: true },即显示"剩余可输入字数",且允许负值;- 对象:通过
remain与negative两个布尔字段精细控制。
基本配置示例:
<cube-textarea v-model="value" indicator="indicator"></cube-textarea>export default { data() { return { indicator: { negative: true, remain: true } } } }indicator 子配置项
| 参数 | 说明 | 类型 | 可选值 | 默认值 | | - | - | - | - | - | | remain | 是否显示剩余字数,为false时显示已输入字数 | Boolean | true/false | true | | negative | 当remain为 true 时有效,是否允许出现负值(即允许超出 maxlength 后显示负数) | Boolean | true/false | true |
从源码看,textarea.vue 用indicatorConf计算属性将用户配置与默认值合并,并用count/remain两个计算属性得出展示数值:
const DEFAULT_INDICATOR = { negative: true, remain: true } indicatorConf() { let indicator = this.indicator if (typeof indicator === 'boolean') { indicator = {} } return Object.assign({}, DEFAULT_INDICATOR, indicator) }, count() { return this.textareaValue.length }, remain() { let diff = this.maxlength - this.count if (!this.indicatorConf.negative && diff < 0) { diff = 0 // negative 为 false 时,超限一律显示 0 } return diff }值得注意的两点实现细节:
negative: false的真正含义是"超限后仍显示 0 而非负数"——这在表单必填校验场景下可以避免出现刺眼的负数字;- 默认计数标识文本由模板中的默认插槽内容渲染(见 textarea.vue),且仅在展开态(
v-show="expanded")下可见。
自定义计数标识:具名作用域插槽 indicator(1.12.53+)
从1.12.53开始,组件支持使用具名作用域插槽indicator完全自定义右下角计数标识。插槽提供两个作用域值:remain(剩余可输入字数)和count(当前已输入字数)。
<cube-textarea v-model="text" placeholder="请您至少输入8个字(必填)" :maxlength="300" :auto-expand="true" > <span slot="indicator" slot-scope="{ remain }" class="cube-textarea-indicator">{{remain}}/300</span> <!-- 或者 vue2.6以上 --> <!-- <template #indicator="childValue"> <span class="cube-textarea-indicator">{{childValue.remain}}/300</span> </template> --> </cube-textarea>插槽模板的实现位于 textarea.vue,它把remain/count通过作用域暴露出来,默认内容仅充当兜底:
<slot name="indicator" :remain="remain" :count="count"> <span v-if="indicator" v-show="expanded" class="cube-textarea-indicator">{{indicatorConf.remain ? remain : count}}</span> </slot>在 example/pages/textarea.vue 的官方示例中,还演示了force-expand+ 自定义插槽的组合用法,将计数渲染为{{remain}}/{{maxlength}}的"已用/总量"样式,这在移动端输入场景中非常常见。
多项配置:原生属性透传
组件通过v-bind="$props"将声明的 props 直接透传到原生<textarea>上(见 textarea.vue),因此placeholder、maxlength、readonly、disabled、autofocus等原生能力开箱即用:
<cube-textarea v-model="value" :placeholder="placeholder" :maxlength="maxlength" :readonly="readonly" :disabled="disabled" :autofocus="autofocus" ></cube-textarea>export default { data() { return { value: '', placeholder: '请输入内容', readonly: true, maxlength: 100, disabled: true, autofocus: true } } }该行为在 test/unit/specs/textarea.spec.js 中有对应测试用例,断言透传后原生textarea的disabled、readOnly、autofocus属性均为true,可作为配置生效的直接证据。
Props 配置总览
| 参数 | 说明 | 类型 | 可选值 | 默认值 | | - | - | - | - | - | | v-model | 绑定的值 | String | - | 空 | | disabled | 禁用状态 | Boolean | true/false | false | | readonly | 只读状态 | Boolean | true/false | false | | maxlength | 最大输入长度 | Number | - | 60 | | placeholder | 占位文本 | String | - | 空 | | autofocus | 自动对焦 | Boolean | true/false | false | | indicator1.10.0| 计数标识配置 | Boolean/Object | true/false/{} | true | | autoExpand1.12.0| 为 true 且默认有内容时,默认展开 | Boolean | true/false | false | | forceExpand1.12.53| 为 true 时始终保持展开 | Boolean | true/false | false |
补充几点从源码确认的细节:
- 组件还额外声明了
cols、rows、wrap、required、dirname、form、name等原生属性(见 textarea.vue),这些同样会通过$props透传到原生元素上,类型声明见 types/components/Textarea.d.ts; autoExpand的生效前提是"默认有内容":初始展开条件为autoExpand ? !!this.value : false,即只有初始value非空时才展开;forceExpand优先级最高:一旦为true,无论内容多少、是否聚焦,组件始终处于 80px 展开态,watch与blur中的折叠分支都会被跳过。
插槽
| 名称 | 说明 | | - | - | | indicator1.12.53| 自定义右下角计数标识,作用域参数为remain(剩余字数)与count(已输入字数) |
事件
| 事件名 | 说明 | 参数 | | - | - | - | | focus | 输入框聚焦后触发;禁用状态下不触发 | e - 事件对象 | | blur | 输入框失焦后触发 | e - 事件对象 | | input | 绑定值变化时触发 | 更新后的绑定值 |
focus/blur的触发逻辑见 textarea.vue,input事件在textareaValue变化时通过$emit('input', newValue)抛出,这正是v-model得以工作的基石。此外,组件还会透传原生change事件(由 src/common/mixins/input.js 中的changeHander抛出)。
实例方法
| 方法名 | 说明 | | - | - | | focus1.12.10+| 获得焦点 | | blur1.12.10+| 离焦 |
这两个方法定义在 src/common/mixins/input.js,实现非常直接,通过$refs.input调用原生focus()/blur():
focus() { this.$refs.input.focus() }, blur() { this.$refs.input.blur() }使用方式:this.$refs.textarea.focus()(需给<cube-textarea ref="textarea">设置 ref)。
源码级深入:样式主题与测试验证
主题变量:一键换肤的样式基础
Textarea的视觉样式全部通过 Stylus 主题变量驱动(定义见 src/common/stylus/theme/default.styl):
//textarea $textarea-color := $color-grey $textarea-bgc := $color-white $textarea-border-color := $color-row-line $textarea-focus-border-color := $color-orange $textarea-outline-color := $color-orange $textarea-placeholder-color := $color-light-grey-s $textarea-indicator-color := $color-light-grey-s其中聚焦边框色$textarea-focus-border-color与组件聚焦态 classcube-textarea_active对应,展开态的 80px 高度由 textarea.vue 中的.cube-textarea_expanded定义,折叠态 40px 为默认高度。这意味着在定制主题时,只需替换主题变量即可整体改变输入框外观。
测试用例:行为契约的实证
仓库在 test/unit/specs/textarea.spec.js 中为Textarea建立了完整的行为契约,可直接用于验证本文前述结论:
- 折叠/展开高度:失焦后高度保持 40px;聚焦后高度变为 80px,清空内容再失焦则恢复 40px(
should not expand when blur、should expand when focus, fold when blur); - 计数展示:maxlength=60 时聚焦显示剩余
56,输入 61 个字符后显示0,将indicator.negative设为false时超限仍显示0(should has remain when focus); - remain=false 显示输入字数:
remain: false时计数显示已输入字符数4(should change value); - 原生属性透传:
autofocus/readonly/disabled均正确落到原生元素(should support more native props); - autoExpand:初始有内容且
autoExpand: true时挂载即带cube-textarea_expandedclass(should expand when autoExpand)。
这些用例既是组件稳定性的保障,也是读者理解各配置项实际效果的最快途径。
实战建议:组合配置要点
结合文档与示例页(example/pages/textarea.vue),给出几个高频组合场景:
- 必填长文本 + 剩余字数提示:
auto-expand保证有初值时展开,:maxlength限制长度,默认indicator即可显示剩余字数; - 超出限制也不显示负数:配置
:indicator="{ remain: true, negative: false }",超限时计数固定显示 0; - 自定义"已用/总量"计数:
1.12.53+使用slot="indicator"配合作用域remain渲染{{remain}}/{{maxlength}},同时可令indicator为false隐藏默认计数; - 始终展开的固定区域:
force-expand适用于评论区这类固定高度的场景,避免折叠/展开跳动影响布局。
组件完整能力以源码为准,使用时请确认你的 cube-ui 版本不低于对应能力标注的版本号(例如插槽与forceExpand需 1.12.53+、focus/blur方法需 1.12.10+、autoExpand需 1.12.0+、indicator配置需 1.10.0+)。
- 前端
- UI组件
- 移动开发
【免费下载链接】cube-ui
:large_orange_diamond: A fantastic mobile ui lib implement by Vue
相关推荐
CANN/xla-npu GatherV2Op实现总结
GatherV2Op 实现总结 完成的工作 1. 在 mair_ops.td 中添加 GatherV2Op 定义 文件 : mair_ops.td https:
前端UI组件移动开发终极指南:如何利用LLaMA2-Accessory实现符号推理与神经网络的完美融合
终极指南:如何利用LLaMA2 Accessory实现符号推理与神经网络的完美融合 LLaMA2 Accessory是一个强大的开源LLM开发工具包,它提供了将
前端UI组件移动开发Voyager 输入框折叠(Input Collapse)功能详解:空输入框自动折叠,为阅读让出更多空间
Voyager 输入框折叠(Input Collapse)功能详解:空输入框自动折叠,为阅读让出更多空间 导读 输入框折叠(Input Collapse)是 V
AI 应用前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考