mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
add PasswordInput component
This commit is contained in:
parent
4c45b5eb39
commit
eb724555cb
88
docs/examples-docs/password-input.md
Normal file
88
docs/examples-docs/password-input.md
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
value: '',
|
||||||
|
showKeyboard: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
onInput(key) {
|
||||||
|
this.value = (this.value + key).slice(0, 6);
|
||||||
|
},
|
||||||
|
onDelete() {
|
||||||
|
this.value = this.value.slice(0, this.value.length - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
## PasswordInput 密码输入框
|
||||||
|
密码输入框组件通常与 [数字键盘](/zanui/vue/component/number-keyboard) 组件配合使用
|
||||||
|
|
||||||
|
### 使用指南
|
||||||
|
``` javascript
|
||||||
|
import { PasswordInput, NumberKeyBoard } from 'vant';
|
||||||
|
|
||||||
|
Vue.component(PasswordInput.name, PasswordInput);
|
||||||
|
Vue.component(NumberKeyBoard.name, NumberKeyBoard);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 代码演示
|
||||||
|
|
||||||
|
#### 基础用法
|
||||||
|
|
||||||
|
:::demo 基础用法
|
||||||
|
```html
|
||||||
|
<!-- 密码输入框 -->
|
||||||
|
<van-password-input
|
||||||
|
:value="value"
|
||||||
|
info="密码为 6 位数字"
|
||||||
|
@focus="showKeyboard = true"
|
||||||
|
></van-password-input>
|
||||||
|
|
||||||
|
<!-- 数字键盘 -->
|
||||||
|
<van-number-keyboard
|
||||||
|
:show="showKeyboard"
|
||||||
|
@input="onInput"
|
||||||
|
@delete="onDelete"
|
||||||
|
@blur="showKeyboard = false"
|
||||||
|
></van-number-keyboard>
|
||||||
|
```
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
value: '',
|
||||||
|
showKeyboard: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
onInput(key) {
|
||||||
|
this.value = (this.value + key).slice(0, 6);
|
||||||
|
},
|
||||||
|
onDelete() {
|
||||||
|
this.value = this.value.slice(0, this.value.length - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
:::
|
||||||
|
|
||||||
|
### API
|
||||||
|
|
||||||
|
| 参数 | 说明 | 类型 | 默认值 | 可选值 |
|
||||||
|
|-----------|-----------|-----------|-------------|-------------|
|
||||||
|
| value | 密码值 | `String` | `''` | - |
|
||||||
|
| length | 密码长度 | `Number` | `6` | - |
|
||||||
|
| info | 输入框下方提示 | `String` | - | - |
|
||||||
|
| errorInfo | 输入框下方错误提示 | `String` | - | - |
|
||||||
|
|
||||||
|
### Event
|
||||||
|
|
||||||
|
| 事件名 | 说明 | 参数 |
|
||||||
|
|-----------|-----------|-----------|
|
||||||
|
| focus | 输入框聚焦时触发 | - |
|
@ -147,6 +147,10 @@ module.exports = {
|
|||||||
"path": "/number-keyboard",
|
"path": "/number-keyboard",
|
||||||
"title": "NumberKeyboard 数字键盘"
|
"title": "NumberKeyboard 数字键盘"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"path": "/password-input",
|
||||||
|
"title": "PasswordInput 密码输入框"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "/radio",
|
"path": "/radio",
|
||||||
"title": "Radio 单选框"
|
"title": "Radio 单选框"
|
||||||
|
@ -26,6 +26,7 @@ import NavBar from './nav-bar';
|
|||||||
import NoticeBar from './notice-bar';
|
import NoticeBar from './notice-bar';
|
||||||
import NumberKeyboard from './number-keyboard';
|
import NumberKeyboard from './number-keyboard';
|
||||||
import Panel from './panel';
|
import Panel from './panel';
|
||||||
|
import PasswordInput from './password-input';
|
||||||
import Picker from './picker';
|
import Picker from './picker';
|
||||||
import Popup from './popup';
|
import Popup from './popup';
|
||||||
import Progress from './progress';
|
import Progress from './progress';
|
||||||
@ -78,6 +79,7 @@ const components = [
|
|||||||
NoticeBar,
|
NoticeBar,
|
||||||
NumberKeyboard,
|
NumberKeyboard,
|
||||||
Panel,
|
Panel,
|
||||||
|
PasswordInput,
|
||||||
Picker,
|
Picker,
|
||||||
Popup,
|
Popup,
|
||||||
Progress,
|
Progress,
|
||||||
@ -146,6 +148,7 @@ export {
|
|||||||
NoticeBar,
|
NoticeBar,
|
||||||
NumberKeyboard,
|
NumberKeyboard,
|
||||||
Panel,
|
Panel,
|
||||||
|
PasswordInput,
|
||||||
Picker,
|
Picker,
|
||||||
Popup,
|
Popup,
|
||||||
Progress,
|
Progress,
|
||||||
|
43
packages/password-input/index.vue
Normal file
43
packages/password-input/index.vue
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<template>
|
||||||
|
<div class="van-password-input">
|
||||||
|
<ul class="van-password-input__security van-hairline--surround" @touchstart.stop="$emit('focus')">
|
||||||
|
<li v-for="visibility in points" class="van-hairline">
|
||||||
|
<i :style="`visibility: ${visibility}`" />
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div
|
||||||
|
v-if="errorInfo || info"
|
||||||
|
v-text="errorInfo || info"
|
||||||
|
:class="errorInfo ? 'van-password-input__error-info' : 'van-password-input__info'"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'van-password-input',
|
||||||
|
|
||||||
|
props: {
|
||||||
|
info: String,
|
||||||
|
errorInfo: String,
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
length: {
|
||||||
|
type: Number,
|
||||||
|
default: 6
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
points() {
|
||||||
|
const arr = [];
|
||||||
|
for (let i = 0; i < this.length; i++) {
|
||||||
|
arr[i] = this.value[i] ? 'visible' : 'hidden';
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
@ -34,6 +34,7 @@
|
|||||||
@import './radio.css';
|
@import './radio.css';
|
||||||
@import './switch.css';
|
@import './switch.css';
|
||||||
@import './uploader.css';
|
@import './uploader.css';
|
||||||
|
@import './password-input.css';
|
||||||
@import './number-keyboard.css';
|
@import './number-keyboard.css';
|
||||||
|
|
||||||
/* action components */
|
/* action components */
|
||||||
|
59
packages/vant-css/src/password-input.css
Normal file
59
packages/vant-css/src/password-input.css
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
@import "./common/var.css";
|
||||||
|
|
||||||
|
.van-password-input {
|
||||||
|
margin: 0 15px;
|
||||||
|
user-select: none;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__info,
|
||||||
|
&__error-info {
|
||||||
|
font-size: 14px;
|
||||||
|
margin-top: 15px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__info {
|
||||||
|
color: $gray-dark;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__error-info {
|
||||||
|
color: $red;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__security {
|
||||||
|
width: 100%;
|
||||||
|
height: 50px;
|
||||||
|
display: flex;
|
||||||
|
background-color: $white;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
flex: 1;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&:not(:first-of-type)::after {
|
||||||
|
border-left-width: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
margin: -5px 0 0 -5px;
|
||||||
|
visibility: hidden;
|
||||||
|
border-radius: 100%;
|
||||||
|
background-color: $black;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
56
test/unit/specs/password-input.spec.js
Normal file
56
test/unit/specs/password-input.spec.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import PasswordInput from 'packages/password-input';
|
||||||
|
import { mount } from 'avoriaz';
|
||||||
|
|
||||||
|
describe('PasswordInput', () => {
|
||||||
|
let wrapper;
|
||||||
|
afterEach(() => {
|
||||||
|
wrapper && wrapper.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('create a PasswordInput', () => {
|
||||||
|
wrapper = mount(PasswordInput, {});
|
||||||
|
expect(wrapper.find('.van-password-input').length).to.equal(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('create a PasswordInput with value && info', (done) => {
|
||||||
|
wrapper = mount(PasswordInput, {
|
||||||
|
propsData: {
|
||||||
|
value: '000',
|
||||||
|
info: '测试info'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(wrapper.find('.van-password-input i')[2].hasStyle('visibility', 'visible')).to.be.true;
|
||||||
|
expect(wrapper.find('.van-password-input i')[3].hasStyle('visibility', 'visible')).to.be.false;
|
||||||
|
expect(wrapper.find('.van-password-input__info')[0].text()).to.equal('测试info');
|
||||||
|
|
||||||
|
wrapper.vm.value = '0000';
|
||||||
|
wrapper.vm.errorInfo = '测试errorInfo';
|
||||||
|
wrapper.vm.$nextTick(() => {
|
||||||
|
expect(wrapper.find('.van-password-input i')[3].hasStyle('visibility', 'visible')).to.be.true;
|
||||||
|
expect(wrapper.find('.van-password-input__info').length).to.equal(0);
|
||||||
|
expect(wrapper.find('.van-password-input__error-info')[0].text()).to.equal('测试errorInfo');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('listen to focus event', () => {
|
||||||
|
wrapper = mount(PasswordInput, {});
|
||||||
|
|
||||||
|
const focus = sinon.spy();
|
||||||
|
wrapper.vm.$on('focus', focus);
|
||||||
|
wrapper.find('.van-password-input__security')[0].trigger('touchstart');
|
||||||
|
|
||||||
|
expect(focus.calledOnce).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('change password length', () => {
|
||||||
|
wrapper = mount(PasswordInput, {
|
||||||
|
propsData: {
|
||||||
|
length: 2
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(wrapper.find('.van-password-input i').length).to.equal(2);
|
||||||
|
});
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user