mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
feat(Field): add digit type (#5524)
This commit is contained in:
parent
47e326fb2a
commit
ac3808cd47
@ -37,12 +37,10 @@ Use `type` prop to custom different type fields.
|
|||||||
|
|
||||||
```html
|
```html
|
||||||
<van-field v-model="text" label="Text" />
|
<van-field v-model="text" label="Text" />
|
||||||
|
|
||||||
<van-field v-model="password" type="password" label="Password" />
|
|
||||||
|
|
||||||
<van-field v-model="number" type="number" label="Number" />
|
|
||||||
|
|
||||||
<van-field v-model="tel" type="tel" label="Phone" />
|
<van-field v-model="tel" type="tel" label="Phone" />
|
||||||
|
<van-field v-model="digit" type="digit" label="Digit" />
|
||||||
|
<van-field v-model="number" type="number" label="Number" />
|
||||||
|
<van-field v-model="password" type="password" label="Password" />
|
||||||
```
|
```
|
||||||
|
|
||||||
```js
|
```js
|
||||||
@ -50,8 +48,9 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
tel: '',
|
tel: '',
|
||||||
|
text: '',
|
||||||
|
digit: '',
|
||||||
number: '',
|
number: '',
|
||||||
username: '',
|
|
||||||
password: ''
|
password: ''
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -182,7 +181,7 @@ Textarea Field can be auto resize when has `autosize` prop
|
|||||||
|------|------|------|------|------|
|
|------|------|------|------|------|
|
||||||
| value | Field value | *string \| number* | - | - |
|
| value | Field value | *string \| number* | - | - |
|
||||||
| label | Field label | *string* | - | - |
|
| label | Field label | *string* | - | - |
|
||||||
| type | Input type, can be set to `tel` `number`<br>`textarea` `password` | *string* | `text` | - |
|
| type | Input type, can be set to `tel` `digit`<br>`number` `textarea` `password` | *string* | `text` | - |
|
||||||
| size | Size,can be set to `large` | *string* | - | - |
|
| size | Size,can be set to `large` | *string* | - | - |
|
||||||
| maxlength | Max length of value | *string \| number* | - | - |
|
| maxlength | Max length of value | *string \| number* | - | - |
|
||||||
| placeholder | Placeholder | *string* | - | - |
|
| placeholder | Placeholder | *string* | - | - |
|
||||||
|
@ -41,17 +41,16 @@ export default {
|
|||||||
根据`type`属性定义不同类型的输入框,默认值为`text`
|
根据`type`属性定义不同类型的输入框,默认值为`text`
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<!-- type="text" 可以输入任意文本 -->
|
<!-- 输入任意文本 -->
|
||||||
<van-field v-model="text" label="文本" />
|
<van-field v-model="text" label="文本" />
|
||||||
|
<!-- 输入手机号,调起手机号键盘 -->
|
||||||
<!-- type="password" 表示输入密码 -->
|
|
||||||
<van-field v-model="password" type="password" label="密码" />
|
|
||||||
|
|
||||||
<!-- type="number" 允许输入数字和小数点,调起全键盘 -->
|
|
||||||
<van-field v-model="number" type="number" label="数字" />
|
|
||||||
|
|
||||||
<!-- type="tel" 输入手机号,调起手机号键盘 -->
|
|
||||||
<van-field v-model="tel" type="tel" label="手机号" />
|
<van-field v-model="tel" type="tel" label="手机号" />
|
||||||
|
<!-- 允许输入整数,调起数字键盘 -->
|
||||||
|
<van-field v-model="digit" type="digit" label="整数" />
|
||||||
|
<!-- 允许输入数字,调起全键盘 -->
|
||||||
|
<van-field v-model="number" type="number" label="数字" />
|
||||||
|
<!-- 输入密码 -->
|
||||||
|
<van-field v-model="password" type="password" label="密码" />
|
||||||
```
|
```
|
||||||
|
|
||||||
```js
|
```js
|
||||||
@ -60,6 +59,7 @@ export default {
|
|||||||
return {
|
return {
|
||||||
tel: '',
|
tel: '',
|
||||||
text: '',
|
text: '',
|
||||||
|
digit: '',
|
||||||
number: '',
|
number: '',
|
||||||
password: ''
|
password: ''
|
||||||
};
|
};
|
||||||
@ -67,6 +67,8 @@ export default {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> Tips: digit 类型从 2.4.2 版本开始支持
|
||||||
|
|
||||||
### 禁用输入框
|
### 禁用输入框
|
||||||
|
|
||||||
通过`readonly`将输入框设置为只读状态,通过`disabled`将输入框设置为禁用状态
|
通过`readonly`将输入框设置为只读状态,通过`disabled`将输入框设置为禁用状态
|
||||||
@ -197,7 +199,7 @@ export default {
|
|||||||
|------|------|------|------|------|
|
|------|------|------|------|------|
|
||||||
| label | 输入框左侧文本 | *string* | - | - |
|
| label | 输入框左侧文本 | *string* | - | - |
|
||||||
| value | 当前输入的值 | *string \| number* | - | - |
|
| value | 当前输入的值 | *string \| number* | - | - |
|
||||||
| type | 输入框类型, 可选值为 `tel` `number`<br>`textarea` `password` 等 | *string* | `text` | - |
|
| type | 输入框类型, 可选值为 `tel` `digit`<br>`number` `textarea` `password` 等 | *string* | `text` | - |
|
||||||
| size | 大小,可选值为 `large` | *string* | - | - |
|
| size | 大小,可选值为 `large` | *string* | - | - |
|
||||||
| maxlength | 输入的最大字符数 | *string \| number* | - | - |
|
| maxlength | 输入的最大字符数 | *string \| number* | - | - |
|
||||||
| placeholder | 占位提示文字 | *string* | - | - |
|
| placeholder | 占位提示文字 | *string* | - | - |
|
||||||
|
@ -15,10 +15,17 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<van-field
|
<van-field
|
||||||
v-model="password"
|
v-model="phone"
|
||||||
type="password"
|
type="tel"
|
||||||
:label="$t('password')"
|
:label="$t('phone')"
|
||||||
:placeholder="$t('passwordPlaceholder')"
|
:placeholder="$t('phonePlaceholder')"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<van-field
|
||||||
|
v-model="digit"
|
||||||
|
type="digit"
|
||||||
|
:label="$t('digit')"
|
||||||
|
:placeholder="$t('digitPlaceholder')"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<van-field
|
<van-field
|
||||||
@ -29,10 +36,10 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<van-field
|
<van-field
|
||||||
v-model="phone"
|
v-model="password"
|
||||||
type="tel"
|
type="password"
|
||||||
:label="$t('phone')"
|
:label="$t('password')"
|
||||||
:placeholder="$t('phonePlaceholder')"
|
:placeholder="$t('passwordPlaceholder')"
|
||||||
/>
|
/>
|
||||||
</van-cell-group>
|
</van-cell-group>
|
||||||
</demo-block>
|
</demo-block>
|
||||||
@ -141,6 +148,7 @@ export default {
|
|||||||
sms: '短信验证码',
|
sms: '短信验证码',
|
||||||
tel: '手机号',
|
tel: '手机号',
|
||||||
text: '文本',
|
text: '文本',
|
||||||
|
digit: '整数',
|
||||||
phone: '手机号',
|
phone: '手机号',
|
||||||
number: '数字',
|
number: '数字',
|
||||||
message: '留言',
|
message: '留言',
|
||||||
@ -151,7 +159,8 @@ export default {
|
|||||||
textareaAutosize: '高度自适应',
|
textareaAutosize: '高度自适应',
|
||||||
smsPlaceholder: '请输入短信验证码',
|
smsPlaceholder: '请输入短信验证码',
|
||||||
textPlaceholder: '请输入文本',
|
textPlaceholder: '请输入文本',
|
||||||
numberPlaceholder: '请输入数字',
|
digitPlaceholder: '请输入整数',
|
||||||
|
numberPlaceholder: '请输入数字(支持小数)',
|
||||||
phonePlaceholder: '请输入手机号',
|
phonePlaceholder: '请输入手机号',
|
||||||
messagePlaceholder: '请输入留言',
|
messagePlaceholder: '请输入留言',
|
||||||
inputReadonly: '输入框只读',
|
inputReadonly: '输入框只读',
|
||||||
@ -166,6 +175,7 @@ export default {
|
|||||||
sms: 'SMS',
|
sms: 'SMS',
|
||||||
tel: 'Tel',
|
tel: 'Tel',
|
||||||
text: 'Text',
|
text: 'Text',
|
||||||
|
digit: 'Digit',
|
||||||
phone: 'Phone',
|
phone: 'Phone',
|
||||||
number: 'Number',
|
number: 'Number',
|
||||||
message: 'Message',
|
message: 'Message',
|
||||||
@ -176,6 +186,7 @@ export default {
|
|||||||
textareaAutosize: 'Auto Resize',
|
textareaAutosize: 'Auto Resize',
|
||||||
smsPlaceholder: 'SMS',
|
smsPlaceholder: 'SMS',
|
||||||
textPlaceholder: 'Text',
|
textPlaceholder: 'Text',
|
||||||
|
digitPlaceholder: 'Digit',
|
||||||
phonePlaceholder: 'Phone',
|
phonePlaceholder: 'Phone',
|
||||||
numberPlaceholder: 'Number',
|
numberPlaceholder: 'Number',
|
||||||
messagePlaceholder: 'Message',
|
messagePlaceholder: 'Message',
|
||||||
@ -190,6 +201,7 @@ export default {
|
|||||||
sms: '',
|
sms: '',
|
||||||
text: '',
|
text: '',
|
||||||
value: '',
|
value: '',
|
||||||
|
digit: '',
|
||||||
number: '',
|
number: '',
|
||||||
icon1: '',
|
icon1: '',
|
||||||
icon2: '123',
|
icon2: '123',
|
||||||
|
@ -3,20 +3,12 @@ import Cell from '../cell';
|
|||||||
import { cellProps } from '../cell/shared';
|
import { cellProps } from '../cell/shared';
|
||||||
import { preventDefault } from '../utils/dom/event';
|
import { preventDefault } from '../utils/dom/event';
|
||||||
import { resetScroll } from '../utils/dom/reset-scroll';
|
import { resetScroll } from '../utils/dom/reset-scroll';
|
||||||
|
import { isIOS } from '../utils/validate/system';
|
||||||
|
import { formatNumber } from './utils';
|
||||||
import { createNamespace, isObj, isDef, addUnit } from '../utils';
|
import { createNamespace, isObj, isDef, addUnit } from '../utils';
|
||||||
|
|
||||||
const [createComponent, bem] = createNamespace('field');
|
const [createComponent, bem] = createNamespace('field');
|
||||||
|
|
||||||
function formatNumber(value) {
|
|
||||||
const dotIndex = value.indexOf('.');
|
|
||||||
|
|
||||||
if (dotIndex > -1) {
|
|
||||||
value = value.slice(0, dotIndex + 1) + value.slice(dotIndex).replace(/\./g, '');
|
|
||||||
}
|
|
||||||
|
|
||||||
return value.replace(/[^0-9.]/g, '');
|
|
||||||
}
|
|
||||||
|
|
||||||
export default createComponent({
|
export default createComponent({
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
|
|
||||||
@ -121,10 +113,11 @@ export default createComponent({
|
|||||||
target.value = value;
|
target.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.type === 'number') {
|
if (this.type === 'number' || this.type === 'digit') {
|
||||||
const originValue = value;
|
const originValue = value;
|
||||||
|
const allowDot = this.type === 'number';
|
||||||
|
|
||||||
value = formatNumber(value);
|
value = formatNumber(value, allowDot);
|
||||||
|
|
||||||
if (value !== originValue) {
|
if (value !== originValue) {
|
||||||
target.value = value;
|
target.value = value;
|
||||||
@ -213,6 +206,7 @@ export default createComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
genInput() {
|
genInput() {
|
||||||
|
const { type } = this;
|
||||||
const inputSlot = this.slots('input');
|
const inputSlot = this.slots('input');
|
||||||
|
|
||||||
if (inputSlot) {
|
if (inputSlot) {
|
||||||
@ -239,18 +233,34 @@ export default createComponent({
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.type === 'textarea') {
|
if (type === 'textarea') {
|
||||||
return <textarea {...inputProps} />;
|
return <textarea {...inputProps} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let inputType = type;
|
||||||
|
|
||||||
// type="number" is weired in iOS
|
// type="number" is weired in iOS
|
||||||
const inputType = this.type === 'number' ? 'text' : this.type;
|
if (type === 'number') {
|
||||||
|
inputType = 'text';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'digit') {
|
||||||
|
// set pattern to show number keyboard in iOS
|
||||||
|
if (isIOS()) {
|
||||||
|
inputType = 'number';
|
||||||
|
inputProps.attrs.pattern = '\\d*';
|
||||||
|
// cannot prevent dot when type is number in Android, so use tel
|
||||||
|
} else {
|
||||||
|
inputType = 'tel';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return <input type={inputType} {...inputProps} />;
|
return <input type={inputType} {...inputProps} />;
|
||||||
},
|
},
|
||||||
|
|
||||||
genLeftIcon() {
|
genLeftIcon() {
|
||||||
const showLeftIcon = this.slots('left-icon') || this.leftIcon;
|
const showLeftIcon = this.slots('left-icon') || this.leftIcon;
|
||||||
|
|
||||||
if (showLeftIcon) {
|
if (showLeftIcon) {
|
||||||
return (
|
return (
|
||||||
<div class={bem('left-icon')} onClick={this.onClickLeftIcon}>
|
<div class={bem('left-icon')} onClick={this.onClickLeftIcon}>
|
||||||
@ -263,6 +273,7 @@ export default createComponent({
|
|||||||
genRightIcon() {
|
genRightIcon() {
|
||||||
const { slots } = this;
|
const { slots } = this;
|
||||||
const showRightIcon = slots('right-icon') || this.rightIcon;
|
const showRightIcon = slots('right-icon') || this.rightIcon;
|
||||||
|
|
||||||
if (showRightIcon) {
|
if (showRightIcon) {
|
||||||
return (
|
return (
|
||||||
<div class={bem('right-icon')} onClick={this.onClickRightIcon}>
|
<div class={bem('right-icon')} onClick={this.onClickRightIcon}>
|
||||||
@ -289,6 +300,7 @@ export default createComponent({
|
|||||||
const scopedSlots = {
|
const scopedSlots = {
|
||||||
icon: this.genLeftIcon
|
icon: this.genLeftIcon
|
||||||
};
|
};
|
||||||
|
|
||||||
if (slots('label')) {
|
if (slots('label')) {
|
||||||
scopedSlots.title = () => slots('label');
|
scopedSlots.title = () => slots('label');
|
||||||
}
|
}
|
||||||
|
@ -20,21 +20,27 @@ exports[`renders demo correctly 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="van-cell van-field">
|
<div class="van-cell van-field">
|
||||||
<div class="van-cell__title van-field__label"><span>密码</span></div>
|
<div class="van-cell__title van-field__label"><span>手机号</span></div>
|
||||||
<div class="van-cell__value">
|
<div class="van-cell__value">
|
||||||
<div class="van-field__body"><input type="password" placeholder="请输入密码" class="van-field__control"></div>
|
<div class="van-field__body"><input type="tel" placeholder="请输入手机号" class="van-field__control"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="van-cell van-field">
|
||||||
|
<div class="van-cell__title van-field__label"><span>整数</span></div>
|
||||||
|
<div class="van-cell__value">
|
||||||
|
<div class="van-field__body"><input type="tel" placeholder="请输入整数" class="van-field__control"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="van-cell van-field">
|
<div class="van-cell van-field">
|
||||||
<div class="van-cell__title van-field__label"><span>数字</span></div>
|
<div class="van-cell__title van-field__label"><span>数字</span></div>
|
||||||
<div class="van-cell__value">
|
<div class="van-cell__value">
|
||||||
<div class="van-field__body"><input type="text" placeholder="请输入数字" class="van-field__control"></div>
|
<div class="van-field__body"><input type="text" placeholder="请输入数字(支持小数)" class="van-field__control"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="van-cell van-field">
|
<div class="van-cell van-field">
|
||||||
<div class="van-cell__title van-field__label"><span>手机号</span></div>
|
<div class="van-cell__title van-field__label"><span>密码</span></div>
|
||||||
<div class="van-cell__value">
|
<div class="van-cell__value">
|
||||||
<div class="van-field__body"><input type="tel" placeholder="请输入手机号" class="van-field__control"></div>
|
<div class="van-field__body"><input type="password" placeholder="请输入密码" class="van-field__control"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -56,6 +56,29 @@ test('number type', () => {
|
|||||||
expect(wrapper.emitted('input')[2][0]).toEqual('123');
|
expect(wrapper.emitted('input')[2][0]).toEqual('123');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('digit type', () => {
|
||||||
|
const wrapper = mount(Field, {
|
||||||
|
propsData: {
|
||||||
|
value: '',
|
||||||
|
type: 'digit'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const input = wrapper.find('input');
|
||||||
|
|
||||||
|
input.element.value = '1';
|
||||||
|
input.trigger('input');
|
||||||
|
expect(wrapper.emitted('input')[0][0]).toEqual('1');
|
||||||
|
|
||||||
|
input.element.value = '1.';
|
||||||
|
input.trigger('input');
|
||||||
|
expect(wrapper.emitted('input')[1][0]).toEqual('1');
|
||||||
|
|
||||||
|
input.element.value = '123abc';
|
||||||
|
input.trigger('input');
|
||||||
|
expect(wrapper.emitted('input')[2][0]).toEqual('123');
|
||||||
|
});
|
||||||
|
|
||||||
test('render textarea', async () => {
|
test('render textarea', async () => {
|
||||||
const wrapper = mount(Field, {
|
const wrapper = mount(Field, {
|
||||||
propsData: {
|
propsData: {
|
||||||
|
14
src/field/utils.ts
Normal file
14
src/field/utils.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
export function formatNumber(value: string, allowDot: boolean) {
|
||||||
|
if (allowDot) {
|
||||||
|
const dotIndex = value.indexOf('.');
|
||||||
|
|
||||||
|
if (dotIndex > -1) {
|
||||||
|
value =
|
||||||
|
value.slice(0, dotIndex + 1) + value.slice(dotIndex).replace(/\./g, '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const regExp = allowDot ? /[^0-9.]/g : /\D/g;
|
||||||
|
|
||||||
|
return value.replace(regExp, '');
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user