[improvement] rename packages dir to src (#3659)

This commit is contained in:
neverland
2019-06-27 11:25:57 +08:00
committed by GitHub
parent 8489918dca
commit 75c79b7044
619 changed files with 21 additions and 21 deletions
+111
View File
@@ -0,0 +1,111 @@
<template>
<demo-section>
<van-cell
center
:title="$t('basicUsage')"
>
<van-stepper v-model="stepper1" />
</van-cell>
<van-cell
center
:title="$t('step')"
>
<van-stepper
v-model="stepper2"
step="2"
/>
</van-cell>
<van-cell
center
:title="$t('range')"
>
<van-stepper
v-model="stepper3"
:min="5"
:max="8"
/>
</van-cell>
<van-cell
center
:title="$t('integer')"
>
<van-stepper
v-model="stepper4"
integer
/>
</van-cell>
<van-cell
center
:title="$t('disabled')"
>
<van-stepper
v-model="stepper5"
disabled
/>
</van-cell>
<van-cell
center
:title="$t('asyncChange')"
>
<van-stepper
:value="stepper6"
async-change
@change="onChange"
/>
</van-cell>
</demo-section>
</template>
<script>
export default {
i18n: {
'zh-CN': {
step: '步长设置',
range: '限制输入范围',
integer: '限制输入整数',
asyncChange: '异步变更'
},
'en-US': {
step: 'Step',
range: 'Range',
integer: 'Integer',
asyncChange: 'Async Change',
}
},
data() {
return {
stepper1: 1,
stepper2: 1,
stepper3: 1,
stepper4: 1,
stepper5: 1,
stepper6: 1
};
},
methods: {
onChange(value) {
this.$toast.loading({ forbidClick: true });
setTimeout(() => {
this.stepper6 = value;
this.$toast.clear();
}, 500);
}
}
};
</script>
<style lang="less">
.demo-stepper {
.van-stepper {
margin-left: 15px;
}
}
</style>
+109
View File
@@ -0,0 +1,109 @@
# Stepper
### Install
``` javascript
import { Stepper } from 'vant';
Vue.use(Stepper);
```
## Usage
### Basic Usage
```html
<van-stepper v-model="value" />
```
```javascript
export default {
data() {
return {
value: 1
}
}
}
```
### Step
```html
<van-stepper v-model="value" step="2" />
```
### Range
```html
<van-stepper v-model="value" min="5" max="8" />
```
### Integer
```html
<van-stepper v-model="value" integer />
```
### Disabled
```html
<van-stepper v-model="value" disabled />
```
### Async Change
```html
<van-stepper
:value="value"
async-change
@change="onChange"
/>
```
```javascript
export default {
data() {
return {
value: 1
}
},
methods: {
onChange(value) {
Toast.loading({ forbidClick: true });
setTimeout(() => {
Toast.claer();
this.value = value;
}, 500);
}
}
}
```
## API
### Props
| Attribute | Description | Type | Default |
|------|------|------|------|
| v-model | Current value | `String | Number` | Min value |
| min | Min value | `String | Number` | `1` |
| max | Max value | `String | Number` | - |
| step | Value change step | `String | Number` | `1` |
| integer | Whether to allow only integers | `Boolean` | `false` |
| disabled | Disable value change | `Boolean` | `false` |
| disable-input | Disable input | `Boolean` | `false` |
| async-change | Whether to enable async change | `Boolean` | `false` | - |
| input-width | Input width | `String | Number` | `30px` |
### Events
| Event | Description | Arguments |
|------|------|------|
| change | Triggered when value change | value: current value |
| overlimit | Triggered when click disabled button | - |
| plus | Triggered when click plus button | - |
| minus | Triggered when click minus button | - |
| focus | Triggered when input focused | - |
| blur | Triggered when input blured | - |
+158
View File
@@ -0,0 +1,158 @@
import { createNamespace, isDef, suffixPx } from '../utils';
const [createComponent, bem] = createNamespace('stepper');
export default createComponent({
props: {
value: null,
integer: Boolean,
disabled: Boolean,
inputWidth: [String, Number],
asyncChange: Boolean,
disableInput: Boolean,
min: {
type: [String, Number],
default: 1
},
max: {
type: [String, Number],
default: Infinity
},
step: {
type: [String, Number],
default: 1
},
defaultValue: {
type: [String, Number],
default: 1
}
},
data() {
const value = this.range(isDef(this.value) ? this.value : this.defaultValue);
if (value !== +this.value) {
this.$emit('input', value);
}
return {
currentValue: value
};
},
computed: {
minusDisabled() {
return this.disabled || this.currentValue <= this.min;
},
plusDisabled() {
return this.disabled || this.currentValue >= this.max;
}
},
watch: {
value(val) {
if (val !== this.currentValue) {
this.currentValue = this.format(val);
}
},
currentValue(val) {
this.$emit('input', val);
this.$emit('change', val);
}
},
methods: {
// filter illegal characters
format(value) {
value = String(value).replace(/[^0-9.-]/g, '');
return value === '' ? 0 : this.integer ? Math.floor(value) : +value;
},
// limit value range
range(value) {
return Math.max(Math.min(this.max, this.format(value)), this.min);
},
onInput(event) {
const { value } = event.target;
const formatted = this.format(value);
if (!this.asyncChange) {
if (+value !== formatted) {
event.target.value = formatted;
}
this.currentValue = formatted;
} else {
event.target.value = this.currentValue;
this.$emit('input', formatted);
this.$emit('change', formatted);
}
},
onChange(type) {
if (this[`${type}Disabled`]) {
this.$emit('overlimit', type);
return;
}
const diff = type === 'minus' ? -this.step : +this.step;
const value = Math.round((this.currentValue + diff) * 100) / 100;
if (!this.asyncChange) {
this.currentValue = this.range(value);
} else {
this.$emit('input', value);
this.$emit('change', value);
}
this.$emit(type);
},
onFocus(event) {
this.$emit('focus', event);
},
onBlur(event) {
this.currentValue = this.range(this.currentValue);
this.$emit('blur', event);
// fix edge case when input is empty and min is 0
if (this.currentValue === 0) {
event.target.value = this.currentValue;
}
}
},
render(h) {
const onChange = type => () => {
this.onChange(type);
};
return (
<div class={bem()}>
<button
class={bem('minus', { disabled: this.minusDisabled })}
onClick={onChange('minus')}
/>
<input
type="number"
role="spinbutton"
class={bem('input')}
value={this.currentValue}
aria-valuemax={this.max}
aria-valuemin={this.min}
aria-valuenow={this.currentValue}
disabled={this.disabled || this.disableInput}
style={{ width: suffixPx(this.inputWidth) }}
onInput={this.onInput}
onFocus={this.onFocus}
onBlur={this.onBlur}
/>
<button
class={bem('plus', { disabled: this.plusDisabled })}
onClick={onChange('plus')}
/>
</div>
);
}
});
+94
View File
@@ -0,0 +1,94 @@
@import '../style/var';
.van-stepper {
font-size: 0;
&__minus,
&__plus {
position: relative;
box-sizing: border-box;
width: 28px;
height: 28px;
margin: 1px;
padding: 5px;
color: @stepper-button-icon-color;
vertical-align: middle;
background-color: @stepper-background-color;
border: 0;
&::before {
width: 9px;
height: 1px;
}
&::after {
width: 1px;
height: 9px;
}
&::before,
&::after {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
background-color: currentColor;
content: '';
}
&:active {
background-color: @stepper-active-color;
}
&--disabled {
color: @stepper-button-disabled-icon-color;
background-color: @stepper-button-disabled-color;
&:active {
background-color: @stepper-button-disabled-color;
}
}
}
&__minus {
border-radius: @stepper-border-radius 0 0 @stepper-border-radius;
&::after {
display: none;
}
}
&__plus {
border-radius: 0 @stepper-border-radius @stepper-border-radius 0;
}
&__input {
box-sizing: content-box;
width: @stepper-input-width;
height: @stepper-input-height;
margin: 1px;
padding: 1px;
color: @stepper-input-text-color;
font-size: @stepper-input-font-size;
text-align: center;
vertical-align: middle;
background-color: @stepper-background-color;
border: 0;
border-width: 1px 0;
border-radius: 0;
-webkit-appearance: none;
&[disabled] {
color: @stepper-input-disabled-text-color;
background-color: @stepper-input-disabled-background-color;
}
}
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
margin: 0;
-webkit-appearance: none;
}
}
@@ -0,0 +1,42 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders demo correctly 1`] = `
<div>
<div class="van-cell van-cell--center">
<div class="van-cell__title"><span>基础用法</span></div>
<div class="van-cell__value">
<div class="van-stepper"><button class="van-stepper__minus van-stepper__minus--disabled"></button><input type="number" role="spinbutton" aria-valuemax="Infinity" aria-valuemin="1" aria-valuenow="1" class="van-stepper__input"><button class="van-stepper__plus"></button></div>
</div>
</div>
<div class="van-cell van-cell--center">
<div class="van-cell__title"><span>步长设置</span></div>
<div class="van-cell__value">
<div class="van-stepper"><button class="van-stepper__minus van-stepper__minus--disabled"></button><input type="number" role="spinbutton" aria-valuemax="Infinity" aria-valuemin="1" aria-valuenow="1" class="van-stepper__input"><button class="van-stepper__plus"></button></div>
</div>
</div>
<div class="van-cell van-cell--center">
<div class="van-cell__title"><span>限制输入范围</span></div>
<div class="van-cell__value">
<div class="van-stepper"><button class="van-stepper__minus van-stepper__minus--disabled"></button><input type="number" role="spinbutton" aria-valuemax="8" aria-valuemin="5" aria-valuenow="5" class="van-stepper__input"><button class="van-stepper__plus"></button></div>
</div>
</div>
<div class="van-cell van-cell--center">
<div class="van-cell__title"><span>限制输入整数</span></div>
<div class="van-cell__value">
<div class="van-stepper"><button class="van-stepper__minus van-stepper__minus--disabled"></button><input type="number" role="spinbutton" aria-valuemax="Infinity" aria-valuemin="1" aria-valuenow="1" class="van-stepper__input"><button class="van-stepper__plus"></button></div>
</div>
</div>
<div class="van-cell van-cell--center">
<div class="van-cell__title"><span>禁用状态</span></div>
<div class="van-cell__value">
<div class="van-stepper"><button class="van-stepper__minus van-stepper__minus--disabled"></button><input type="number" role="spinbutton" aria-valuemax="Infinity" aria-valuemin="1" aria-valuenow="1" disabled="disabled" class="van-stepper__input"><button class="van-stepper__plus van-stepper__plus--disabled"></button></div>
</div>
</div>
<div class="van-cell van-cell--center">
<div class="van-cell__title"><span>异步变更</span></div>
<div class="van-cell__value">
<div class="van-stepper"><button class="van-stepper__minus van-stepper__minus--disabled"></button><input type="number" role="spinbutton" aria-valuemax="Infinity" aria-valuemin="1" aria-valuenow="1" class="van-stepper__input"><button class="van-stepper__plus"></button></div>
</div>
</div>
</div>
`;
@@ -0,0 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`disable stepper input 1`] = `<div class="van-stepper"><button class="van-stepper__minus van-stepper__minus--disabled"></button><input type="number" role="spinbutton" aria-valuemax="Infinity" aria-valuemin="1" aria-valuenow="1" disabled="disabled" class="van-stepper__input"><button class="van-stepper__plus"></button></div>`;
exports[`disabled stepper 1`] = `<div class="van-stepper"><button class="van-stepper__minus van-stepper__minus--disabled"></button><input type="number" role="spinbutton" aria-valuemax="Infinity" aria-valuemin="1" aria-valuenow="1" disabled="disabled" class="van-stepper__input"><button class="van-stepper__plus van-stepper__plus--disabled"></button></div>`;
exports[`input width 1`] = `<div class="van-stepper"><button class="van-stepper__minus van-stepper__minus--disabled"></button><input type="number" role="spinbutton" aria-valuemax="Infinity" aria-valuemin="1" aria-valuenow="1" class="van-stepper__input" style="width: 10rem;"><button class="van-stepper__plus"></button></div>`;
+4
View File
@@ -0,0 +1,4 @@
import Demo from '../demo';
import demoTest from '../../../test/demo-test';
demoTest(Demo);
+119
View File
@@ -0,0 +1,119 @@
import Stepper from '..';
import { mount } from '../../../test/utils';
test('disabled stepper', () => {
const wrapper = mount(Stepper, {
propsData: {
disabled: true
}
});
expect(wrapper).toMatchSnapshot();
});
test('disable stepper input', () => {
const wrapper = mount(Stepper, {
propsData: {
disableInput: true
}
});
expect(wrapper).toMatchSnapshot();
});
test('click button', () => {
const wrapper = mount(Stepper, {
propsData: {
value: 1,
max: 2
}
});
const plus = wrapper.find('.van-stepper__plus');
const minus = wrapper.find('.van-stepper__minus');
plus.trigger('click');
plus.trigger('click');
minus.trigger('click');
minus.trigger('click');
expect(wrapper.emitted('input')).toEqual([[2], [1]]);
expect(wrapper.emitted('overlimit')).toEqual([['plus'], ['minus']]);
});
test('correct value when value is not correct', () => {
const wrapper = mount(Stepper, {
propsData: {
value: 50,
max: 30,
min: 10
}
});
const input = wrapper.find('input');
input.element.value = 1;
input.trigger('input');
input.element.value = 'abc';
input.trigger('input');
wrapper.setData({ value: 'abc' });
input.trigger('input');
wrapper.setData({ value: '' });
input.trigger('input');
wrapper.setData({ value: 40 });
input.trigger('input');
wrapper.setData({ value: 30 });
input.trigger('input');
expect(wrapper.emitted('input')).toEqual([[30], [1], [0], [40], [30]]);
});
test('only allow interger', () => {
const wrapper = mount(Stepper, {
propsData: {
integer: true
}
});
const input = wrapper.find('input');
input.element.value = '1.2';
input.trigger('input');
input.trigger('blur');
expect(wrapper.emitted('input')).toEqual([[1]]);
});
test('stepper focus', () => {
const wrapper = mount(Stepper);
const input = wrapper.find('input');
input.trigger('focus');
expect(wrapper.emitted('focus')).toBeTruthy();
});
test('stepper blur', () => {
const wrapper = mount(Stepper, {
propsData: {
value: 5,
min: 3
}
});
wrapper.vm.$on('input', value => {
wrapper.setProps({ value });
});
const input = wrapper.find('input');
input.trigger('blur');
input.element.value = '';
input.trigger('input');
input.trigger('blur');
expect(wrapper.emitted('input')).toEqual([[0], [3]]);
expect(wrapper.emitted('blur')).toBeTruthy();
});
test('input width', () => {
const wrapper = mount(Stepper, {
propsData: {
inputWidth: '10rem'
}
});
expect(wrapper).toMatchSnapshot();
});
+111
View File
@@ -0,0 +1,111 @@
# Stepper 步进器
### 引入
``` javascript
import { Stepper } from 'vant';
Vue.use(Stepper);
```
## 代码演示
### 基础用法
```html
<van-stepper v-model="value" />
```
```javascript
export default {
data() {
return {
value: 1
}
}
}
```
### 步长设置
```html
<van-stepper v-model="value" step="2" />
```
### 限制输入范围
```html
<van-stepper v-model="value" min="5" max="8" />
```
### 限制输入整数
```html
<van-stepper v-model="value" integer />
```
### 禁用状态
通过设置`disabled`属性来禁用 stepper
```html
<van-stepper v-model="value" disabled />
```
### 异步变更
```html
<van-stepper
:value="value"
async-change
@change="onChange"
/>
```
```javascript
export default {
data() {
return {
value: 1
}
},
methods: {
onChange(value) {
Toast.loading({ forbidClick: true });
setTimeout(() => {
Toast.claer();
this.value = value;
}, 500);
}
}
}
```
## API
### Props
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|------|------|------|------|------|
| v-model | 当前输入值 | `String | Number` | 最小值 | - |
| min | 最小值 | `String | Number` | `1` | - |
| max | 最大值 | `String | Number` | - | - |
| step | 步数 | `String | Number` | `1` | - |
| integer | 是否只允许输入整数 | `Boolean` | `false` | 1.1.1 |
| disabled | 是否禁用步进器 | `Boolean` | `false` | - |
| disable-input | 是否禁用输入框 | `Boolean` | `false` | - |
| async-change | 是否开启异步变更,开启后需要手动控制输入值 | `Boolean` | `false` | - |
| input-width | 输入框宽度,默认单位为`px` | `String | Number` | `30px` | 1.6.13 |
### Events
| 事件名 | 说明 | 回调参数 |
|------|------|------|
| change | 当绑定值变化时触发的事件 | 当前组件的值 |
| overlimit | 点击不可用的按钮时触发 | - |
| plus | 点击增加按钮时触发 | - |
| minus | 点击减少按钮时触发 | - |
| focus | 输入框聚焦时触发 | - |
| blur | 输入框失焦时触发 | - |