From d5eca77afcab9149e2498065c83ce68f250f34d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=98=89=E6=B6=B5?= Date: Wed, 1 Aug 2018 17:09:38 +0800 Subject: [PATCH] [breaking change] Field: rewrite --- example/pages/field/config.js | 68 ---------- example/pages/field/index.js | 86 ++----------- example/pages/field/index.json | 6 +- example/pages/field/index.wxml | 162 ++++++++++++------------ example/pages/field/index.wxss | 18 +-- packages/card/README.md | 6 +- packages/cell/index.pcss | 1 - packages/field/README.md | 224 ++++++++++++++++++++------------- packages/field/index.js | 143 ++++++++++++++------- packages/field/index.json | 3 +- packages/field/index.pcss | 140 ++++++++++++--------- packages/field/index.wxml | 97 ++++++++------ 12 files changed, 480 insertions(+), 474 deletions(-) delete mode 100644 example/pages/field/config.js diff --git a/example/pages/field/config.js b/example/pages/field/config.js deleted file mode 100644 index ee14e6f1..00000000 --- a/example/pages/field/config.js +++ /dev/null @@ -1,68 +0,0 @@ -module.exports = { - // 基础类型输入框配置 - base: { - name: { - focus: true, - title: '收货人', - placeholder: '名字' - }, - tel: { - error: true, - title: '联系电话', - inputType: 'number', - placeholder: '请输入手机号' - }, - address: { - title: '详细地址', - type: 'textarea', - placeholder: '请输入详细地址(最多50字)' - }, - disabled: { - title: '用户信息', - disabled: true, - value: '输入框已禁用' - } - }, - // 无标题输入框 - notitle: { - placeholder: '请输入收货人姓名', - componentId: 'textarea:test' - }, - // 圆角输入框 - radius: { - totalPrice: { - right: true, - mode: 'wrapped', - title: '消费总额', - inputType: 'number', - placeholder: '询问收银员后输入' - }, - excludePrice: { - right: true, - error: true, - mode: 'wrapped', - title: '不参与优惠金额', - inputType: 'number', - placeholder: '询问收银员后输入' - }, - notitle: { - mode: 'wrapped', - inputType: 'number', - placeholder: '请输入消费金额' - } - }, - // Form 中使用输入框 - form: { - name: { - name: 'name', - placeholder: '请输入收货人姓名', - componentId: 'form:test:name' - }, - tel: { - name: 'tel', - inputType: 'tel', - placeholder: '请输入收货人手机号码', - componentId: 'form:test:tel' - } - } -}; diff --git a/example/pages/field/index.js b/example/pages/field/index.js index 28ef3a4b..28075b3e 100644 --- a/example/pages/field/index.js +++ b/example/pages/field/index.js @@ -1,82 +1,18 @@ -const config = require('./config'); - Page({ data: { - config, - value: 'test', - textareaValue: 'test textarea', - area: ['省份', '北京市', '天津市', '河北省', '山西省', '内蒙古自治区', '辽宁省', '吉林省', '黑龙江省', '上海市', '江苏省', '浙江省', '安徽省', '福建省', '江西省', '山东省', '河南省', '湖北省', '湖南省', '广东省', '广西壮族自治区', '海南省', '重庆市', '四川省', '贵州省', '云南省', '西藏自治区', '陕西省', '甘肃省', '青海省', '宁夏回族自治区', '新疆维吾尔自治区', '台湾省', '香港特别行政区', '澳门特别行政区'], - areaIndex: 0, - // picker-view 示例配置 - pickerViewConfig: { - show: false, - value: [0, 0], - year: [2016, 2017, 2018], - sex: ['男', '女'] - } + sms: '', + value: '', + password: '', + username: '', + username2: '', + message: '', + phone: '1365577' }, - onAreaChange(e) { - this.setData({ - areaIndex: e.detail.value - }); - }, - - handleZanFieldChange(e) { - const { detail } = e; - - console.log('[zan:field:change]', detail); - }, - - handleZanFieldFocus(e) { - const { detail } = e; - - console.log('[zan:field:focus]', detail); - }, - - handleZanFieldBlur(e) { - const { detail } = e; - - console.log('[zan:field:blur]', detail); - }, - - clearInput() { - this.setData({ - value: '' - }); - }, - - clearTextarea() { - this.setData({ - textareaValue: '' - }); - }, - - formSubmit(event) { - console.log('[zan:field:submit]', event.detail.value); - }, - - formReset(event) { - console.log('[zan:field:reset]', event); - }, - - /* piker-view 示例相关函数 */ - handleDateFieldClick() { - this.setData({ - 'pickerViewConfig.show': true - }); - }, - - handlePopupDateChange(e) { - this.setData({ - 'pickerViewConfig.value': e.detail.value - }); - }, - - hideDatePopup() { - this.setData({ - 'pickerViewConfig.show': false + onTapIcon() { + wx.showToast({ + icon: 'none', + title: '点击图标' }); } - }); diff --git a/example/pages/field/index.json b/example/pages/field/index.json index d88f1555..4477ae8a 100644 --- a/example/pages/field/index.json +++ b/example/pages/field/index.json @@ -1,9 +1,9 @@ { "navigationBarTitleText": "Field 输入框", "usingComponents": { - "van-button": "../../dist/button/index", - "van-cell-group": "../../dist/cell-group/index", + "demo-block": "../../components/demo-block/index", "van-field": "../../dist/field/index", - "van-panel": "../../dist/panel/index" + "van-button": "../../dist/button/index", + "van-cell-group": "../../dist/cell-group/index" } } diff --git a/example/pages/field/index.wxml b/example/pages/field/index.wxml index 9586eb80..26fd4aaa 100644 --- a/example/pages/field/index.wxml +++ b/example/pages/field/index.wxml @@ -1,90 +1,88 @@ - - + + + + + + + - + value="{{ username }}" + label="用户名" + placeholder="请输入用户名" + clearable + icon="question" + icon-class="icon" + required + bind:tap-icon="onTapIcon" + /> - + value="{{ password }}" + type="password" + label="密码" + placeholder="请输入密码" + required + border="{{ false }}" + /> + + + + + - + value="输入框已禁用" + label="用户名" + left-icon="contact" + disabled + border="{{ false }}" + /> + + + + + + + + + + + + + + + + + + + 发送验证码 - - -清除输入 - - - - - - - -清除输入 - - - - - - - - - - - - -
- - - - - -
-
+ diff --git a/example/pages/field/index.wxss b/example/pages/field/index.wxss index 003aabb7..ddfc7c9f 100644 --- a/example/pages/field/index.wxss +++ b/example/pages/field/index.wxss @@ -1,17 +1,7 @@ -.field__title--radius { - padding-bottom: 10px; +.button { + vertical-align: middle; } -.popup-field-example--bottom { - width: 100%; - height: 150px; -} - -.picker-view-example { - height: 120px; -} - -.picker-view-column-example { - line-height: 50px; - text-align: center; +.icon { + color: #38f; } diff --git a/packages/card/README.md b/packages/card/README.md index 729bcc97..2df38f23 100644 --- a/packages/card/README.md +++ b/packages/card/README.md @@ -58,9 +58,9 @@ | 名称 | 说明 | |-----------|-----------| -| title | 自定义标题栏,如果设置了`title`或`price`属性,则不生效 | -| desc | 自定义描述栏,如果设置了`desc`或`num`属性,则不生效 | -| thumb | 自定义 thumb,如果设置了`thumb`属性,则不生效 | +| title | 自定义标题栏,如果设置了`title`或`price`属性则不生效 | +| desc | 自定义描述栏,如果设置了`desc`或`num`属性则不生效 | +| thumb | 自定义 thumb,如果设置了`thumb`属性则不生效 | | footer | 自定义 footer | | tags | 自定义 tags | diff --git a/packages/cell/index.pcss b/packages/cell/index.pcss index 44b9358b..0f6a6f26 100644 --- a/packages/cell/index.pcss +++ b/packages/cell/index.pcss @@ -10,7 +10,6 @@ background-color: $white; color: $text-color; font-size: 14px; - overflow: hidden; &::after { left: 15px; diff --git a/packages/field/README.md b/packages/field/README.md index d0142d6e..3d4814df 100644 --- a/packages/field/README.md +++ b/packages/field/README.md @@ -3,115 +3,171 @@ ### 使用指南 在 index.json 中引入组件 ```json -{ - "usingComponents": { - "van-field": "path/to/vant-weapp/dist/field/index" - } +"usingComponents": { + "van-field": "path/to/vant-weapp/dist/field/index" } ``` ### 代码演示 #### 基础用法 -field 支持多种展示方式,在 `data` 中传入对应的设置即可。 -```html - - -``` -```js -Page({ - data: { - field: { - focus: true, - title: '收货人', - placeholder: '名字', - value: 'test' - } - } -}); -``` - -#### Field 列表 ```html - - + ``` -#### 监听事件 - -field会触发一些事件,当你需要监听这些事件时,可以绑定对应的事件。 +#### 自定义类型 +根据`type`属性定义不同类型的输入框 ```html - - + + + + + ``` -```js -Page(extend({}, { - data: { - field: { - focus: true, - title: '收货人', - placeholder: '名字', - value: 'test' - } - }, +#### 禁用输入框 - methods: { - handleFieldChange(event) { - console.log(event); - }, +```html + + + +``` - handleFieldFocus(event) { - console.log(event); - }, +#### 错误提示 +通过`error`或者`error-message`属性增加对应的错误提示 - handleFieldBlur(event) { - console.log(event); - } - } -})); +```html + + + + +``` + +#### 高度自适应 +对于 textarea,可以通过`autosize`属性设置高度自适应 + +```html + + + +``` + +#### 插入按钮 +通过 button slot 可以在输入框尾部插入按钮 + +```html + + + 发送验证码 + + ``` ### API -| 参数 | 说明 | 类型 | 默认值 | 必须 | +| 参数 | 说明 | 类型 | 默认值 | |-----------|-----------|-----------|-------------|-------------| -| title | 输入框左侧标题,若传入为空,则不显示标题 | String | - | | -| name | 输入框的名字,作为 form 表单提交时数据的 key | String | componentId 指定的值 | | -| value | 输入框的内容 | String | - | | -| type | 输入框的类型,可选值为 input, textarea | String | input | | -| inputType | 输入框为 input 情况下,输入框的类型,例如:number, text, password | String | text | | -| placeholder | 输入框为空时占位符 | String | | | -| maxlength | 最大输入长度,设置为 -1 的时候不限制最大长度 | Number | 140 | | -| focus | 自动聚焦,拉起键盘 | Boolean | false | | -| disabled | 输入框是否禁用 | Boolean | false | | -| mode | 输入框展示样式,可选值为 wrapped, normal | String | normal | | -| right | 输入框内容是否居右显示 | Boolean | false | | -| error | 是否显示为输入框错误情况下的样式 | Boolean | false | | -| componentId | 用于区分输入框之间的唯一名称 | String | - | | +| label | 输入框左侧文本 | `String` | - | +| value | 当前输入的值 | `String | Number` | - | +| type | 可设置为任意原生类型, 如 `number` `idcard` `textarea` `digit` | `String` | `text` | +| focus | 获取焦点 | `Boolean` | `false` | +| border | 是否显示内边框 | `Boolean` | `true` | +| disabled | 是否禁用输入框 | `Boolean` | `false` | +| readonly | 是否只读 | `Boolean` | `false` | +| clearable | 是否启用清除控件 | `Boolean` | `false` | +| required | 是否显示表单必填星号 | `Boolean` | `false` | +| maxlength | 最大输入长度,设置为 -1 的时候不限制最大长度 | `Number` | `-1` | +| placeholder | 输入框为空时占位符 | `String` | - | +| is-link | 是否展示右侧箭头并开启点击反馈 | `Boolean` | `false` | +| error | 是否将输入内容标红 | `Boolean` | `false` | +| error-message | 底部错误提示文案,为空时不展示 | `String` | `''` | +| label-align | 文本对齐方式,可选值为 `center` `right` | `String` | `left` | +| input-align | 输入框内容对齐方式,可选值为 `center` `right` | `String` | `left` | +| autosize | 自适应内容高度,只对 textarea 有效 | `Boolean` | `false` | +| icon | 输入框尾部图标 (可选值见 Icon 组件) | `String` | - | +| left-icon | 输入框左侧图标 (可选值见 Icon 组件) | `String` | - | +| cursor-spacing | 输入框聚焦时底部与键盘的距离 | `Number` | `50` | +| use-button-slot | 是否使用 button slot | `Boolean` | `false` | ### Event -| 事件名称 | 说明 | 回调参数 | +| 事件 | 说明 | 回调参数 | |-----------|-----------|-----------| -| change | 当绑定值变化时触发的事件 | event对象 | -| focus | 输入框focus | event对象 | -| blur | 输入框blur | event对象 | +| inout | 输入内容时触发 | value: 当前输入值 | +| change | 输入内容时触发 | value: 当前输入值 | +| click-icon | 点击尾部图标时触发 | - | +| focus | 输入框聚焦时触发 | - | +| blur | 输入框失焦时触发 | - | + +### Slot + +| 名称 | 说明 | +|-----------|-----------| +| label | 自定义输入框标签,如果设置了`label`属性则不生效 | +| icon | 自定义输入框尾部图标,如果设置了`icon`属性则不生效 | +| button | 自定义输入框尾部按钮,需要设置`use-button-slot`属性 | + +### 外部样式类 + +| 类名 | 说明 | +|-----------|-----------| +| custom-class | 根节点样式类 | +| input-class | 输入框样式类 | +| icon-class | 右侧图标样式类 | +| placeholder-class | 占位内容样式类 | diff --git a/packages/field/index.js b/packages/field/index.js index 05df865c..58ca456b 100644 --- a/packages/field/index.js +++ b/packages/field/index.js @@ -1,68 +1,117 @@ Component({ behaviors: ['wx://form-field'], - externalClasses: ['field-class'], + externalClasses: [ + 'custom-class', + 'input-class' + ], - relations: { - '../cell-group/index': { - type: 'parent' - } + options: { + multipleSlots: true }, properties: { - title: String, - type: { - type: String, - value: 'input' - }, - disabled: Boolean, - focus: Boolean, - inputType: { - type: String, - value: 'text' - }, - placeholder: String, - mode: { - type: String, - value: 'normal' - }, - right: Boolean, + icon: String, + label: String, error: Boolean, + focus: Boolean, + center: Boolean, + isLink: Boolean, + leftIcon: String, + disabled: Boolean, + autosize: Boolean, + readonly: Boolean, + required: Boolean, + iconClass: String, + clearable: Boolean, + labelAlign: String, + inputAlign: String, + errorMessage: String, + placeholder: String, + useButtonSlot: Boolean, + placeholderClass: String, + cursorSpacing: { + type: Number, + value: 50 + }, maxlength: { type: Number, - value: 140 + value: -1 + }, + value: { + type: null, + value: '' + }, + type: { + type: String, + value: 'text', + observer(currentValue) { + this.setData({ currentValue }); + } + }, + border: { + type: Boolean, + value: true } }, data: { - showBorder: true + focused: false, + showClear: false, + currentValue: '' + }, + + attached() { + this.setData({ + currentValue: this.data.value + }); }, methods: { - handleFieldChange(event) { - const { detail = {} } = event; - const { value = '' } = detail; - this.setData({ value }); - - this.triggerEvent('change', event); - }, - - handleFieldFocus(event) { - this.triggerEvent('focus', event); - }, - - handleFieldBlur(event) { - this.triggerEvent('blur', event); - }, - - updateIsLastElement(isLastField) { - let showBorder = true; - if (isLastField && this.data.mode === 'normal') { - showBorder = false; - } - + onInput(event) { + const { value = '' } = event.detail || {}; + this.triggerEvent('input', value); + this.triggerEvent('change', value); this.setData({ - showBorder + currentValue: value, + showClear: this.getShowClear({ value }) + }); + }, + + onFocus(event) { + this.triggerEvent('focus', event); + this.setData({ + focused: true, + showClear: this.getShowClear({ focused: true }) + }); + }, + + onBlur(event) { + this.focused = false; + this.triggerEvent('blur', event); + this.setData({ + focused: false, + showClear: this.getShowClear({ focused: false }) + }); + }, + + onTapIcon() { + this.triggerEvent('tap-icon'); + }, + + getShowClear(options) { + const { + focused = this.data.focused, + value = this.data.currentValue + } = options; + + return this.data.clearable && focused && value !== '' && !this.data.readonly; + }, + + onClear() { + this.setData({ + currentValue: '', + showClear: this.getShowClear({ value: '' }) }); } } diff --git a/packages/field/index.json b/packages/field/index.json index 114b55d6..8809c46b 100644 --- a/packages/field/index.json +++ b/packages/field/index.json @@ -1,6 +1,7 @@ { "component": true, "usingComponents": { - "van-cell": "../cell/index" + "van-cell": "../cell/index", + "van-icon": "../icon/index" } } \ No newline at end of file diff --git a/packages/field/index.pcss b/packages/field/index.pcss index 9a8ec253..a411d0be 100644 --- a/packages/field/index.pcss +++ b/packages/field/index.pcss @@ -1,70 +1,88 @@ -@import "../common/_mixins"; +@import '../helper/index.pcss'; .van-field { - display: block; - position: relative; - color: #333; -} + &__body { + display: flex; + align-items: center; -.van-field::after { - @mixin hairline; - border-bottom-width: 1px; - left: 15px; - right: 0; -} + &--textarea { + min-height: 24px; + } + } -.van-field--no-border::after { - border-bottom-width: 0; -} + &__control { + border: 0; + margin: 0; + padding: 0; + width: 100%; + resize: none; + display: block; + text-align: left; + box-sizing: border-box; + line-height: inherit; + background-color: transparent; -.van-cell--field { - padding: 7px 15px; -} + &--disabled { + opacity: 1; + color: $gray-darker; + background-color: transparent; + } -.van-field--wrapped { - margin: 10px 15px; - background-color: #fff; + &--center { + text-align: center; + } - &::after { - left: 0; - border-width: 1px; - border-radius: 4px; + &--right { + text-align: right; + } + } + + &__clear, + &__icon-container, + &__button { + flex-shrink: 0; + } + + &__clear, + &__icon-container { + padding: 0 10px; + color: $gray-dark; + line-height: inherit; + margin-right: -10px; + vertical-align: middle; + } + + &__icon { + display: block; + font-size: 16px; + line-height: inherit; + } + + &__button { + padding-left: 10px; + } + + &__error-message { + color: $red; + font-size: 12px; + text-align: left; + } + + &--error { + color: $red; + } + + &--label { + &-center { + .van-cell__title { + text-align: center; + } + } + + &-right { + .van-cell__title { + text-align: right; + } + } } } - -/* 圆角输入框,强制展示边框 */ -.van-field--wrapped::after { - display: block; -} - -.van-field--error { - color: #f40; -} - -/* 圆角输入框出现错误时,将边框也置红 */ -.van-field--wrapped.van-field--error::after { - border-color: #f40; -} - -.van-field__title { - color: #333; - min-width: 65px; - padding-right: 10px; -} - -.van-field__input { - flex: 1; - line-height: 1.6; - padding: 4px 0; - min-height: 22px; - height: auto; - font-size: 14px; -} - -.van-field__placeholder { - font-size: 14px; -} - -.van-field__input--right { - text-align: right; -} diff --git a/packages/field/index.wxml b/packages/field/index.wxml index 9792e9c9..ab4ab9ec 100644 --- a/packages/field/index.wxml +++ b/packages/field/index.wxml @@ -1,39 +1,66 @@ - - {{ title }} + + + -