[improvement] rename packages dir to src (#3659)
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
import { createNamespace } from '../utils';
|
||||
|
||||
const [createComponent, bem] = createNamespace('key');
|
||||
|
||||
export default createComponent({
|
||||
props: {
|
||||
type: String,
|
||||
theme: Array,
|
||||
text: [String, Number]
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
active: false
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
className() {
|
||||
const classNames = this.theme.slice(0);
|
||||
|
||||
if (this.active) {
|
||||
classNames.push('active');
|
||||
}
|
||||
|
||||
if (this.type) {
|
||||
classNames.push(this.type);
|
||||
}
|
||||
|
||||
return bem(classNames);
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onFocus() {
|
||||
this.active = true;
|
||||
},
|
||||
|
||||
onBlur(event) {
|
||||
this.active = false;
|
||||
},
|
||||
|
||||
onClick() {
|
||||
this.$emit('press', this.text, this.type);
|
||||
}
|
||||
},
|
||||
|
||||
render(h) {
|
||||
const { onBlur } = this;
|
||||
return (
|
||||
<i
|
||||
role="button"
|
||||
tabindex="0"
|
||||
class={['van-hairline', this.className]}
|
||||
onClick={this.onClick}
|
||||
onTouchstart={this.onFocus}
|
||||
onTouchmove={onBlur}
|
||||
onTouchend={onBlur}
|
||||
onTouchcancel={onBlur}
|
||||
>
|
||||
{this.slots('default') || this.text}
|
||||
</i>
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,112 @@
|
||||
<template>
|
||||
<demo-section>
|
||||
<demo-block :title="$t('default')">
|
||||
<van-button
|
||||
type="primary"
|
||||
@touchstart.stop="keyboard = 'default'"
|
||||
>
|
||||
{{ $t('button1') }}
|
||||
</van-button>
|
||||
|
||||
<van-number-keyboard
|
||||
:show="keyboard === 'default'"
|
||||
:close-button-text="$t('close')"
|
||||
extra-key="."
|
||||
safe-area-inset-bottom
|
||||
@blur="keyboard = ''"
|
||||
@input="onInput"
|
||||
@delete="onDelete"
|
||||
/>
|
||||
</demo-block>
|
||||
|
||||
<demo-block :title="$t('custom')">
|
||||
<van-button
|
||||
type="primary"
|
||||
@touchstart.stop="keyboard = 'custom'"
|
||||
>
|
||||
{{ $t('button2') }}
|
||||
</van-button>
|
||||
|
||||
<van-number-keyboard
|
||||
:show="keyboard === 'custom'"
|
||||
:close-button-text="$t('close')"
|
||||
theme="custom"
|
||||
extra-key="."
|
||||
safe-area-inset-bottom
|
||||
@blur="keyboard = ''"
|
||||
@input="onInput"
|
||||
@delete="onDelete"
|
||||
/>
|
||||
</demo-block>
|
||||
|
||||
<demo-block :title="$t('bindValue')">
|
||||
<van-field
|
||||
readonly
|
||||
clickable
|
||||
:value="value"
|
||||
:placeholder="$t('clickToInput')"
|
||||
@touchstart.native.stop="keyboard = 'bindValue'"
|
||||
/>
|
||||
|
||||
<van-number-keyboard
|
||||
v-model="value"
|
||||
:show="keyboard === 'bindValue'"
|
||||
maxlength="6"
|
||||
safe-area-inset-bottom
|
||||
@blur="keyboard = ''"
|
||||
/>
|
||||
</demo-block>
|
||||
</demo-section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
i18n: {
|
||||
'zh-CN': {
|
||||
default: '默认样式',
|
||||
custom: '自定义样式',
|
||||
button1: '弹出默认键盘',
|
||||
button2: '弹出自定义键盘',
|
||||
close: '完成',
|
||||
input: '输入',
|
||||
bindValue: '双向绑定',
|
||||
clickToInput: '点此输入'
|
||||
},
|
||||
'en-US': {
|
||||
default: 'Default style',
|
||||
custom: 'Custom style',
|
||||
button1: 'Show Default Keyboard',
|
||||
button2: 'Show Custom Keyboard',
|
||||
close: 'Close',
|
||||
input: 'Input',
|
||||
bindValue: 'Bind Value',
|
||||
clickToInput: 'Click To Input'
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
value: '',
|
||||
keyboard: 'default'
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
onInput(value) {
|
||||
this.$toast(`${this.$t('input')}: ${value}`);
|
||||
},
|
||||
|
||||
onDelete() {
|
||||
this.$toast(this.$t('delete'));
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.demo-number-keyboard {
|
||||
.van-button {
|
||||
margin-left: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,127 @@
|
||||
# NumberKeyboard
|
||||
|
||||
### Install
|
||||
``` javascript
|
||||
import { NumberKeyboard } from 'vant';
|
||||
|
||||
Vue.use(NumberKeyboard);
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Default Style
|
||||
|
||||
```html
|
||||
<van-button @touchstart.stop="show = true">
|
||||
Show Keyboard
|
||||
</van-button>
|
||||
|
||||
<van-number-keyboard
|
||||
:show="show"
|
||||
extra-key="."
|
||||
close-button-text="Close"
|
||||
@blur="show = false"
|
||||
@input="onInput"
|
||||
@delete="onDelete"
|
||||
/>
|
||||
```
|
||||
|
||||
```javascript
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
show: true
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onInput(value) {
|
||||
Toast(value);
|
||||
},
|
||||
onDelete() {
|
||||
Toast('delete');
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Custom Style
|
||||
|
||||
```html
|
||||
<van-number-keyboard
|
||||
:show="show"
|
||||
theme="custom"
|
||||
extra-key="."
|
||||
close-button-text="Close"
|
||||
@blur="show = false"
|
||||
@input="onInput"
|
||||
@delete="onDelete"
|
||||
/>
|
||||
```
|
||||
|
||||
### Bind Value
|
||||
|
||||
```html
|
||||
<van-field
|
||||
readonly
|
||||
clickable
|
||||
:value="value"
|
||||
@touchstart.native.stop="show = true"
|
||||
/>
|
||||
|
||||
<van-number-keyboard
|
||||
v-model="value"
|
||||
:show="show"
|
||||
:maxlength="6"
|
||||
@blur="show = false"
|
||||
/>
|
||||
```
|
||||
|
||||
```javascript
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
show: false,
|
||||
value: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Props
|
||||
|
||||
| Attribute | Description | Type | Default |
|
||||
|------|------|------|------|
|
||||
| v-model | Current value | `String` | - |
|
||||
| show | Whether to show keyboard | `Boolean` | - |
|
||||
| theme | Keyboard theme,can be set to `default` `custom` | `String` | `default` |
|
||||
| title | Keyboard title | `String` | - |
|
||||
| maxlength | Value maxlength | `Number | String` | - |
|
||||
| transition | Whether to show transition animation | `Boolean` | `true` |
|
||||
| z-index | Keyboard z-index | `Number` | `100` |
|
||||
| extra-key | Content of bottom left key | `String` | `''` |
|
||||
| close-button-text | Close button text | `String` | `-` |
|
||||
| delete-button-text | Delete button text | `String` | `delete` |
|
||||
| show-delete-key | Whether to show delete button | `Boolean` | `true` |
|
||||
| hide-on-click-outside | Whether to hide keyboard when click outside | `Boolean` | `true` |
|
||||
| safe-area-inset-bottom | Whether to enable bottom safe area adaptation, to enable those features use `viewport-fit=cover` in the `viewport` meta tag | `Boolean` | `false` |
|
||||
|
||||
### Events
|
||||
|
||||
| Event | Description | Arguments |
|
||||
|------|------|------|
|
||||
| input | Triggered when keydown | key: Content of the key |
|
||||
| delete | Triggered when press delete key | - |
|
||||
| blur | Triggered when click close button | - |
|
||||
| blur | Triggered when click close button or blur keyboard | - |
|
||||
| show | Triggered when keyboard is fully displayed. | - |
|
||||
| hide | Triggered when keyboard is fully hidden. | - |
|
||||
|
||||
### Slots
|
||||
|
||||
| Name | Description |
|
||||
|------|------|
|
||||
| delete | Custom delete button content |
|
||||
| title-left | Custom title left content |
|
||||
@@ -0,0 +1,199 @@
|
||||
import { createNamespace } from '../utils';
|
||||
import { stopPropagation } from '../utils/dom/event';
|
||||
import { BindEventMixin } from '../mixins/bind-event';
|
||||
import Key from './Key';
|
||||
|
||||
const [createComponent, bem, t] = createNamespace('number-keyboard');
|
||||
const CLOSE_KEY_THEME = ['blue', 'big'];
|
||||
const DELETE_KEY_THEME = ['delete', 'big', 'gray'];
|
||||
|
||||
export default createComponent({
|
||||
mixins: [
|
||||
BindEventMixin(function (bind) {
|
||||
if (this.hideOnClickOutside) {
|
||||
bind(document.body, 'touchstart', this.onBlur);
|
||||
}
|
||||
})
|
||||
],
|
||||
|
||||
model: {
|
||||
event: 'update:value'
|
||||
},
|
||||
|
||||
props: {
|
||||
show: Boolean,
|
||||
title: String,
|
||||
closeButtonText: String,
|
||||
deleteButtonText: String,
|
||||
safeAreaInsetBottom: Boolean,
|
||||
theme: {
|
||||
type: String,
|
||||
default: 'default'
|
||||
},
|
||||
value: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
extraKey: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
maxlength: {
|
||||
type: [Number, String],
|
||||
default: Number.MAX_VALUE
|
||||
},
|
||||
zIndex: {
|
||||
type: Number,
|
||||
default: 100
|
||||
},
|
||||
transition: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
showDeleteKey: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
hideOnClickOutside: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
show() {
|
||||
if (!this.transition) {
|
||||
this.$emit(this.show ? 'show' : 'hide');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
keys() {
|
||||
const keys = [];
|
||||
for (let i = 1; i <= 9; i++) {
|
||||
keys.push({ text: i });
|
||||
}
|
||||
|
||||
switch (this.theme) {
|
||||
case 'default':
|
||||
keys.push(
|
||||
{ text: this.extraKey, theme: ['gray'] },
|
||||
{ text: 0 },
|
||||
{ text: this.deleteText, theme: ['gray'], type: 'delete' }
|
||||
);
|
||||
break;
|
||||
case 'custom':
|
||||
keys.push({ text: 0, theme: ['middle'] }, { text: this.extraKey });
|
||||
break;
|
||||
}
|
||||
|
||||
return keys;
|
||||
},
|
||||
|
||||
deleteText() {
|
||||
return this.deleteButtonText || t('delete');
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onBlur() {
|
||||
this.$emit('blur');
|
||||
},
|
||||
|
||||
onClose() {
|
||||
this.$emit('close');
|
||||
this.onBlur();
|
||||
},
|
||||
|
||||
onAnimationEnd() {
|
||||
this.$emit(this.show ? 'show' : 'hide');
|
||||
},
|
||||
|
||||
onPress(text, type) {
|
||||
if (text === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
const { value } = this;
|
||||
|
||||
if (type === 'delete') {
|
||||
this.$emit('delete');
|
||||
this.$emit('update:value', value.slice(0, value.length - 1));
|
||||
} else if (type === 'close') {
|
||||
this.onClose();
|
||||
} else if (value.length < this.maxlength) {
|
||||
this.$emit('input', text);
|
||||
this.$emit('update:value', value + text);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
render(h) {
|
||||
const { title, theme, onPress, closeButtonText } = this;
|
||||
|
||||
const titleLeftSlot = this.slots('title-left');
|
||||
const showTitleClose = closeButtonText && theme === 'default';
|
||||
const showTitle = title || showTitleClose || titleLeftSlot;
|
||||
|
||||
const Title = showTitle && (
|
||||
<div class={[bem('title'), 'van-hairline--top']}>
|
||||
{titleLeftSlot && <span class={bem('title-left')}>{titleLeftSlot}</span>}
|
||||
{title && <span>{title}</span>}
|
||||
{showTitleClose && (
|
||||
<span role="button" tabindex="0" class={bem('close')} onClick={this.onClose}>
|
||||
{closeButtonText}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
const Keys = this.keys.map(key => (
|
||||
<Key
|
||||
key={key.text}
|
||||
text={key.text}
|
||||
type={key.type}
|
||||
theme={key.theme}
|
||||
onPress={onPress}
|
||||
>
|
||||
{key.type === 'delete' && this.slots('delete')}
|
||||
</Key>
|
||||
));
|
||||
|
||||
const Sidebar = theme === 'custom' && (
|
||||
<div class={bem('sidebar')}>
|
||||
<Key
|
||||
text={this.deleteText}
|
||||
type="delete"
|
||||
theme={DELETE_KEY_THEME}
|
||||
onPress={onPress}
|
||||
>
|
||||
{this.slots('delete')}
|
||||
</Key>
|
||||
<Key
|
||||
text={closeButtonText}
|
||||
type="close"
|
||||
theme={CLOSE_KEY_THEME}
|
||||
onPress={onPress}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<transition name={this.transition ? 'van-slide-up' : ''}>
|
||||
<div
|
||||
vShow={this.show}
|
||||
style={{ zIndex: this.zIndex }}
|
||||
class={bem([theme, { 'safe-area-inset-bottom': this.safeAreaInsetBottom }])}
|
||||
onTouchstart={stopPropagation}
|
||||
onAnimationend={this.onAnimationEnd}
|
||||
onWebkitAnimationEnd={this.onAnimationEnd}
|
||||
>
|
||||
{Title}
|
||||
<div class={bem('body')}>{Keys}</div>
|
||||
{Sidebar}
|
||||
</div>
|
||||
</transition>
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,115 @@
|
||||
@import '../style/var';
|
||||
|
||||
.van-number-keyboard {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background-color: @number-keyboard-background-color;
|
||||
animation-timing-function: ease-out;
|
||||
user-select: none;
|
||||
|
||||
&__title {
|
||||
position: relative;
|
||||
height: @number-keyboard-title-height;
|
||||
color: @number-keyboard-title-color;
|
||||
font-size: @number-keyboard-title-font-size;
|
||||
line-height: @number-keyboard-title-height;
|
||||
text-align: center;
|
||||
|
||||
&-left {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&__body {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
&__close {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
padding: @number-keyboard-close-padding;
|
||||
color: @number-keyboard-close-color;
|
||||
font-size: @number-keyboard-close-font-size;
|
||||
|
||||
&:active {
|
||||
background-color: @number-keyboard-key-active-color;
|
||||
}
|
||||
}
|
||||
|
||||
&__sidebar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 25%;
|
||||
height: @number-keyboard-key-height * 4;
|
||||
}
|
||||
|
||||
&--custom {
|
||||
.van-number-keyboard__body {
|
||||
padding-right: 25%;
|
||||
}
|
||||
}
|
||||
|
||||
&--safe-area-inset-bottom {
|
||||
padding-bottom: constant(safe-area-inset-bottom);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
}
|
||||
|
||||
.van-key {
|
||||
display: inline-block;
|
||||
width: 100% / 3;
|
||||
height: @number-keyboard-key-height;
|
||||
font-size: @number-keyboard-key-font-size;
|
||||
font-style: normal;
|
||||
line-height: @number-keyboard-key-height;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
|
||||
&::after {
|
||||
border-width: 1px 1px 0 0;
|
||||
}
|
||||
|
||||
&--middle {
|
||||
width: 200% / 3;
|
||||
}
|
||||
|
||||
&--big {
|
||||
width: 100%;
|
||||
height: @number-keyboard-key-height * 2;
|
||||
line-height: @number-keyboard-key-height * 2;
|
||||
}
|
||||
|
||||
&--blue,
|
||||
&--delete {
|
||||
font-size: @number-keyboard-delete-font-size;
|
||||
}
|
||||
|
||||
&--blue {
|
||||
color: @number-keyboard-button-text-color;
|
||||
background-color: @number-keyboard-button-background-color;
|
||||
|
||||
&.van-key--active {
|
||||
background-color: @number-keyboard-button-background-color;
|
||||
}
|
||||
|
||||
&::after {
|
||||
border-color: @number-keyboard-button-background-color;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: darken(@number-keyboard-button-background-color, 10%);
|
||||
}
|
||||
}
|
||||
|
||||
&--gray {
|
||||
background-color: @number-keyboard-key-background;
|
||||
}
|
||||
|
||||
&--active {
|
||||
background-color: @number-keyboard-key-active-color;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders demo correctly 1`] = `
|
||||
<div>
|
||||
<div><button class="van-button van-button--primary van-button--normal"><span class="van-button__text">
|
||||
弹出默认键盘
|
||||
</span></button>
|
||||
<div class="van-number-keyboard van-number-keyboard--default van-number-keyboard--safe-area-inset-bottom" style="z-index: 100;" name="van-slide-up">
|
||||
<div class="van-number-keyboard__title van-hairline--top"><span role="button" tabindex="0" class="van-number-keyboard__close">完成</span></div>
|
||||
<div class="van-number-keyboard__body"><i role="button" tabindex="0" class="van-hairline van-key">1</i><i role="button" tabindex="0" class="van-hairline van-key">2</i><i role="button" tabindex="0" class="van-hairline van-key">3</i><i role="button" tabindex="0" class="van-hairline van-key">4</i><i role="button" tabindex="0" class="van-hairline van-key">5</i><i role="button" tabindex="0" class="van-hairline van-key">6</i><i role="button" tabindex="0" class="van-hairline van-key">7</i><i role="button" tabindex="0" class="van-hairline van-key">8</i><i role="button" tabindex="0" class="van-hairline van-key">9</i><i role="button" tabindex="0" class="van-hairline van-key van-key--gray">.</i><i role="button" tabindex="0" class="van-hairline van-key">0</i><i role="button" tabindex="0" class="van-hairline van-key van-key--gray van-key--delete">删除</i></div>
|
||||
</div>
|
||||
</div>
|
||||
<div><button class="van-button van-button--primary van-button--normal"><span class="van-button__text">
|
||||
弹出自定义键盘
|
||||
</span></button>
|
||||
<div class="van-number-keyboard van-number-keyboard--custom van-number-keyboard--safe-area-inset-bottom" style="z-index: 100; display: none;" name="van-slide-up">
|
||||
<div class="van-number-keyboard__body"><i role="button" tabindex="0" class="van-hairline van-key">1</i><i role="button" tabindex="0" class="van-hairline van-key">2</i><i role="button" tabindex="0" class="van-hairline van-key">3</i><i role="button" tabindex="0" class="van-hairline van-key">4</i><i role="button" tabindex="0" class="van-hairline van-key">5</i><i role="button" tabindex="0" class="van-hairline van-key">6</i><i role="button" tabindex="0" class="van-hairline van-key">7</i><i role="button" tabindex="0" class="van-hairline van-key">8</i><i role="button" tabindex="0" class="van-hairline van-key">9</i><i role="button" tabindex="0" class="van-hairline van-key van-key--middle">0</i><i role="button" tabindex="0" class="van-hairline van-key">.</i></div>
|
||||
<div class="van-number-keyboard__sidebar"><i role="button" tabindex="0" class="van-hairline van-key van-key--delete van-key--big van-key--gray van-key--delete">删除</i><i role="button" tabindex="0" class="van-hairline van-key van-key--blue van-key--big van-key--close">完成</i></div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="van-cell van-cell--clickable van-field">
|
||||
<div class="van-cell__value van-cell__value--alone">
|
||||
<div class="van-field__body"><input type="text" placeholder="点此输入" readonly="readonly" class="van-field__control"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-number-keyboard van-number-keyboard--default van-number-keyboard--safe-area-inset-bottom" style="z-index: 100; display: none;" name="van-slide-up">
|
||||
<div class="van-number-keyboard__body"><i role="button" tabindex="0" class="van-hairline van-key">1</i><i role="button" tabindex="0" class="van-hairline van-key">2</i><i role="button" tabindex="0" class="van-hairline van-key">3</i><i role="button" tabindex="0" class="van-hairline van-key">4</i><i role="button" tabindex="0" class="van-hairline van-key">5</i><i role="button" tabindex="0" class="van-hairline van-key">6</i><i role="button" tabindex="0" class="van-hairline van-key">7</i><i role="button" tabindex="0" class="van-hairline van-key">8</i><i role="button" tabindex="0" class="van-hairline van-key">9</i><i role="button" tabindex="0" class="van-hairline van-key van-key--gray"></i><i role="button" tabindex="0" class="van-hairline van-key">0</i><i role="button" tabindex="0" class="van-hairline van-key van-key--gray van-key--delete">删除</i></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1,27 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`focus on key 1`] = `
|
||||
<div class="van-number-keyboard van-number-keyboard--default" style="z-index: 100; display: none;" name="van-slide-up">
|
||||
<div class="van-number-keyboard__body"><i role="button" tabindex="0" class="van-hairline van-key van-key--active">1</i><i role="button" tabindex="0" class="van-hairline van-key">2</i><i role="button" tabindex="0" class="van-hairline van-key">3</i><i role="button" tabindex="0" class="van-hairline van-key">4</i><i role="button" tabindex="0" class="van-hairline van-key">5</i><i role="button" tabindex="0" class="van-hairline van-key">6</i><i role="button" tabindex="0" class="van-hairline van-key">7</i><i role="button" tabindex="0" class="van-hairline van-key">8</i><i role="button" tabindex="0" class="van-hairline van-key">9</i><i role="button" tabindex="0" class="van-hairline van-key van-key--gray"></i><i role="button" tabindex="0" class="van-hairline van-key">0</i><i role="button" tabindex="0" class="van-hairline van-key van-key--gray van-key--delete">删除</i></div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`focus on key 2`] = `
|
||||
<div class="van-number-keyboard van-number-keyboard--default" style="z-index: 100; display: none;" name="van-slide-up">
|
||||
<div class="van-number-keyboard__body"><i role="button" tabindex="0" class="van-hairline van-key">1</i><i role="button" tabindex="0" class="van-hairline van-key">2</i><i role="button" tabindex="0" class="van-hairline van-key">3</i><i role="button" tabindex="0" class="van-hairline van-key">4</i><i role="button" tabindex="0" class="van-hairline van-key">5</i><i role="button" tabindex="0" class="van-hairline van-key">6</i><i role="button" tabindex="0" class="van-hairline van-key">7</i><i role="button" tabindex="0" class="van-hairline van-key">8</i><i role="button" tabindex="0" class="van-hairline van-key">9</i><i role="button" tabindex="0" class="van-hairline van-key van-key--gray"></i><i role="button" tabindex="0" class="van-hairline van-key">0</i><i role="button" tabindex="0" class="van-hairline van-key van-key--gray van-key--delete">删除</i></div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`render title 1`] = `
|
||||
<div class="van-number-keyboard van-number-keyboard--default" style="z-index: 100; display: none;" name="van-slide-up">
|
||||
<div class="van-number-keyboard__title van-hairline--top"><span>Title</span><span role="button" tabindex="0" class="van-number-keyboard__close">Close</span></div>
|
||||
<div class="van-number-keyboard__body"><i role="button" tabindex="0" class="van-hairline van-key">1</i><i role="button" tabindex="0" class="van-hairline van-key">2</i><i role="button" tabindex="0" class="van-hairline van-key">3</i><i role="button" tabindex="0" class="van-hairline van-key">4</i><i role="button" tabindex="0" class="van-hairline van-key">5</i><i role="button" tabindex="0" class="van-hairline van-key">6</i><i role="button" tabindex="0" class="van-hairline van-key">7</i><i role="button" tabindex="0" class="van-hairline van-key">8</i><i role="button" tabindex="0" class="van-hairline van-key">9</i><i role="button" tabindex="0" class="van-hairline van-key van-key--gray"></i><i role="button" tabindex="0" class="van-hairline van-key">0</i><i role="button" tabindex="0" class="van-hairline van-key van-key--gray van-key--delete">删除</i></div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`title-left slot 1`] = `
|
||||
<div class="van-number-keyboard van-number-keyboard--default" style="z-index: 100; display: none;" name="van-slide-up">
|
||||
<div class="van-number-keyboard__title van-hairline--top"><span class="van-number-keyboard__title-left">Custom Title Left</span></div>
|
||||
<div class="van-number-keyboard__body"><i role="button" tabindex="0" class="van-hairline van-key">1</i><i role="button" tabindex="0" class="van-hairline van-key">2</i><i role="button" tabindex="0" class="van-hairline van-key">3</i><i role="button" tabindex="0" class="van-hairline van-key">4</i><i role="button" tabindex="0" class="van-hairline van-key">5</i><i role="button" tabindex="0" class="van-hairline van-key">6</i><i role="button" tabindex="0" class="van-hairline van-key">7</i><i role="button" tabindex="0" class="van-hairline van-key">8</i><i role="button" tabindex="0" class="van-hairline van-key">9</i><i role="button" tabindex="0" class="van-hairline van-key van-key--gray"></i><i role="button" tabindex="0" class="van-hairline van-key">0</i><i role="button" tabindex="0" class="van-hairline van-key van-key--gray van-key--delete">删除</i></div>
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1,4 @@
|
||||
import Demo from '../demo';
|
||||
import demoTest from '../../../test/demo-test';
|
||||
|
||||
demoTest(Demo);
|
||||
@@ -0,0 +1,173 @@
|
||||
import NumberKeyboard from '..';
|
||||
import { mount, trigger } from '../../../test/utils';
|
||||
|
||||
test('click number key', () => {
|
||||
const wrapper = mount(NumberKeyboard, {
|
||||
propsData: {
|
||||
theme: 'custom',
|
||||
closeButtonText: 'close'
|
||||
}
|
||||
});
|
||||
|
||||
wrapper
|
||||
.findAll('.van-key')
|
||||
.at(0)
|
||||
.trigger('click');
|
||||
expect(wrapper.emitted('input')[0][0]).toEqual(1);
|
||||
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
it('click delete key', () => {
|
||||
const wrapper = mount(NumberKeyboard);
|
||||
wrapper
|
||||
.findAll('.van-key')
|
||||
.at(11)
|
||||
.trigger('click');
|
||||
expect(wrapper.emitted('delete')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('click empty key', () => {
|
||||
const wrapper = mount(NumberKeyboard);
|
||||
wrapper
|
||||
.findAll('.van-key')
|
||||
.at(9)
|
||||
.trigger('click');
|
||||
expect(wrapper.emitted('input')).toBeFalsy();
|
||||
});
|
||||
|
||||
test('click close button', () => {
|
||||
const wrapper = mount(NumberKeyboard, {
|
||||
propsData: {
|
||||
theme: 'custom',
|
||||
closeButtonText: 'close'
|
||||
}
|
||||
});
|
||||
|
||||
wrapper
|
||||
.findAll('.van-key')
|
||||
.at(12)
|
||||
.trigger('click');
|
||||
expect(wrapper.emitted('close')).toBeTruthy();
|
||||
});
|
||||
|
||||
test('listen to show/hide event when has transtion', () => {
|
||||
const wrapper = mount(NumberKeyboard);
|
||||
wrapper.vm.show = true;
|
||||
wrapper.trigger('animationend');
|
||||
wrapper.vm.show = false;
|
||||
wrapper.trigger('animationend');
|
||||
expect(wrapper.emitted('show')).toBeTruthy();
|
||||
expect(wrapper.emitted('hide')).toBeTruthy();
|
||||
});
|
||||
|
||||
test('listen to show event when no transtion', () => {
|
||||
const wrapper = mount(NumberKeyboard, {
|
||||
propsData: {
|
||||
transition: false
|
||||
}
|
||||
});
|
||||
wrapper.vm.show = true;
|
||||
wrapper.vm.show = false;
|
||||
expect(wrapper.emitted('show')).toBeTruthy();
|
||||
expect(wrapper.emitted('hide')).toBeTruthy();
|
||||
});
|
||||
|
||||
test('render title', () => {
|
||||
const wrapper = mount(NumberKeyboard, {
|
||||
propsData: {
|
||||
title: 'Title',
|
||||
closeButtonText: 'Close'
|
||||
}
|
||||
});
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('title-left slot', () => {
|
||||
const wrapper = mount(NumberKeyboard, {
|
||||
scopedSlots: {
|
||||
'title-left': () => 'Custom Title Left'
|
||||
}
|
||||
});
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('hideOnClickOutside', () => {
|
||||
const wrapper = mount(NumberKeyboard, {
|
||||
propsData: {
|
||||
show: true
|
||||
}
|
||||
});
|
||||
|
||||
trigger(document.body, 'touchstart');
|
||||
expect(wrapper.emitted('blur')).toBeTruthy();
|
||||
});
|
||||
|
||||
test('disable hideOnClickOutside', () => {
|
||||
const wrapper = mount(NumberKeyboard, {
|
||||
propsData: {
|
||||
show: true,
|
||||
hideOnClickOutside: false
|
||||
}
|
||||
});
|
||||
|
||||
trigger(document.body, 'touchstart');
|
||||
expect(wrapper.emitted('blur')).toBeFalsy();
|
||||
});
|
||||
|
||||
test('focus on key', () => {
|
||||
const wrapper = mount(NumberKeyboard);
|
||||
|
||||
const key = wrapper.find('.van-key');
|
||||
trigger(key, 'touchstart');
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
trigger(key, 'touchend');
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('bind value', () => {
|
||||
const wrapper = mount(NumberKeyboard, {
|
||||
propsData: {
|
||||
value: ''
|
||||
},
|
||||
listeners: {
|
||||
'update:value': value => {
|
||||
wrapper.setProps({ value });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const keys = wrapper.findAll('.van-key');
|
||||
keys.at(0).trigger('click');
|
||||
keys.at(1).trigger('click');
|
||||
|
||||
expect(wrapper.vm.value).toEqual('12');
|
||||
|
||||
keys.at(11).trigger('click');
|
||||
expect(wrapper.vm.value).toEqual('1');
|
||||
});
|
||||
|
||||
test('maxlength', () => {
|
||||
const onInput = jest.fn();
|
||||
const wrapper = mount(NumberKeyboard, {
|
||||
propsData: {
|
||||
value: '',
|
||||
maxlength: 1
|
||||
},
|
||||
listeners: {
|
||||
input: onInput,
|
||||
'update:value': value => {
|
||||
wrapper.setProps({ value });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const keys = wrapper.findAll('.van-key');
|
||||
keys.at(0).trigger('click');
|
||||
keys.at(1).trigger('click');
|
||||
|
||||
expect(wrapper.vm.value).toEqual('1');
|
||||
expect(onInput).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
@@ -0,0 +1,130 @@
|
||||
# NumberKeyboard 数字键盘
|
||||
|
||||
### 引入
|
||||
|
||||
``` javascript
|
||||
import { NumberKeyboard } from 'vant';
|
||||
|
||||
Vue.use(NumberKeyboard);
|
||||
```
|
||||
|
||||
## 代码演示
|
||||
|
||||
### 默认样式
|
||||
|
||||
```html
|
||||
<van-button @touchstart.stop="show = true">
|
||||
弹出默认键盘
|
||||
</van-button>
|
||||
|
||||
<van-number-keyboard
|
||||
:show="show"
|
||||
extra-key="."
|
||||
close-button-text="完成"
|
||||
@blur="show = false"
|
||||
@input="onInput"
|
||||
@delete="onDelete"
|
||||
/>
|
||||
```
|
||||
|
||||
```javascript
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
show: true
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onInput(value) {
|
||||
Toast(value);
|
||||
},
|
||||
onDelete() {
|
||||
Toast('删除');
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 自定义样式
|
||||
|
||||
```html
|
||||
<van-number-keyboard
|
||||
:show="show"
|
||||
theme="custom"
|
||||
extra-key="."
|
||||
close-button-text="完成"
|
||||
@blur="show = false"
|
||||
@input="onInput"
|
||||
@delete="onDelete"
|
||||
/>
|
||||
```
|
||||
|
||||
### 双向绑定
|
||||
|
||||
可以通过`v-model`绑定键盘当前输入值
|
||||
|
||||
```html
|
||||
<van-field
|
||||
readonly
|
||||
clickable
|
||||
:value="value"
|
||||
@touchstart.native.stop="show = true"
|
||||
/>
|
||||
|
||||
<van-number-keyboard
|
||||
v-model="value"
|
||||
:show="show"
|
||||
:maxlength="6"
|
||||
@blur="show = false"
|
||||
/>
|
||||
```
|
||||
|
||||
```javascript
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
show: false,
|
||||
value: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Props
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
|------|------|------|------|------|
|
||||
| v-model | 当前输入值 | `String` | - | 2.0.2 |
|
||||
| show | 是否显示键盘 | `Boolean` | - | - |
|
||||
| theme | 样式风格,可选值为 `default` `custom` | `String` | `default` | - |
|
||||
| title | 键盘标题 | `String` | - | - |
|
||||
| maxlength | 输入值最大长度 | `Number | String` | - | 2.0.2 |
|
||||
| transition | 是否开启过场动画 | `Boolean` | `true` | - |
|
||||
| z-index | 键盘 z-index | `Number` | `100` | - |
|
||||
| extra-key | 左下角按键内容 | `String` | `''` | - |
|
||||
| close-button-text | 关闭按钮文字,空则不展示 | `String` | `-` | - |
|
||||
| delete-button-text | 删除按钮文字 | `String` | `删除` | - |
|
||||
| show-delete-key | 是否展示删除按钮 | `Boolean` | `true` | - |
|
||||
| hide-on-click-outside | 点击外部时是否收起键盘 | `Boolean` | `true` | - |
|
||||
| safe-area-inset-bottom | 是否开启 iPhone X 底部安全区适配,需要在 `viewport` meta 标签中设置 `viewport-fit=cover` | `Boolean` | `false` | 1.6.15 |
|
||||
|
||||
### Events
|
||||
|
||||
| 事件名 | 说明 | 回调参数 |
|
||||
|------|------|------|
|
||||
| input | 点击按键时触发 | key: 按键内容 |
|
||||
| delete | 点击删除键时触发 | - |
|
||||
| close | 点击关闭按钮时触发 | - |
|
||||
| blur | 点击关闭按钮或非键盘区域时触发 | - |
|
||||
| show | 键盘完全弹出时触发 | - |
|
||||
| hide | 键盘完全收起时触发 | - |
|
||||
|
||||
### Slots
|
||||
|
||||
| 名称 | 说明 |
|
||||
|------|------|
|
||||
| delete | 自定义删除按钮内容 |
|
||||
| title-left | 自定义标题栏左侧内容 |
|
||||
Reference in New Issue
Block a user