diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts
index 57fc6df6..ceb67980 100644
--- a/docs/.vitepress/config.ts
+++ b/docs/.vitepress/config.ts
@@ -1,7 +1,7 @@
/*
* @Author: weisheng
* @Date: 2023-07-27 10:26:09
- * @LastEditTime: 2023-12-07 15:08:32
+ * @LastEditTime: 2023-12-21 22:27:02
* @LastEditors: weisheng
* @Description:
* @FilePath: \wot-design-uni\docs\.vitepress\config.ts
@@ -231,10 +231,13 @@ export default defineConfig({
text: "DatetimePickerView 时间选择器视图"
}, {
link: "/component/form",
- text: "Form 表单组合"
+ text: "Form 表单"
}, {
link: "/component/input",
text: "Input 输入框"
+ }, {
+ link: "/component/textarea",
+ text: "Textarea 文本域"
}, {
link: "/component/input-number",
text: "InputNumber 计数器"
diff --git a/docs/component/calendar.md b/docs/component/calendar.md
index d1b15b49..22c6b1e1 100644
--- a/docs/component/calendar.md
+++ b/docs/component/calendar.md
@@ -397,6 +397,17 @@ function handleConfirm4({ value }) {
| close-on-click-modal | 点击遮罩是否关闭 | boolean | - | true | - |
| z-index | 弹窗层级 | number | - | 15 | - |
| safe-area-inset-bottom | 弹出面板是否设置底部安全距离(iphone X 类型的机型) | boolean | - | true | - |
+| prop | 表单域 `model` 字段名,在使用表单校验功能的情况下,该属性是必填的 | string | - | - | - |
+| rules | 表单验证规则 | `FormItemRule []` | - | `[]` | - |
+
+### FormItemRule 数据结构
+
+| 键名 | 说明 | 类型 |
+| --- | --- | --- |
+| required | 是否为必选字段 | `boolean` |
+| message | 错误提示文案 | `string` |
+| validator | 通过函数进行校验,可以返回一个 `Promise` 来进行异步校验 | `(value, rule) => boolean \| Promise` |
+| pattern | 通过正则表达式进行校验,正则无法匹配表示校验不通过 | `RegExp` |
## Events
diff --git a/docs/component/cell.md b/docs/component/cell.md
index a44bbb01..ab1c2d51 100644
--- a/docs/component/cell.md
+++ b/docs/component/cell.md
@@ -35,10 +35,10 @@
```scss
.cell-icon {
display: block;
+ box-sizing: border-box;
width: 16px;
height: 16px;
- margin-top: 2px;
- margin-right: 15px;
+ margin-right: 4px;
background: url('https://img10.360buyimg.com/jmadvertisement/jfs/t1/71075/7/3762/1820/5d1f26d1E0d600b9e/a264c901943080ac.png') no-repeat;
background-size: cover;
}
@@ -198,10 +198,11 @@ function handleSwitchChange({ value }) {
```scss
.cell-icon {
display: block;
+ box-sizing: border-box;
+ padding: 4px 0;
width: 16px;
- height: 16px;
- margin-top: 2px;
- margin-right: 15px;
+ height: 24px;
+ margin-right: 4px;
background: url('https://img10.360buyimg.com/jmadvertisement/jfs/t1/71075/7/3762/1820/5d1f26d1E0d600b9e/a264c901943080ac.png') no-repeat;
background-size: cover;
}
@@ -251,6 +252,18 @@ function handleSwitchChange({ value }) {
| center | 是否垂直居中,默认顶部居中 | boolean | - | false | - |
| required | 表单属性,必填 | boolean | - | false | - |
| vertical | 表单属性,上下结构 | boolean | - | false | - |
+| prop | 表单域 `model` 字段名,在使用表单校验功能的情况下,该属性是必填的 | string | - | - | - |
+| rules | 表单验证规则 | `FormItemRule []` | - | `[]` | - |
+
+### FormItemRule 数据结构
+
+| 键名 | 说明 | 类型 |
+| --- | --- | --- |
+| required | 是否为必选字段 | `boolean` |
+| message | 错误提示文案 | `string` |
+| validator | 通过函数进行校验,可以返回一个 `Promise` 来进行异步校验 | `(value, rule) => boolean \| Promise` |
+| pattern | 通过正则表达式进行校验,正则无法匹配表示校验不通过 | `RegExp` |
+
## Cell Events
diff --git a/docs/component/col-picker.md b/docs/component/col-picker.md
index 2441f62f..2b39ed2c 100644
--- a/docs/component/col-picker.md
+++ b/docs/component/col-picker.md
@@ -525,6 +525,17 @@ const columnChange = ({ selectedItem, resolve, finish }) => {
| z-index | 弹窗层级 | number | - | 15 | - |
| safe-area-inset-bottom | 弹出面板是否设置底部安全距离(iphone X 类型的机型) | boolean | - | true | - |
| ellipsis | 是否超出隐藏 | boolean | - | false | - |
+| prop | 表单域 `model` 字段名,在使用表单校验功能的情况下,该属性是必填的 | string | - | - | - |
+| rules | 表单验证规则 | `FormItemRule []` | - | `[]` | - |
+
+### FormItemRule 数据结构
+
+| 键名 | 说明 | 类型 |
+| --- | --- | --- |
+| required | 是否为必选字段 | `boolean` |
+| message | 错误提示文案 | `string` |
+| validator | 通过函数进行校验,可以返回一个 `Promise` 来进行异步校验 | `(value, rule) => boolean \| Promise` |
+| pattern | 通过正则表达式进行校验,正则无法匹配表示校验不通过 | `RegExp` |
## 选项数据结构
diff --git a/docs/component/datetime-picker.md b/docs/component/datetime-picker.md
index baef9bb0..6970e6bf 100644
--- a/docs/component/datetime-picker.md
+++ b/docs/component/datetime-picker.md
@@ -284,6 +284,17 @@ const displayFormatTabLabel = (items) => {
| z-index | 弹窗层级 | number | - | 15 | - |
| safe-area-inset-bottom | 弹出面板是否设置底部安全距离(iphone X 类型的机型) | boolean | - | true | - |
| ellipsis | 是否超出隐藏 | boolean | - | false | - |
+| prop | 表单域 `model` 字段名,在使用表单校验功能的情况下,该属性是必填的 | string | - | - | - |
+| rules | 表单验证规则 | `FormItemRule []` | - | `[]` | - |
+
+### FormItemRule 数据结构
+
+| 键名 | 说明 | 类型 |
+| --- | --- | --- |
+| required | 是否为必选字段 | `boolean` |
+| message | 错误提示文案 | `string` |
+| validator | 通过函数进行校验,可以返回一个 `Promise` 来进行异步校验 | `(value, rule) => boolean \| Promise` |
+| pattern | 通过正则表达式进行校验,正则无法匹配表示校验不通过 | `RegExp` |
## Events
diff --git a/docs/component/form.md b/docs/component/form.md
index 4807b417..19674651 100644
--- a/docs/component/form.md
+++ b/docs/component/form.md
@@ -1,141 +1,727 @@
-# Form 表单组合
+# Form 表单 0.2.0
-本章节主要讲如何将多个 form 表单组件进行组合,形成一个完整的表单页面。
+用于数据录入、校验,支持输入框、单选框、复选框、文件上传等类型,常见的 form 表单为`单元格`形式的展示,即左侧为表单的标题描述,右侧为表单的输入。
-常见的 form 表单为`单元格`形式的展示,即左侧为表单的标题描述,右侧为表单的输入。
+其中,`Input 输入框`、`Textarea 输入框`、`Picker 选择器`、 `Calendar 日历选择器`、 `ColPicker 多列选择器`、`SelectPicker 单复选选择器`、`Cell 单元格` 和 `DatetimePicker 日期时间选择器`具有`单元格`的展示形式,同时也支持 `prop` 和 `rules` 属性,我们称之为`表单项组件`,而 `InputNumber 计数器` 、 `Switch 开关` 和 `Upload 上传` 等组件则需要使用 `Cell 单元格` 进行包裹使用。
-其中,`Input 输入框`、`Picker 选择器`、 `Calendar 日历选择器`, `ColPicker 多列选择器`、`SelectPicker 单复选选择器` 和 `DatetimePicker 日期时间选择器`具有`单元格`的展示形式,而 `InputNumber 计数器`和 `Switch 开关`需要使用 `Cell 单元格`进行包裹使用。
+结合 `wd-form` 组件,可以实现对以上组件的规则校验。
-所有的表单组件都支持 `name` 属性,可以结合小程序原生的 `form` 组件,监听 `submit` 事件,统一获取到所有表单组件的 `value`,也可以单独对每个表单组件监听 `change` 事件来获取单个表单组件的 `value`。
+> 对于表单组件,建议对 wd-cell-group 开启 border 属性,这样每条 cell 就会有边框线隔离开,这样表单的划分比较清晰。
-> 对于表单组件,建议对 wd-cell-group 开启 border 属性,这样每条cell就会有边框线隔离开,这样表单的划分比较清晰。
+## 基础用法
-下面是 Demo 示例:
+在表单中,使用 `model` 指定表单数据对象,每个 `表单项组件` 代表一个表单项,使用 `prop` 指定表单项字段 ,使用 `rules` 属性定义校验规则。
-html 文件代码:
+::: details 查看基础用法示例
+::: code-group
-```html
+```html [vue]
+
+
+
+
+
+
+
+```
+
+```typescript [typescript]
+
+```
+
+```css [css]
+.footer {
+ padding: 12px;
+}
+```
+
+:::
+
+## 校验规则
+
+本章节演示四种自定义校验及提示规则:`正则校验`、`函数校验`、`函数返回错误提示`和`异步函数校验`。
+
+::: details 查看校验规则示例
+::: code-group
+
+```html [vue]
+
+
+
+
+
+
+
+
+
+```
+
+```typescript [typescript]
+
+```
+
+```css [css]
+.footer {
+ padding: 12px;
+}
+```
+
+:::
+
+## 动态表单
+
+表单项动态增减。
+
+::: details 查看动态表单示例
+::: code-group
+
+```html [vue]
+
+
+
+
+
+
+
+
+
+
+```
+
+```typescript [typescript]
+
+```
+
+```css [css]
+.footer {
+ text-align: left;
+ :deep(.wd-button) {
+ &:not(:last-child) {
+ margin-right: 12px;
+ }
+ }
+}
+```
+
+:::
+
+## 指定字段校验
+
+`validate` 方法可以传入一个 `prop` 参数,指定校验的字段,可以实现在表单组件的`blur`、`change`等事件触发时对该字段的校验。
+
+::: details 查看指定字段校验示例
+::: code-group
+
+```html [vue]
+
+
+
+
+
+
+
+
+```
+
+```typescript [typescript]
+
+```
+
+```css [css]
+.footer {
+ padding: 12px;
+}
+```
+
+:::
+
+## 复杂表单
+
+结合`Input 输入框`、`Textarea 输入框`、`Picker 选择器`、 `Calendar 日历选择器`、 `ColPicker 多列选择器`、`SelectPicker 单复选选择器`、`Cell 单元格` 和 `DatetimePicker 日期时间选择器`实现一个复杂表单。
+
+::: details 查看复杂表单示例
+::: code-group
+
+```html [vue]
+
-
+
+
```
-> 自定义按钮组件的 form-type 无法触发小程序官方form组件的submit事件,微信要求小程序基础库 2.10.3 才支持,京东小程序的则暂时不支持,因此需要用小程序自带的官方 button 组件,样式上可以引入 wot-design 中 button 的样式文件,使用 `wd-button` , `is-primary` , `is-suck` , `is-block`, `is-plain` , `is-disabled` 等类名进行组合使用来展示 wot-design 组件库的按钮样式。
-
-index.js 文件代码:
-
-```typescript
-import { useMessage } from '@/uni_modules/wot-design-uni/components/wd-message-box'
+```typescript [typescript]
+
```
-css 文件代码:
-
-```scss
+```css [css]
.inline-txt {
display: inline-block;
font-size: 14px;
@@ -292,3 +834,34 @@ css 文件代码:
font-size: 12px !important;
}
```
+
+:::
+
+## Attributes
+
+| 参数 | 说明 | 类型 | 可选值 | 默认值 | 最低版本 |
+| ----- | ------------ | --------------------- | ------ | ------ | -------- |
+| model | 表单数据对象 | `Record` | - | - | 0.2.0 |
+| rules | 表单验证规则 | `FormRules` | - | - | 0.2.0 |
+
+### FormItemRule 数据结构
+
+| 键名 | 说明 | 类型 |
+| --------- | ------------------------------------------------------- | ------------------------------------- |
+| required | 是否为必选字段 | `boolean` |
+| message | 错误提示文案 | `string` |
+| validator | 通过函数进行校验,可以返回一个 `Promise` 来进行异步校验 | `(value, rule) => boolean \| Promise` |
+| pattern | 通过正则表达式进行校验,正则无法匹配表示校验不通过 | `RegExp` |
+
+## Events
+
+| 事件名称 | 说明 | 参数 | 最低版本 |
+| -------- | ------------------------------------------------------------------------------ | --------------- | -------- |
+| validate | 验证表单,支持传入一个 prop 来验证单个表单项,不传入 prop 时,会验证所有表单项 | `prop?: string` | 0.2.0 |
+| reset | 重置校验结果 | - | 0.2.0 |
+
+## 外部样式类
+
+| 类名 | 说明 | 最低版本 |
+| ------------ | ---------- | -------- |
+| custom-class | 根节点样式 | 0.2.0 |
diff --git a/docs/component/input.md b/docs/component/input.md
index 5a1d3957..8b6b9188 100644
--- a/docs/component/input.md
+++ b/docs/component/input.md
@@ -69,36 +69,6 @@ function handleChange(event) {
```
-## 文本域
-
-设置 `type` 为 'textarea`。
-
-:::warning
-当 `wd-input` 的 `type` 为 'textarea' ,并嵌入 `wd-message-box`、`wd-popup`、`wd-action-sheet` 这类弹层组件时,textarea 的 placeholder 样式会失效,需要手动给 `wd-message-box`、`wd-popup`、`wd-action-sheet` 组件设置 `:lazy-render="false"` 属性,textarea 原生组件在这块实现有些问题,对于页面非立即渲染的 textarea 无法成功设置 placeholder 样式
-:::
-
-```html
-
-```
-
-设置清空,字数限制。
-
-```html
-
-```
-也可以设置`auto-height`使高度自增加。
-
-```html
-
-```
-
## 设置label标题
设置 `label` 标题,可以和 `cell-group` 组合使用,形成 `cell` 展示类型。可以通过 `label-width` 设置标题宽度,默认为 '33%'。
@@ -143,7 +113,7 @@ function handleChange(event) {
| 参数 | 说明 | 类型 | 可选值 | 默认值 | 最低版本 |
|-----|------|-----|-------|-------|---------|
-| type | 类型 | string | text / textarea / number / digit / idcard | text | - |
+| type | 类型 | string | text / number / digit / idcard | text | - |
| v-model | 绑定值 | string / number | - | - | - |
| placeholder | 占位文本 | string | - | 请输入... | - |
| clearable | 显示清空按钮 | boolean | - | false | - |
@@ -157,17 +127,14 @@ function handleChange(event) {
| confirm-type | 设置键盘右下角按钮的文字,仅在type='text'时生效 | string | done / go / next / search / send | done | - |
| confirm-hold | 点击键盘右下角按钮时是否保持键盘不收起 | Boolean | - | false | - |
| always-embed | 微信小程序原生属性,强制 input 处于同层状态,默认 focus 时 input 会切到非同层状态 (仅在 iOS 下生效) | Boolean | - | false | - |
-| placeholderStyle | 原生属,指定 placeholder 的样式,目前仅支持color,font-size和font-weight | string | - | - | - |
-| placeholderClass | textarea指定 placeholder 的样式类 | string | - | textarea-placeholder | - |
+| placeholderStyle | 原生属性,指定 placeholder 的样式,目前仅支持color,font-size和font-weight | string | - | - | - |
+| placeholderClass | 原生属性,指定 placeholder 的样式类 | string | - | - | - |
| focus | 原生属性,获取焦点 | boolean | - | false | - |
-| cursorSpacing | 原生属性,指定光标与键盘的距离。取textarea距离底部的距离和cursor-spacing指定的距离的最小值作为光标与键盘的距离 | number | - | 0 | - |
-| fixed | textarea原生属性,如果 textarea 是在一个 position:fixed 的区域,需要显示指定属性 fixed 为 true | boolean | - | false | - |
+| cursorSpacing | 原生属性,指定光标与键盘的距离。取 input 距离底部的距离和cursor-spacing指定的距离的最小值作为光标与键盘的距离 | number | - | 0 | - |
| cursor | 原生属性,指定focus时的光标位置 | number | - | -1 | - |
-| showConfirmBar | 原生属性,是否显示键盘上方带有”完成“按钮那一栏 | boolean | - | true | - |
| selectionStart | 原生属性,光标起始位置,自动聚集时有效,需与selection-end搭配使用 | number | - | -1 | - |
| selectionEnd | 原生属性,光标结束位置,自动聚集时有效,需与selection-start搭配使用 | number | - | -1 | - |
| adjustPosition | 原生属性,键盘弹起时,是否自动上推页面 | boolean | - | true | - |
-| autoHeight | textarea原生属性,textarea 行数自适应,从1行开始显示 | boolean | - | false | - |
| label | 设置左侧标题 | string | - | - | - |
| size | 设置输入框大小 | string | - | - | - |
| error | 设置输入框错误状态,错误状态时为红色 | boolean | - | false | - |
@@ -177,8 +144,20 @@ function handleChange(event) {
| use-suffix-slot | 使用 后置图标 插槽 | boolean | - | false | - |
| use-prefix-slot | 使用 前置图标 插槽 | boolean | - | false | - |
| required | cell 类型下必填样式 | boolean | - | false | - |
-| name | form 表单中的字段名 | string | - | - | - |
| no-border | 非 cell 类型下是否隐藏下划线 | boolean | - | false | - | - |
+| prop | 表单域 `model` 字段名,在使用表单校验功能的情况下,该属性是必填的 | string | - | - | - |
+| rules | 表单验证规则 | `FormItemRule []` | - | `[]` | - |
+
+
+### FormItemRule 数据结构
+
+| 键名 | 说明 | 类型 |
+| --- | --- | --- |
+| required | 是否为必选字段 | `boolean` |
+| message | 错误提示文案 | `string` |
+| validator | 通过函数进行校验,可以返回一个 `Promise` 来进行异步校验 | `(value, rule) => boolean \| Promise` |
+| pattern | 通过正则表达式进行校验,正则无法匹配表示校验不通过 | `RegExp` |
+
## Events
@@ -186,10 +165,9 @@ function handleChange(event) {
|---------|-----|-----|---------|
| input | 监听输入框input事件 | ` {value, cursor, keyCode}` | - |
| focus | 监听输入框focus事件 | ` { value, height }`, height 为键盘高度 | - |
-| blur | 监听输入框blur事件 | ` { value, cursor }`,仅在type="textarea"时存在cursor | - |
+| blur | 监听输入框blur事件 | ` { value }` | - |
| change | 监听输入框修改事件 | ` { value }` | - |
| clear | 监听输入框清空按钮事件 | - | - |
-| linechange | 监听输入框行数变化(仅限textarea) | ` { height: 0, heightRpx: 0, lineCount: 0 }` | - |
| confirm | 点击完成时, 触发 confirm 事件 | ` { value }` | - |
| keyboardheightchange | 键盘高度发生变化的时候触发此事件 | ` { height, duration }` | - |
| clickprefixicon | 点击前置图标时触发 | - | - |
@@ -211,7 +189,5 @@ function handleChange(event) {
| 类名 | 说明 | 最低版本 |
|-----|------|--------|
| custom-class | 根节点样式 | - |
-| custom-textarea-container-class | textarea 容器外部自定义样式 | - |
-| custom-textarea-class | textarea 外部自定义样式 | - |
| custom-input-class | input 外部自定义样式 | - |
| custom-label-class | label 外部自定义样式 | - |
\ No newline at end of file
diff --git a/docs/component/picker.md b/docs/component/picker.md
index 90db0602..994e099e 100644
--- a/docs/component/picker.md
+++ b/docs/component/picker.md
@@ -261,6 +261,17 @@ function handleConfirm({ value }) {
| z-index | 弹窗层级 | number | - | 15 | - |
| safe-area-inset-bottom | 弹出面板是否设置底部安全距离(iphone X 类型的机型) | boolean | - | true | - |
| ellipsis | 是否超出隐藏 | boolean | - | false | - |
+| prop | 表单域 `model` 字段名,在使用表单校验功能的情况下,该属性是必填的 | string | - | - | - |
+| rules | 表单验证规则 | `FormItemRule []` | - | `[]` | - |
+
+### FormItemRule 数据结构
+
+| 键名 | 说明 | 类型 |
+| --- | --- | --- |
+| required | 是否为必选字段 | `boolean` |
+| message | 错误提示文案 | `string` |
+| validator | 通过函数进行校验,可以返回一个 `Promise` 来进行异步校验 | `(value, rule) => boolean \| Promise` |
+| pattern | 通过正则表达式进行校验,正则无法匹配表示校验不通过 | `RegExp` |
## Events
diff --git a/docs/component/select-picker.md b/docs/component/select-picker.md
index f0b379dd..7d0602f0 100644
--- a/docs/component/select-picker.md
+++ b/docs/component/select-picker.md
@@ -342,6 +342,17 @@ function handleConfirm({ value, selectedItems }) {
| filter-placeholder | 搜索框占位符 | string | - | 搜索 | - |
| ellipsis | 是否超出隐藏 | boolean | - | false | - |
| scroll-into-view | 重新打开是否滚动到选中项 | boolean | - | true | 0.1.34 |
+| prop | 表单域 `model` 字段名,在使用表单校验功能的情况下,该属性是必填的 | string | - | - | - |
+| rules | 表单验证规则 | `FormItemRule []` | - | `[]` | - |
+
+### FormItemRule 数据结构
+
+| 键名 | 说明 | 类型 |
+| --- | --- | --- |
+| required | 是否为必选字段 | `boolean` |
+| message | 错误提示文案 | `string` |
+| validator | 通过函数进行校验,可以返回一个 `Promise` 来进行异步校验 | `(value, rule) => boolean \| Promise` |
+| pattern | 通过正则表达式进行校验,正则无法匹配表示校验不通过 | `RegExp` |
## 选项数据结构
diff --git a/src/components/page-wraper/page-wraper.vue b/src/components/page-wraper/page-wraper.vue
index 2fcba85c..fb2f8965 100644
--- a/src/components/page-wraper/page-wraper.vue
+++ b/src/components/page-wraper/page-wraper.vue
@@ -1,14 +1,6 @@
-
+
diff --git a/src/pages.json b/src/pages.json
index f40dba8e..9e8441a0 100644
--- a/src/pages.json
+++ b/src/pages.json
@@ -160,6 +160,16 @@
"navigationBarTitleText": "Input 输入框"
}
},
+ {
+ "path": "pages/textarea/Index",
+ "name": "textarea",
+ "style": {
+ "mp-alipay": {
+ "allowsBounceVertical": "NO"
+ },
+ "navigationBarTitleText": "Textarea 文本域"
+ }
+ },
{
"path": "pages/messageBox/Index",
"name": "messageBox",
@@ -528,7 +538,37 @@
"mp-alipay": {
"allowsBounceVertical": "NO"
},
- "navigationBarTitleText": "Form 表单组合"
+ "navigationBarTitleText": "Form 表单"
+ }
+ },
+ {
+ "path": "pages/form/demo1",
+ "name": "formDemo1",
+ "style": {
+ "mp-alipay": {
+ "allowsBounceVertical": "NO"
+ },
+ "navigationBarTitleText": "复杂表单"
+ }
+ },
+ {
+ "path": "pages/form/demo2",
+ "name": "formDemo2",
+ "style": {
+ "mp-alipay": {
+ "allowsBounceVertical": "NO"
+ },
+ "navigationBarTitleText": "失焦校验"
+ }
+ },
+ {
+ "path": "pages/form/demo3",
+ "name": "formDemo3",
+ "style": {
+ "mp-alipay": {
+ "allowsBounceVertical": "NO"
+ },
+ "navigationBarTitleText": "复杂表单"
}
},
{
diff --git a/src/pages/cell/Index.vue b/src/pages/cell/Index.vue
index b9592a0c..f2c2ea7d 100644
--- a/src/pages/cell/Index.vue
+++ b/src/pages/cell/Index.vue
@@ -128,10 +128,10 @@ function showToast() {
diff --git a/src/pages/form/demo1.vue b/src/pages/form/demo1.vue
new file mode 100644
index 00000000..4b4a3d93
--- /dev/null
+++ b/src/pages/form/demo1.vue
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/form/demo2.vue b/src/pages/form/demo2.vue
new file mode 100644
index 00000000..288d562b
--- /dev/null
+++ b/src/pages/form/demo2.vue
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/form/demo3.vue b/src/pages/form/demo3.vue
new file mode 100644
index 00000000..b6030a31
--- /dev/null
+++ b/src/pages/form/demo3.vue
@@ -0,0 +1,426 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ 满
+
+ 减
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 已阅读并同意
+ 《借款额度合同及相关授权》
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/index/Index.vue b/src/pages/index/Index.vue
index 3442a716..8ee8a4f5 100644
--- a/src/pages/index/Index.vue
+++ b/src/pages/index/Index.vue
@@ -151,6 +151,10 @@ const list = ref([
id: 'input',
name: 'Input 输入框'
},
+ {
+ id: 'textarea',
+ name: 'Textarea 文本域'
+ },
{
id: 'inputNumber',
name: 'InputNumber 计数器'
@@ -189,7 +193,7 @@ const list = ref([
},
{
id: 'form',
- name: 'Form 表单组件组合'
+ name: 'Form 表单'
},
{
id: 'upload',
diff --git a/src/pages/input/Index.vue b/src/pages/input/Index.vue
index fe9c04ab..1cb07714 100644
--- a/src/pages/input/Index.vue
+++ b/src/pages/input/Index.vue
@@ -16,7 +16,7 @@
-
+
@@ -26,16 +26,7 @@
- 元
-
-
-
-
-
-
-
-
-
+ 元
@@ -45,12 +36,12 @@
-
+
获取验证码
-
+
@@ -101,6 +92,12 @@ function handleBlur(event) {
color: $-dark-color;
}
}
+.custom-txt {
+ display: inline-block;
+ vertical-align: middle;
+ font-size: 14px;
+ line-height: 24px;
+}
.flex {
display: flex;
justify-content: space-between;
diff --git a/src/pages/tabs/Index.vue b/src/pages/tabs/Index.vue
index af69d6da..8b2aa16b 100644
--- a/src/pages/tabs/Index.vue
+++ b/src/pages/tabs/Index.vue
@@ -1,6 +1,18 @@
+
+
+
+
+
+ 内容{{ tab1 + 1 }}
+ 下一个
+
+
+
+
+
@@ -129,4 +141,8 @@ function handleChange(event) {
line-height: 320px;
text-align: center;
}
+.main {
+ :deep(.wd-tabs) {
+ }
+}
diff --git a/src/uni_modules/wot-design-uni/components/wd-calendar/index.scss b/src/uni_modules/wot-design-uni/components/wd-calendar/index.scss
index d6ebece8..4c1ab101 100644
--- a/src/uni_modules/wot-design-uni/components/wd-calendar/index.scss
+++ b/src/uni_modules/wot-design-uni/components/wd-calendar/index.scss
@@ -52,13 +52,14 @@
@include e(cell) {
position: relative;
display: flex;
- padding: 0 $-cell-padding;
+ padding: $-cell-wrapper-padding $-cell-padding;
+ align-items: flex-start;
background-color: $-color-white;
text-decoration: none;
color: $-cell-title-color;
font-size: $-cell-title-fs;
overflow: hidden;
- line-height: $-cell-ling-height;
+ line-height: $-cell-line-height;
}
@include e(cell) {
@@ -101,11 +102,19 @@
}
}
+ @include e(error-message){
+ color: $-form-item-error-message-color;
+ font-size: $-form-item-error-message-font-size;
+ line-height: $-form-item-error-message-line-height;
+ text-align: left;
+ vertical-align: middle;
+ }
+
@include e(label) {
position: relative;
width: $-input-cell-label-width;
- padding: $-cell-wrapper-padding 0;
margin-right: $-cell-padding;
+ color: $-cell-title-color;
box-sizing: border-box;
@include when(required) {
@@ -114,7 +123,7 @@
&::after {
position: absolute;
left: 0;
- top: calc($-cell-wrapper-padding + 2px);
+ top: 2px;
content: '*';
font-size: $-cell-required-size;
line-height: 1.1;
@@ -123,12 +132,14 @@
}
}
+ @include e(value-wraper) {
+ display: flex;
+ }
+
@include e(value) {
flex: 1;
- padding: $-cell-wrapper-padding 0;
margin-right: 10px;
color: $-cell-value-color;
- white-space: pre-wrap;
@include when(ellipsis) {
@include lineEllipsis;
@@ -139,12 +150,15 @@
}
}
+ @include e(body) {
+ flex: 1;
+ }
+
@include edeep(arrow) {
display: block;
- margin-top: $-cell-wrapper-padding;
font-size: $-cell-icon-size;
color: $-cell-arrow-color;
- line-height: 1.25;
+ line-height: $-cell-line-height;
}
@include e(header) {
diff --git a/src/uni_modules/wot-design-uni/components/wd-calendar/wd-calendar.vue b/src/uni_modules/wot-design-uni/components/wd-calendar/wd-calendar.vue
index 834a8f75..c3414f13 100644
--- a/src/uni_modules/wot-design-uni/components/wd-calendar/wd-calendar.vue
+++ b/src/uni_modules/wot-design-uni/components/wd-calendar/wd-calendar.vue
@@ -10,18 +10,23 @@
>
{{ label }}
-
- {{ showValue || placeholder || '请选择' }}
+
+
+
+ {{ showValue || placeholder || '请选择' }}
+
+
+
+ {{ errorMessage }}
-
import { ref, computed, watch } from 'vue'
import { dayjs } from '../common/dayjs'
-import { debounce, deepClone, isArray, isEqual, padZero } from '../common/util'
+import { deepClone, isArray, isEqual, padZero } from '../common/util'
import { getWeekNumber, isRange } from '../wd-calendar-view/utils'
import { useCell } from '../composables/useCell'
+import { FORM_KEY, FormItemRule } from '../wd-form/types'
+import { useParent } from '../composables/useParent'
const defaultDisplayFormat = (value, type) => {
switch (type) {
@@ -229,6 +236,8 @@ interface Props {
safeAreaInsetBottom?: boolean
// eslint-disable-next-line @typescript-eslint/ban-types
beforeConfirm?: Function
+ prop?: string
+ rules?: FormItemRule[]
}
const props = withDefaults(defineProps(), {
customClass: '',
@@ -255,7 +264,8 @@ const props = withDefaults(defineProps(), {
ellipsis: false,
showTypeSwitch: false,
shortcuts: () => [],
- safeAreaInsetBottom: true
+ safeAreaInsetBottom: true,
+ rules: () => []
})
const pickerShow = ref(false)
@@ -329,6 +339,31 @@ watch(
}
)
+const { parent: form } = useParent(FORM_KEY)
+
+// 表单校验错误信息
+const errorMessage = computed(() => {
+ if (form && props.prop && form.errorMessages && form.errorMessages[props.prop]) {
+ return form.errorMessages[props.prop]
+ } else {
+ return ''
+ }
+})
+
+// 是否展示必填
+const isRequired = computed(() => {
+ let formRequired = false
+ if (form && form.rules) {
+ const rules = form.rules
+ for (const key in rules) {
+ if (Object.prototype.hasOwnProperty.call(rules, key) && key === props.prop && Array.isArray(rules[key])) {
+ formRequired = rules[key].some((rule: FormItemRule) => rule.required)
+ }
+ }
+ }
+ return props.required || props.rules.some((rule) => rule.required) || formRequired
+})
+
const range = computed(() => {
return (type) => {
return isRange(type)
diff --git a/src/uni_modules/wot-design-uni/components/wd-cell-group/wd-cell-group.vue b/src/uni_modules/wot-design-uni/components/wd-cell-group/wd-cell-group.vue
index 00dedb0b..1658b579 100644
--- a/src/uni_modules/wot-design-uni/components/wd-cell-group/wd-cell-group.vue
+++ b/src/uni_modules/wot-design-uni/components/wd-cell-group/wd-cell-group.vue
@@ -1,12 +1,3 @@
-
diff --git a/src/uni_modules/wot-design-uni/components/wd-cell/index.scss b/src/uni_modules/wot-design-uni/components/wd-cell/index.scss
index a10071bb..b155287b 100644
--- a/src/uni_modules/wot-design-uni/components/wd-cell/index.scss
+++ b/src/uni_modules/wot-design-uni/components/wd-cell/index.scss
@@ -24,7 +24,7 @@
}
}
- :deep(.wd-cell__arrow-right){
+ :deep(.wd-cell__arrow-right) {
color: $-dark-color;
}
}
@@ -36,7 +36,7 @@
background-color: $-color-white;
text-decoration: none;
color: $-cell-title-color;
- line-height: $-cell-ling-height;
+ line-height: $-cell-line-height;
-webkit-tap-highlight-color: transparent;
@include when(border) {
@@ -62,6 +62,10 @@
.wd-cell__value {
text-align: left;
}
+
+ .wd-cell__left {
+ margin-right: 0;
+ }
}
@include when(label) {
@@ -73,10 +77,9 @@
position: relative;
flex: 1;
display: flex;
- align-items: center;
- margin-right: $-cell-padding;
font-size: $-cell-title-fs;
box-sizing: border-box;
+ margin-right: $-cell-padding;
@include when(required) {
padding-left: 12px;
@@ -94,7 +97,6 @@
@include e(right) {
position: relative;
- display: flex;
flex: 1;
}
@@ -102,7 +104,6 @@
flex: 1;
width: 100%;
font-size: $-cell-title-fs;
- margin-right: $-cell-padding;
}
@include e(label) {
@@ -115,11 +116,14 @@
@include edeep(icon) {
display: block;
position: relative;
- width: $-cell-icon-size;
- height: $-cell-icon-size;
- line-height: 1.25;
margin-right: $-cell-icon-right;
font-size: $-cell-icon-size;
+ height: $-cell-line-height;
+ line-height: $-cell-line-height;
+ }
+
+ @include e(body){
+ display: flex;
}
@include e(value) {
@@ -128,18 +132,25 @@
font-size: $-cell-value-fs;
color: $-cell-value-color;
text-align: right;
- line-height: $-cell-value-line-height;
- vertical-align: top;
+ vertical-align: middle;
}
@include edeep(arrow-right) {
- display: inline-block;
+ display: block;
margin-left: 8px;
width: $-cell-arrow-size;
- line-height: 1.22;
font-size: $-cell-arrow-size;
color: $-cell-arrow-color;
- vertical-align: top;
+ height: $-cell-line-height;
+ line-height: $-cell-line-height;
+ }
+
+ @include e(error-message){
+ color: $-form-item-error-message-color;
+ font-size: $-form-item-error-message-font-size;
+ line-height: $-form-item-error-message-line-height;
+ text-align: left;
+ vertical-align: middle;
}
@include when(link) {
@@ -155,14 +166,17 @@
font-size: $-cell-title-fs-large;
}
+ .wd-cell__wrapper {
+ padding-top: $-cell-wrapper-padding-large;
+ padding-bottom: $-cell-wrapper-padding-large;
+ }
+
.wd-cell__label {
font-size: $-cell-label-fs-large;
}
- .wd-cell__icon {
+ :deep(.wd-cell__icon) {
font-size: $-cell-icon-size-large;
- width: $-cell-icon-size-large;
- height: $-cell-icon-size-large;
}
}
diff --git a/src/uni_modules/wot-design-uni/components/wd-cell/wd-cell.vue b/src/uni_modules/wot-design-uni/components/wd-cell/wd-cell.vue
index 8275b7c6..e3748f29 100644
--- a/src/uni_modules/wot-design-uni/components/wd-cell/wd-cell.vue
+++ b/src/uni_modules/wot-design-uni/components/wd-cell/wd-cell.vue
@@ -1,13 +1,13 @@
@@ -16,29 +16,29 @@
-
- {{ title }}
-
-
+ {{ title }}
+
-
- {{ label }}
-
-
+ {{ label }}
+
-
-
- {{ value }}
-
+
+
+
+ {{ value }}
+
+
+
+
+
-
-
+ {{ errorMessage }}
@@ -57,7 +57,10 @@ export default {
+
+
+
+
diff --git a/src/uni_modules/wot-design-uni/components/wd-form/index.scss b/src/uni_modules/wot-design-uni/components/wd-form/index.scss
new file mode 100644
index 00000000..44acaeba
--- /dev/null
+++ b/src/uni_modules/wot-design-uni/components/wd-form/index.scss
@@ -0,0 +1,10 @@
+@import "../common/abstracts/variable";
+@import "../common/abstracts/mixin";
+
+.wot-theme-dark {
+ @include b(form) {
+ }
+}
+
+@include b(form) {
+}
diff --git a/src/uni_modules/wot-design-uni/components/wd-form/types.ts b/src/uni_modules/wot-design-uni/components/wd-form/types.ts
new file mode 100644
index 00000000..81fd4bbb
--- /dev/null
+++ b/src/uni_modules/wot-design-uni/components/wd-form/types.ts
@@ -0,0 +1,38 @@
+/*
+ * @Author: weisheng
+ * @Date: 2023-12-14 11:21:58
+ * @LastEditTime: 2023-12-23 16:20:20
+ * @LastEditors: weisheng
+ * @Description:
+ * @FilePath: \wot-design-uni\src\uni_modules\wot-design-uni\components\wd-form\types.ts
+ * 记得注释
+ */
+import { type InjectionKey } from 'vue'
+
+export type FormProvide = {
+ model: Record
+ rules?: FormRules
+ border?: boolean
+ errorMessages?: Record
+}
+
+export const FORM_KEY: InjectionKey = Symbol('wd-form')
+
+export type FormRules = {
+ [key: string]: FormItemRule[]
+}
+
+export type ErrorMessage = {
+ prop: string
+ message: string
+}
+
+export interface FormItemRule {
+ [key: string]: any
+ required: boolean
+ message: string
+ pattern?: RegExp
+ validator?: (value: any, rule: FormItemRuleWithoutValidator) => boolean | Promise | Promise | Promise | Promise
+}
+
+export type FormItemRuleWithoutValidator = Omit
diff --git a/src/uni_modules/wot-design-uni/components/wd-form/wd-form.vue b/src/uni_modules/wot-design-uni/components/wd-form/wd-form.vue
new file mode 100644
index 00000000..b58f511e
--- /dev/null
+++ b/src/uni_modules/wot-design-uni/components/wd-form/wd-form.vue
@@ -0,0 +1,174 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/uni_modules/wot-design-uni/components/wd-input-number/index.scss b/src/uni_modules/wot-design-uni/components/wd-input-number/index.scss
index ddb4a11b..32879c24 100644
--- a/src/uni_modules/wot-design-uni/components/wd-input-number/index.scss
+++ b/src/uni_modules/wot-design-uni/components/wd-input-number/index.scss
@@ -28,7 +28,6 @@
@include b(input-number) {
display: inline-block;
- font-size: 0;
user-select: none;
line-height: 1.15;
diff --git a/src/uni_modules/wot-design-uni/components/wd-input/index.scss b/src/uni_modules/wot-design-uni/components/wd-input/index.scss
index aea1a909..3c80e471 100644
--- a/src/uni_modules/wot-design-uni/components/wd-input/index.scss
+++ b/src/uni_modules/wot-design-uni/components/wd-input/index.scss
@@ -3,6 +3,7 @@
.wot-theme-dark {
@include b(input) {
+ background: $-dark-background2;
&::after {
background: $-dark-color-gray;
@@ -16,9 +17,6 @@
}
}
- @include e(textarea) {
- background: $-dark-background2;
- }
@include e(inner) {
color: $-dark-color;
@@ -28,14 +26,6 @@
}
}
- @include e(textarea-inner) {
- color: $-dark-color;
-
- &::-webkit-input-placeholder {
- color: $-dark-color3;
- }
- }
-
@include e(placeholder) {
color: $-dark-color3;
}
@@ -49,19 +39,8 @@
color: $-dark-color;
}
- @include e(textarea-count) {
- color: $-dark-color3;
- background: transparent;
- }
-
- @include e(textarea-count-current) {
- color: $-dark-color;
- }
-
-
:deep(.wd-input__icon),
- :deep(.wd-input__clear),
- :deep(.wd-input__textarea-icon) {
+ :deep(.wd-input__clear) {
color: $-dark-color;
background: transparent;
}
@@ -76,8 +55,7 @@
@include when(disabled) {
- .wd-input__inner,
- .wd-input__textarea-inner {
+ .wd-input__inner {
color: $-dark-color-gray;
background: transparent;
}
@@ -94,6 +72,7 @@
position: relative;
-webkit-tap-highlight-color: transparent;
text-align: left;
+ background: $-input-bg;
&::after {
position: absolute;
@@ -115,12 +94,6 @@
}
}
- @include when(textarea) {
- &::after {
- display: none;
- }
- }
-
@include e(label) {
position: relative;
width: $-input-cell-label-width;
@@ -129,7 +102,6 @@
box-sizing: border-box;
font-size: $-input-fs;
flex-shrink: 0;
- line-height: $-cell-ling-height;
@include when(required) {
padding-left: 12px;
@@ -137,7 +109,7 @@
&::after {
position: absolute;
left: 0;
- top: calc($-cell-wrapper-padding + 2px);
+ top: 2px;
content: "*";
font-size: $-cell-required-size;
line-height: 1.1;
@@ -148,17 +120,22 @@
@include e(label-inner) {
display: inline-block;
- padding: $-cell-wrapper-padding 0;
font-size: $-input-fs;
+ line-height: $-cell-line-height;
}
- @include e(block) {
+ @include e(body) {
+ flex: 1;
+ }
+
+ @include e(value) {
position: relative;
display: flex;
flex-direction: row;
align-items: center;
}
+
@include e(prefix) {
margin-right: $-input-icon-margin;
font-size: $-input-fs;
@@ -172,12 +149,20 @@
@include e(suffix) {
flex-shrink: 0;
margin-left: $-input-icon-margin;
+ line-height: initial;
+ }
+
+ @include e(error-message){
+ color: $-form-item-error-message-color;
+ font-size: $-form-item-error-message-font-size;
+ line-height: $-form-item-error-message-line-height;
+ text-align: left;
+ vertical-align: middle;
}
@include when(disabled) {
- .wd-input__inner,
- .wd-input__textarea-inner {
+ .wd-input__inner {
color: $-input-disabled-color;
background: transparent;
}
@@ -185,8 +170,7 @@
@include when(error) {
- .wd-input__inner,
- .wd-input__textarea-inner {
+ .wd-input__inner {
color: $-input-error-color;
background: transparent;
}
@@ -207,18 +191,13 @@
@include when(cell) {
display: flex;
align-items: flex-start;
- padding: 0 $-input-cell-padding;
+ padding: $-input-cell-padding $-input-padding;
background-color: $-input-cell-bg;
&.is-error::after {
background: $-input-cell-border-color;
}
- .wd-input__textarea,
- .wd-input__block {
- flex: 1;
- }
-
:deep(.wd-input__icon),
:deep(.wd-input__clear) {
height: $-input-cell-height;
@@ -238,17 +217,6 @@
display: none;
}
- .wd-input__textarea {
- padding: 13px 0 36px 0;
- }
-
- .wd-input__textarea-inner {
- padding-right: 24px;
- }
-
- .wd-input__textarea-suffix {
- right: 0;
- }
@include when(center) {
align-items: center;
@@ -260,6 +228,8 @@
}
@include when(large) {
+ padding: $-input-cell-padding-large;
+
.wd-input__prefix {
font-size: $-input-fs-large;
}
@@ -270,47 +240,20 @@
.wd-input__inner {
font-size: $-input-fs-large;
- height: $-input-cell-height-large;
}
- .wd-input__textarea-inner {
- font-size: $-input-fs-large;
- }
.wd-input__count {
font-size: $-input-count-fs-large;
}
- .wd-input__textarea-count {
- font-size: $-input-count-fs-large;
- }
-
:deep(.wd-input__icon),
:deep(.wd-input__clear) {
- height: $-input-cell-height-large;
- font-size: $-input-icon-size-large;
- line-height: $-input-cell-height-large;
- }
-
- :deep(.wd-input__textarea-icon) {
font-size: $-input-icon-size-large;
}
+
}
- @include when(auto-height) {
- &::after {
- display: block;
- }
-
- .wd-input__textarea {
- padding: $-input-inner-padding;
- }
-
- .wd-input__textarea-suffix {
- top: 8px;
- right: 0;
- }
- }
@include e(inner) {
flex: 1;
@@ -330,16 +273,18 @@
}
}
- @include e(readonly) {
- padding: $-input-inner-padding;
+ @include e(readonly-mask) {
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: 2;
+ width: 100%;
+ height: 100%;
}
- @include e(textarea-inner) {
- width: 100%;
- }
@include edeep(icon) {
- margin-left: 8px;
+ margin-left: $-input-icon-margin;
font-size: $-input-icon-size;
color: $-input-icon-color;
vertical-align: middle;
@@ -347,7 +292,7 @@
}
@include edeep(clear) {
- margin-left: 8px;
+ margin-left: $-input-icon-margin;
font-size: $-input-icon-size;
color: $-input-clear-color;
vertical-align: middle;
@@ -370,79 +315,6 @@
}
}
- @include e(textarea) {
- position: relative;
- padding: $-input-textarea-padding;
- font-size: 0;
- display: flex;
- background: $-input-bg;
-
- @include when(show-limit) {
- padding-bottom: 36px;
- }
- }
-
- @include edeep(textarea-icon) {
- margin-left: 8px;
- font-size: $-input-icon-size;
- line-height: 20px;
- color: $-input-icon-color;
- background: #fff;
- }
-
- @include e(textarea-inner) {
- flex: 1;
- // width: 1px;
- padding: 0;
- font-size: $-input-fs;
- line-height: 1.43;
- color: $-input-color;
- outline: none;
- box-sizing: border-box;
- border: none;
- word-break: break-word;
-
- &::-webkit-input-placeholder {
- color: $-input-placeholder-color;
- }
-
- @include when(suffix) {
- padding-right: calc($-input-textarea-padding + $-input-icon-size);
- }
- }
-
- @include e(textarea-suffix) {
- position: absolute;
- right: 14px;
- top: $-input-textarea-padding;
- bottom: 0;
- }
-
- @include edeep(textarea-icon) {
- margin-left: 8px;
- font-size: $-input-icon-size;
- line-height: 20px;
- color: $-input-clear-color;
- background: $-input-bg;
- }
-
- @include e(textarea-count) {
- position: absolute;
- bottom: 8px;
- right: 0;
- font-size: $-input-count-fs;
- color: $-input-count-color;
- background: $-input-bg;
- line-height: 20px;
- }
-
- @include e(textarea-count-current) {
- color: $-input-count-current-color;
-
- @include when(error) {
- color: $-input-error-color;
- }
- }
@include e(placeholder) {
color: $-input-placeholder-color;
@@ -452,18 +324,8 @@
}
}
- :deep(.wd-input__textarea-count) {
- display: inline-flex;
- }
-
.wd-input__count,
.wd-input__count-current {
display: inline-flex;
}
-
- @include e(textarea-map) {
- position: absolute;
- width: 100%;
- height: 100%;
- }
}
\ No newline at end of file
diff --git a/src/uni_modules/wot-design-uni/components/wd-input/wd-input.vue b/src/uni_modules/wot-design-uni/components/wd-input/wd-input.vue
index 799a8903..86d03ba4 100644
--- a/src/uni_modules/wot-design-uni/components/wd-input/wd-input.vue
+++ b/src/uni_modules/wot-design-uni/components/wd-input/wd-input.vue
@@ -1,74 +1,22 @@
-
+
-
-
- {{ label }}
-
-
+
+ {{ label }}
+
-
-
-
- {{ inputValue }}
-
-
-
-
-
-
- {{ String(inputValue).length }}
-
- /{{ maxlength }}
-
-
-
-
-
-
-
-
-
-
- {{ inputValue }}
-
+
+
+
+
+
+
+
@@ -120,7 +67,8 @@
-
+
+ {{ errorMessage }}
@@ -140,10 +88,10 @@ export default {
import { computed, onBeforeMount, ref, watch } from 'vue'
import { objToStyle, requestAnimationFrame } from '../common/util'
import { useCell } from '../composables/useCell'
+import { FORM_KEY, FormItemRule } from '../wd-form/types'
+import { useParent } from '../composables/useParent'
interface Props {
- customTextareaContainerClass?: string
- customTextareaClass?: string
customInputClass?: string
customLabelClass?: string
customClass?: string
@@ -152,11 +100,8 @@ interface Props {
placeholder?: string
placeholderStyle?: string
placeholderClass?: string
- autoHeight?: boolean
- fixed?: boolean
cursorSpacing?: number
cursor?: number
- showConfirmBar?: boolean
selectionStart?: number
selectionEnd?: number
adjustPosition?: boolean
@@ -167,11 +112,10 @@ interface Props {
type?: string
maxlength?: number
disabled?: boolean
- alignRight?: boolean
alwaysEmbed?: boolean
// 原生属性结束
+ alignRight?: boolean
modelValue: string | number
- minlength?: number
showPassword?: boolean
clearable?: boolean
readonly?: boolean
@@ -180,8 +124,6 @@ interface Props {
prefixIcon?: string
suffixIcon?: string
showWordLimit?: boolean
- suffix?: string
- suffixCount?: number
label?: string
labelWidth?: string
useLabelSlot?: boolean
@@ -190,11 +132,11 @@ interface Props {
center?: boolean
noBorder?: boolean
required?: boolean
+ prop?: string
+ rules?: FormItemRule[]
}
const props = withDefaults(defineProps(), {
- customTextareaContainerClass: '',
- customTextareaClass: '',
customInputClass: '',
customLabelClass: '',
customClass: '',
@@ -203,7 +145,6 @@ const props = withDefaults(defineProps(), {
maxlength: -1,
modelValue: '',
placeholder: '请输入...',
- autoHeight: false,
clearable: false,
showPassword: false,
disabled: false,
@@ -215,12 +156,10 @@ const props = withDefaults(defineProps(), {
showWordLimit: false,
confirmType: 'done',
confirmHold: false,
- placeholderClass: 'textarea-placeholder',
+ placeholderClass: '',
focus: false,
cursorSpacing: 0,
- fixed: false,
cursor: -1,
- showConfirmBar: true,
selectionStart: -1,
selectionEnd: -1,
adjustPosition: true,
@@ -230,7 +169,8 @@ const props = withDefaults(defineProps(), {
labelWidth: '33%',
useLabelSlot: false,
required: false,
- noBorder: false
+ noBorder: false,
+ rules: () => []
})
const showClear = ref(false)
@@ -263,18 +203,40 @@ watch(
{ immediate: true, deep: true }
)
+const { parent: form } = useParent(FORM_KEY)
+
+const errorMessage = computed(() => {
+ if (form && props.prop && form.errorMessages && form.errorMessages[props.prop]) {
+ return form.errorMessages[props.prop]
+ } else {
+ return ''
+ }
+})
+
+// 是否展示必填
+const isRequired = computed(() => {
+ let formRequired = false
+ if (form && form.rules) {
+ const rules = form.rules
+ for (const key in rules) {
+ if (Object.prototype.hasOwnProperty.call(rules, key) && key === props.prop && Array.isArray(rules[key])) {
+ formRequired = rules[key].some((rule: FormItemRule) => rule.required)
+ }
+ }
+ }
+ return props.required || props.rules.some((rule) => rule.required) || formRequired
+})
+
const rootClass = computed(() => {
- return `wd-input ${props.type === 'textarea' ? 'is-textarea' : ''} ${props.label || props.useLabelSlot ? 'is-cell' : ''} ${
- props.center ? 'is-center' : ''
- } ${cell.border.value ? 'is-border' : ''} ${props.size ? 'is-' + props.size : ''} ${props.error ? 'is-error' : ''} ${
- props.disabled ? 'is-disabled' : ''
- } ${props.autoHeight ? 'is-auto-height' : ''} ${inputValue.value && String(inputValue.value).length > 0 ? 'is-not-empty' : ''} ${
- props.noBorder ? 'is-no-border' : ''
- } ${props.customClass}`
+ return `wd-input ${props.label || props.useLabelSlot ? 'is-cell' : ''} ${props.center ? 'is-center' : ''} ${
+ cell.border.value ? 'is-border' : ''
+ } ${props.size ? 'is-' + props.size : ''} ${props.error ? 'is-error' : ''} ${props.disabled ? 'is-disabled' : ''} ${
+ inputValue.value && String(inputValue.value).length > 0 ? 'is-not-empty' : ''
+ } ${props.noBorder ? 'is-no-border' : ''} ${props.customClass}`
})
const labelClass = computed(() => {
- return `wd-input__label ${props.customLabelClass} ${props.required ? 'is-required' : ''}`
+ return `wd-input__label ${props.customLabelClass} ${isRequired.value ? 'is-required' : ''}`
})
const inputPlaceholderClass = computed(() => {
@@ -301,7 +263,8 @@ const emit = defineEmits([
'confirm',
'linechange',
'clicksuffixicon',
- 'clickprefixicon'
+ 'clickprefixicon',
+ 'click'
])
onBeforeMount(() => {
@@ -346,9 +309,7 @@ function handleBlur({ detail }) {
})
emit('update:modelValue', inputValue.value)
emit('blur', {
- value: inputValue.value,
- // textarea 有 cursor
- cursor: detail.cursor ? detail.cursor : null
+ value: inputValue.value
})
}
function handleFocus({ detail }) {
@@ -370,15 +331,15 @@ function handleKeyboardheightchange(event) {
function handleConfirm({ detail }) {
emit('confirm', detail)
}
-function handleLineChange(event) {
- emit('linechange', event.detail)
-}
function onClickSuffixIcon() {
emit('clicksuffixicon')
}
function onClickPrefixIcon() {
emit('clickprefixicon')
}
+function handleClick(event: MouseEvent) {
+ emit('click', event)
+}