feat(field): add new slot input & add new event click-input (#3932)

fix #3604
This commit is contained in:
rex 2021-01-04 20:42:21 +08:00 committed by GitHub
parent cd0fc68de6
commit 5e4cbeac65
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 108 additions and 78 deletions

View File

@ -185,8 +185,9 @@ Page({
### 真机上为什么会出现聚焦时 placeholder 加粗、闪烁的现象? ### 真机上为什么会出现聚焦时 placeholder 加粗、闪烁的现象?
- 由于微信小程序的 input 组件和 textarea 组件是原生组件,聚焦时会将原生的输入框覆盖在对应位置上,导致了这个现象的产生。 由于微信小程序的 input 组件和 textarea 组件是原生组件,聚焦时会将原生的输入框覆盖在对应位置上,导致了这个现象的产生。
- 相关的讨论可以查看[微信开放社区](https://developers.weixin.qq.com/community/search?query=placeholder%20%E9%97%AA%E7%83%81%20%E5%8A%A0%E7%B2%97)
相关的讨论可以查看[微信开放社区](https://developers.weixin.qq.com/community/search?query=placeholder%20%E9%97%AA%E7%83%81%20%E5%8A%A0%E7%B2%97)
### 真机上 placeholder 为什么会盖过 popup 等其它组件? ### 真机上 placeholder 为什么会盖过 popup 等其它组件?
@ -198,9 +199,9 @@ Page({
同时 `placeholder-style``vertical-align``line-height` 等大量 css 属性都不生效。 同时 `placeholder-style``vertical-align``line-height` 等大量 css 属性都不生效。
这一系列的问题导致了 placeholder 在真机上可能会出现偏移。@vant/weapp 已经尽量抹平 textarea 在不同环境下的差异。 这一系列的问题导致了 placeholder 在真机上可能会出现偏移。
微信已经`padding` 的问题列为修复中的问题,可以查看[微信开放社区](https://developers.weixin.qq.com/community/develop/issue/96) 微信已经`2.10.0` 基础库版本后支持移除默认的 `padding`,但低版本仍有问题。详情可以查看 [微信开放社区](https://developers.weixin.qq.com/community/develop/issue/96)
### 手写输入法为什么会丢失部分字符 / 手写输入法为什么不会触发 input 事件? ### 手写输入法为什么会丢失部分字符 / 手写输入法为什么不会触发 input 事件?
@ -259,24 +260,26 @@ Page({
| 事件 | 说明 | 回调参数 | | 事件 | 说明 | 回调参数 |
| --- | --- | --- | | --- | --- | --- |
| bind:input | 输入内容时触发 | value: 当前输入值 | | bind:input | 输入内容时触发 | event.detail: 当前输入值 |
| bind:change | 输入内容时触发 | value: 当前输入值 | | bind:change | 输入内容时触发 | event.detail: 当前输入值 |
| bind:confirm | 点击完成按钮时触发 | value: 当前输入值 | | bind:confirm | 点击完成按钮时触发 | event.detail: 当前输入值 |
| bind:click-icon | 点击尾部图标时触发 | - | | bind:click-icon | 点击尾部图标时触发 | - |
| bind:focus | 输入框聚焦时触发 | event.detail.value: 当前输入值; <br>event.detail.height: 键盘高度 | | bind:focus | 输入框聚焦时触发 | event.detail.value: 当前输入值; <br>event.detail.height: 键盘高度 |
| bind:blur | 输入框失焦时触发 | event.detail.value: 当前输入值; <br>event.detail.cursor: 游标位置(如果 `type` 不为 `textarea`,值为 `0`) | | bind:blur | 输入框失焦时触发 | event.detail.value: 当前输入值; <br>event.detail.cursor: 游标位置(如果 `type` 不为 `textarea`,值为 `0`) |
| bind:clear | 点击清空控件时触发 | - | | bind:clear | 点击清空控件时触发 | - |
| bind:click-input | 点击输入区域时触发 | - |
| bind:linechange | 输入框行数变化时调用,只对 textarea 有效 | event.detail = { height: 0, heightRpx: 0, lineCount: 0 } | | bind:linechange | 输入框行数变化时调用,只对 textarea 有效 | event.detail = { height: 0, heightRpx: 0, lineCount: 0 } |
| bind:keyboardheightchange | 键盘高度发生变化的时候触发此事件 | event.detail = { height: height, duration: duration } | | bind:keyboardheightchange | 键盘高度发生变化的时候触发此事件 | event.detail = { height: height, duration: duration } |
### Slot ### Slot
| 名称 | 说明 | | 名称 | 说明 |
| ---------- | ----------------------------------------------- | | ---------- | ---------------------------------------------------------- |
| label | 自定义输入框标签,如果设置了`label`属性则不生效 | | label | 自定义输入框标签,如果设置了`label`属性则不生效 |
| left-icon | 自定义输入框头部图标 | | left-icon | 自定义输入框头部图标 |
| right-icon | 自定义输入框尾部图标 | | right-icon | 自定义输入框尾部图标 |
| button | 自定义输入框尾部按钮 | | button | 自定义输入框尾部按钮 |
| input | 自定义输入框,使用此插槽后,与输入框相关的属性和事件将失效 |
### 外部样式类 ### 外部样式类

View File

@ -24,9 +24,13 @@
} }
} }
&__input { &__control:empty + &__control {
position: relative;
display: block; display: block;
}
&__control {
position: relative;
display: none;
box-sizing: border-box; box-sizing: border-box;
width: 100%; width: 100%;
margin: 0; margin: 0;
@ -36,10 +40,15 @@
background-color: transparent; background-color: transparent;
border: 0; border: 0;
resize: none; resize: none;
.theme(color, '@field-input-text-color'); .theme(color, '@field-input-text-color');
.theme(height, '@cell-line-height'); .theme(height, '@cell-line-height');
.theme(min-height, '@cell-line-height'); .theme(min-height, '@cell-line-height');
&:empty {
display: none;
}
&--textarea { &--textarea {
.theme(height, '@field-text-area-min-height'); .theme(height, '@field-text-area-min-height');
.theme(min-height, '@field-text-area-min-height'); .theme(min-height, '@field-text-area-min-height');
@ -62,6 +71,13 @@
&--right { &--right {
text-align: right; text-align: right;
} }
&--custom {
display: flex;
align-items: center;
.theme(min-height, '@cell-line-height');
}
} }
&__placeholder { &__placeholder {

View File

@ -1,3 +1,4 @@
import { nextTick } from '../common/utils';
import { VantComponent } from '../common/component'; import { VantComponent } from '../common/component';
import { commonProps, inputProps, textareaProps } from './props'; import { commonProps, inputProps, textareaProps } from './props';
@ -86,12 +87,16 @@ VantComponent({
this.$emit('click-icon'); this.$emit('click-icon');
}, },
onClickInput(event: WechatMiniprogram.TouchEvent) {
this.$emit('click-input', event.detail);
},
onClear() { onClear() {
this.setData({ innerValue: '' }); this.setData({ innerValue: '' });
this.value = ''; this.value = '';
this.setShowClear(); this.setShowClear();
wx.nextTick(() => { nextTick(() => {
this.emitChange(); this.emitChange();
this.$emit('clear', ''); this.$emit('clear', '');
}); });
@ -132,7 +137,7 @@ VantComponent({
emitChange() { emitChange() {
this.setData({ value: this.value }); this.setData({ value: this.value });
wx.nextTick(() => { nextTick(() => {
this.$emit('input', this.value); this.$emit('input', this.value);
this.$emit('change', this.value); this.$emit('change', this.value);
}); });
@ -141,6 +146,7 @@ VantComponent({
setShowClear() { setShowClear() {
const { clearable, readonly } = this.data; const { clearable, readonly } = this.data;
const { focused, value } = this; const { focused, value } = this;
this.setData({ this.setData({
showClear: !!clearable && !!focused && !!value && !readonly, showClear: !!clearable && !!focused && !!value && !readonly,
}); });

View File

@ -21,63 +21,12 @@
</view> </view>
<slot wx:else name="label" slot="title" /> <slot wx:else name="label" slot="title" />
<view class="{{ utils.bem('field__body', [type]) }}"> <view class="{{ utils.bem('field__body', [type]) }}">
<textarea <view class="{{ utils.bem('field__control', [inputAlign, 'custom']) }}" bindtap="onClickInput">
wx:if="{{ type === 'textarea' }}" <slot name="input" />
class="input-class {{ utils.bem('field__input', [inputAlign, type, { disabled, error }]) }}" </view>
fixed="{{ fixed }}" <include wx:if="{{ type === 'textarea' }}" src="textarea.wxml" />
focus="{{ focus }}" <include wx:else src="input.wxml" />
cursor="{{ cursor }}"
value="{{ innerValue }}"
auto-focus="{{ autoFocus }}"
disabled="{{ disabled || readonly }}"
maxlength="{{ maxlength }}"
placeholder="{{ placeholder }}"
placeholder-style="{{ placeholderStyle }}"
placeholder-class="{{ utils.bem('field__placeholder', { error, disabled }) }}"
auto-height="{{ !!autosize }}"
style="{{ computed.inputStyle(autosize) }}"
cursor-spacing="{{ cursorSpacing }}"
adjust-position="{{ adjustPosition }}"
show-confirm-bar="{{ showConfirmBar }}"
hold-keyboard="{{ holdKeyboard }}"
selection-end="{{ selectionEnd }}"
selection-start="{{ selectionStart }}"
disable-default-padding="{{ disableDefaultPadding }}"
bindinput="onInput"
bindblur="onBlur"
bindfocus="onFocus"
bindconfirm="onConfirm"
bindlinechange="onLineChange"
bindkeyboardheightchange="onKeyboardHeightChange"
>
</textarea>
<input
wx:else
class="input-class {{ utils.bem('field__input', [inputAlign, { disabled, error }]) }}"
type="{{ type }}"
focus="{{ focus }}"
cursor="{{ cursor }}"
value="{{ innerValue }}"
auto-focus="{{ autoFocus }}"
disabled="{{ disabled || readonly }}"
maxlength="{{ maxlength }}"
placeholder="{{ placeholder }}"
placeholder-style="{{ placeholderStyle }}"
placeholder-class="{{ utils.bem('field__placeholder', { error }) }}"
confirm-type="{{ confirmType }}"
confirm-hold="{{ confirmHold }}"
hold-keyboard="{{ holdKeyboard }}"
cursor-spacing="{{ cursorSpacing }}"
adjust-position="{{ adjustPosition }}"
selection-end="{{ selectionEnd }}"
selection-start="{{ selectionStart }}"
password="{{ password || type === 'password' }}"
bindinput="onInput"
bindblur="onBlur"
bindfocus="onFocus"
bindconfirm="onConfirm"
bindkeyboardheightchange="onKeyboardHeightChange"
/>
<van-icon <van-icon
wx:if="{{ showClear }}" wx:if="{{ showClear }}"
name="clear" name="clear"

27
packages/field/input.wxml Normal file
View File

@ -0,0 +1,27 @@
<input
class="{{ utils.bem('field__control', [inputAlign, { disabled, error }]) }} input-class"
type="{{ type }}"
focus="{{ focus }}"
cursor="{{ cursor }}"
value="{{ innerValue }}"
auto-focus="{{ autoFocus }}"
disabled="{{ disabled || readonly }}"
maxlength="{{ maxlength }}"
placeholder="{{ placeholder }}"
placeholder-style="{{ placeholderStyle }}"
placeholder-class="{{ utils.bem('field__placeholder', { error }) }}"
confirm-type="{{ confirmType }}"
confirm-hold="{{ confirmHold }}"
hold-keyboard="{{ holdKeyboard }}"
cursor-spacing="{{ cursorSpacing }}"
adjust-position="{{ adjustPosition }}"
selection-end="{{ selectionEnd }}"
selection-start="{{ selectionStart }}"
password="{{ password || type === 'password' }}"
bindinput="onInput"
bindtap="onClickInput"
bindblur="onBlur"
bindfocus="onFocus"
bindconfirm="onConfirm"
bindkeyboardheightchange="onKeyboardHeightChange"
/>

View File

@ -1,7 +1,7 @@
export const commonProps = { export const commonProps: WechatMiniprogram.Component.PropertyOption = {
value: { value: {
type: String, type: String,
observer(this: WechatMiniprogram.Component.TrivialInstance, value: string) { observer(this: WechatMiniprogram.Component.TrivialInstance, value) {
if (value !== this.value) { if (value !== this.value) {
this.setData({ innerValue: value }); this.setData({ innerValue: value });
this.value = value; this.value = value;
@ -41,7 +41,7 @@ export const commonProps = {
holdKeyboard: Boolean, holdKeyboard: Boolean,
}; };
export const inputProps = { export const inputProps: WechatMiniprogram.Component.PropertyOption = {
type: { type: {
type: String, type: String,
value: 'text', value: 'text',
@ -51,7 +51,7 @@ export const inputProps = {
confirmHold: Boolean, confirmHold: Boolean,
}; };
export const textareaProps = { export const textareaProps: WechatMiniprogram.Component.PropertyOption = {
autoHeight: Boolean, autoHeight: Boolean,
fixed: Boolean, fixed: Boolean,
showConfirmBar: { showConfirmBar: {

View File

@ -0,0 +1,29 @@
<textarea
class="{{ utils.bem('field__control', [inputAlign, type, { disabled, error }]) }} input-class"
fixed="{{ fixed }}"
focus="{{ focus }}"
cursor="{{ cursor }}"
value="{{ innerValue }}"
auto-focus="{{ autoFocus }}"
disabled="{{ disabled || readonly }}"
maxlength="{{ maxlength }}"
placeholder="{{ placeholder }}"
placeholder-style="{{ placeholderStyle }}"
placeholder-class="{{ utils.bem('field__placeholder', { error, disabled }) }}"
auto-height="{{ !!autosize }}"
style="{{ computed.inputStyle(autosize) }}"
cursor-spacing="{{ cursorSpacing }}"
adjust-position="{{ adjustPosition }}"
show-confirm-bar="{{ showConfirmBar }}"
hold-keyboard="{{ holdKeyboard }}"
selection-end="{{ selectionEnd }}"
selection-start="{{ selectionStart }}"
disable-default-padding="{{ disableDefaultPadding }}"
bindinput="onInput"
bindtap="onClickInput"
bindblur="onBlur"
bindfocus="onFocus"
bindconfirm="onConfirm"
bindlinechange="onLineChange"
bindkeyboardheightchange="onKeyboardHeightChange"
/>