最简单的处理方法,存在一个缺点,不支持将内容粘贴过来。
1、无法黏贴复制的内容
2、输入错误,需要都删掉在重新输入
3、粗的方法如下:
html
<van-field
v-else
v-model="cardNumber"
input-align="right"
label="身份证号"
readonly
placeholder="请输入身份证号"
style="margin-bottom: 40px"
maxlength="30"
@touchstart.stop="showCardIdBoard = true"
/>
<!-- 手动添加遮罩层:目的是为了防止下层单选点击选中。 同时:hide-on-click-outside="false" 设置为false -->
<div
:class="{'x-keyboard-overlay':showCardIdBoard}"
@click.stop="showCardIdBoard = false"
>
</div>
<van-number-keyboard
v-model="cardNumber"
:transition="false"
:title="cardNumber"
:show="showCardIdBoard"
extra-key="X"
:hide-on-click-outside="false"
close-button-text="完成"
@blur="showCardIdBoard = false"
/>
<van-field
v-else
v-model="cardNumber"
input-align="right"
label="身份证号"
readonly
placeholder="请输入身份证号"
style="margin-bottom: 40px"
maxlength="30"
@touchstart.stop="showCardIdBoard = true"
/>
<!-- 手动添加遮罩层:目的是为了防止下层单选点击选中。 同时:hide-on-click-outside="false" 设置为false -->
<div
:class="{'x-keyboard-overlay':showCardIdBoard}"
@click.stop="showCardIdBoard = false"
>
</div>
<van-number-keyboard
v-model="cardNumber"
:transition="false"
:title="cardNumber"
:show="showCardIdBoard"
extra-key="X"
:hide-on-click-outside="false"
close-button-text="完成"
@blur="showCardIdBoard = false"
/>
优化处理:
1、 为了避免光标存在时,弹出原生键盘,需要使用inputmode="none"
2、不在给键盘绑定数据,自己实现一套删除、修改的逻辑,同时处理光标的位置
3、将外部内容粘贴过来的时候,需要触发双向绑定
4、长按input框的时候,注意不要将键盘收起来(这里用的name进行区分当前光标组件 document.activeElement
和键盘组件是否是同一个)
5、新版组件可参考如下
``
java
<template>
<div>
<!-- 多嵌套一层div,防止出现底部border -->
<div>
<van-field
ref="idCardRef"
v-model="cardNumber"
:class="{'no_padding':noPadding}"
inputmode="none"
:name="name"
input-align="right"
:label="label"
:placeholder="placeholder"
maxlength="18"
@click="showKbTrigger(true)"
/>
</div>
<van-number-keyboard
:transition="true"
title="身份证号"
:show="showCardIdBoard"
extra-key="X"
:hide-on-click-outside="true"
close-button-text="完成"
@blur="keyboardClickCloseOrOut"
@input="onInput"
@delete="onDelete"
/>
</div>
</template>
<script>
export default {
name: 'IdKeyboard',
props: {
label: {
type: String,
default: '身份证号'
},
noPadding: {
type: Boolean,
default: false
},
name: {
type: String,
default: ''
},
placeholder: {
type: String,
default: '请输入身份证号'
},
value: {
type: String,
default: ''
},
show: {
type: Boolean,
default: false
}
},
data () {
return {
cardNumber: '',
showCardIdBoard: false
};
},
watch: {
value: {
handler (newVal) {
if (this.cardNumber !== newVal) {
this.cardNumber = newVal;
}
},
immediate: true
},
show: {
handler (newVal) {
this.showCardIdBoard = newVal;
},
immediate: true
},
// 如果复制过来的,也需要触发一下
cardNumber: {
handler (newVal) {
this.$emit('input', newVal);
}
}
},
methods: {
keyboardClickCloseOrOut () {
// @blur 点击关闭按钮或非键盘区域时触发.
// 1. 如果是input被点击触发,不收起键盘
setTimeout(() => {
this.$nextTick(() => {
if (document && document.activeElement && this.name && document.activeElement.name === this.name) {
// do nothing
} else {
this.showKbTrigger(false);
}
});
}, 200);
},
// 键盘相关的方法
showKbTrigger (show) {
this.showCardIdBoard = show;
this.$emit('update:show', show);
// 键盘展示的时候发送消息
if (show) {
this.$emit('showIdKeyboard');
} else {
this.$emit('hideIdKeyboard');
}
},
selectionIndex () {
const inputElement = this.$refs.idCardRef.$refs.input;
const startIndex = inputElement.selectionStart;
const endIndex = inputElement.selectionEnd;
return [inputElement, startIndex, endIndex];
},
onInput (e) {
const [inputElement, startIndex, endIndex] = this.selectionIndex();
this.cardNumber = this.addContentText(this.cardNumber, startIndex, endIndex, e);
// 还原光标位置
this.$nextTick(() => {
inputElement.setSelectionRange(startIndex + 1, startIndex + 1);
});
this.$emit('input', this.cardNumber);
},
addContentText (soure, start, end, newStr) {
// 开始位置 + 新字符串 + 尾部字符串
return soure.slice(0, start) + newStr + soure.slice(end);
},
onDelete () {
const [inputElement, startIndex, endIndex] = this.selectionIndex();
// 光标在最前,不进行操作
if (startIndex === endIndex && startIndex === 0) {
return;
}
if (startIndex === endIndex) {
// 删除一个字符
this.cardNumber = this.addContentText(this.cardNumber, startIndex - 1, endIndex, '');
// 还原光标位置
this.$nextTick(() => {
const toIndex = startIndex - 1 < 0 ? 0 : startIndex - 1;
inputElement.setSelectionRange(toIndex, toIndex);
});
} else {
// 删除多个字符
this.cardNumber = this.addContentText(this.cardNumber, startIndex, endIndex, '');
// 还原光标位置
this.$nextTick(() => {
inputElement.setSelectionRange(startIndex, startIndex);
});
}
this.$emit('input', this.cardNumber);
}
}
};
</script>
<style scoped lang="less">
/deep/ .van-number-keyboard__title {
font-size: 16px;
}
.no_padding {
padding: 0 !important;
}
</style>
<!--
使用 <id-keyboard v-model="cardNumber" name="xxxx"/>
需要传递一个特定的name,防止点击name的时候被意外收起键盘。
-->
<template>
<div>
<!-- 多嵌套一层div,防止出现底部border -->
<div>
<van-field
ref="idCardRef"
v-model="cardNumber"
:class="{'no_padding':noPadding}"
inputmode="none"
:name="name"
input-align="right"
:label="label"
:placeholder="placeholder"
maxlength="18"
@click="showKbTrigger(true)"
/>
</div>
<van-number-keyboard
:transition="true"
title="身份证号"
:show="showCardIdBoard"
extra-key="X"
:hide-on-click-outside="true"
close-button-text="完成"
@blur="keyboardClickCloseOrOut"
@input="onInput"
@delete="onDelete"
/>
</div>
</template>
<script>
export default {
name: 'IdKeyboard',
props: {
label: {
type: String,
default: '身份证号'
},
noPadding: {
type: Boolean,
default: false
},
name: {
type: String,
default: ''
},
placeholder: {
type: String,
default: '请输入身份证号'
},
value: {
type: String,
default: ''
},
show: {
type: Boolean,
default: false
}
},
data () {
return {
cardNumber: '',
showCardIdBoard: false
};
},
watch: {
value: {
handler (newVal) {
if (this.cardNumber !== newVal) {
this.cardNumber = newVal;
}
},
immediate: true
},
show: {
handler (newVal) {
this.showCardIdBoard = newVal;
},
immediate: true
},
// 如果复制过来的,也需要触发一下
cardNumber: {
handler (newVal) {
this.$emit('input', newVal);
}
}
},
methods: {
keyboardClickCloseOrOut () {
// @blur 点击关闭按钮或非键盘区域时触发.
// 1. 如果是input被点击触发,不收起键盘
setTimeout(() => {
this.$nextTick(() => {
if (document && document.activeElement && this.name && document.activeElement.name === this.name) {
// do nothing
} else {
this.showKbTrigger(false);
}
});
}, 200);
},
// 键盘相关的方法
showKbTrigger (show) {
this.showCardIdBoard = show;
this.$emit('update:show', show);
// 键盘展示的时候发送消息
if (show) {
this.$emit('showIdKeyboard');
} else {
this.$emit('hideIdKeyboard');
}
},
selectionIndex () {
const inputElement = this.$refs.idCardRef.$refs.input;
const startIndex = inputElement.selectionStart;
const endIndex = inputElement.selectionEnd;
return [inputElement, startIndex, endIndex];
},
onInput (e) {
const [inputElement, startIndex, endIndex] = this.selectionIndex();
this.cardNumber = this.addContentText(this.cardNumber, startIndex, endIndex, e);
// 还原光标位置
this.$nextTick(() => {
inputElement.setSelectionRange(startIndex + 1, startIndex + 1);
});
this.$emit('input', this.cardNumber);
},
addContentText (soure, start, end, newStr) {
// 开始位置 + 新字符串 + 尾部字符串
return soure.slice(0, start) + newStr + soure.slice(end);
},
onDelete () {
const [inputElement, startIndex, endIndex] = this.selectionIndex();
// 光标在最前,不进行操作
if (startIndex === endIndex && startIndex === 0) {
return;
}
if (startIndex === endIndex) {
// 删除一个字符
this.cardNumber = this.addContentText(this.cardNumber, startIndex - 1, endIndex, '');
// 还原光标位置
this.$nextTick(() => {
const toIndex = startIndex - 1 < 0 ? 0 : startIndex - 1;
inputElement.setSelectionRange(toIndex, toIndex);
});
} else {
// 删除多个字符
this.cardNumber = this.addContentText(this.cardNumber, startIndex, endIndex, '');
// 还原光标位置
this.$nextTick(() => {
inputElement.setSelectionRange(startIndex, startIndex);
});
}
this.$emit('input', this.cardNumber);
}
}
};
</script>
<style scoped lang="less">
/deep/ .van-number-keyboard__title {
font-size: 16px;
}
.no_padding {
padding: 0 !important;
}
</style>
<!--
使用 <id-keyboard v-model="cardNumber" name="xxxx"/>
需要传递一个特定的name,防止点击name的时候被意外收起键盘。
-->
其他可能存在的优化
1、 处理键盘遮挡的问题,仅参考
js
let element = this.$refs.fatherIdCardInputRef;
if (!element) {
return;
}
// 获取键盘高度
const minOffsetY = window.screen.width / 504 * 408;
// 当前组件距离widow顶部的高度(非scroll)
const top = element.getBoundingClientRect().top;
// 当前组件距离widow顶部的高度(非scroll)
const bottomY = window.screen.height - top;
if (minOffsetY > bottomY) {
// console.log('需要上移', minOffsetY - bottomY);
setTimeout(() => {
this.$nextTick(() => {
// 页面进行移动,调整到合适为止。 20是魔法数字,提供额外的间距
document.getElementById('app').scrollTop = document.getElementById('app').scrollTop + (minOffsetY - bottomY) + 20;
});
}, 100);
}
let element = this.$refs.fatherIdCardInputRef;
if (!element) {
return;
}
// 获取键盘高度
const minOffsetY = window.screen.width / 504 * 408;
// 当前组件距离widow顶部的高度(非scroll)
const top = element.getBoundingClientRect().top;
// 当前组件距离widow顶部的高度(非scroll)
const bottomY = window.screen.height - top;
if (minOffsetY > bottomY) {
// console.log('需要上移', minOffsetY - bottomY);
setTimeout(() => {
this.$nextTick(() => {
// 页面进行移动,调整到合适为止。 20是魔法数字,提供额外的间距
document.getElementById('app').scrollTop = document.getElementById('app').scrollTop + (minOffsetY - bottomY) + 20;
});
}, 100);
}
使用方法举例:
- 简单使用
js
<id-keyboard v-model="cardNumber" name="xxxx"/>
// 需要传递一个特定的name,防止点击name的时候被意外收起键盘。
<id-keyboard v-model="cardNumber" name="xxxx"/>
// 需要传递一个特定的name,防止点击name的时候被意外收起键盘。
- 支持绑定状态 @hideIdKeyboard、@showIdKeyboard,可控制键盘收起状态、展开状态。 可用在键盘收起展开时,处理键盘遮挡等其他事件
js
<id-keyboard
v-model="basicForm.fatherCardid"
name="fatherCardid"
:no-padding="true"
label=""
@hideIdKeyboard="formatterFather(basicForm.fatherCardid)"
@showIdKeyboard="showFatherCardKeyborad(1)"
/>
<id-keyboard
v-model="basicForm.fatherCardid"
name="fatherCardid"
:no-padding="true"
label=""
@hideIdKeyboard="formatterFather(basicForm.fatherCardid)"
@showIdKeyboard="showFatherCardKeyborad(1)"
/>
- 可用通过
:show.sync
绑定身份证键盘的弹出状态
js
<IdKeyboard
v-model="cardNumber"
name="basicCardNum"
:show.sync="showCardIdBoard"
style="margin-bottom: 40px"
/>
<IdKeyboard
v-model="cardNumber"
name="basicCardNum"
:show.sync="showCardIdBoard"
style="margin-bottom: 40px"
/>