vue实现自定义身份证,数字键盘(光标,输入框,键盘)
组件介绍组件代码效果图组件使用引用使用 参数介绍方法插槽组件介绍
vue实现自定义身份证键盘(光标,输入框,键盘全手写)
组件代码
<template><divclass="myKeyboard"@click.stop="handleFocus"@blur="handleBlur"tabindex="0"><div class="input-container"><div class="input-top"><div class="input-label" :style="labelStyle" :class="labelClass">{{inputLabel }}</div><divclass="inputText"id="inputText":style="inputStyle":class="inputClass"><span class="cursor"><span class="holder showWhite">|</span></span><span class="place-holder">{{placeHolder }}</span><spanclass="right-space":style="{ color: zcolor }"@click="moveCursor">占位</span><span class="right-btn"><!-- <span v-if="clearShow" class="clear" @click="handleClear"> --><imgv-if="clearShow"class="clear"@click="handleClear"src="@/assets/keyboard/keyboard_clear.png"alt=""/><slot></slot></span></div></div><div class="error" :style="errorStyle" v-if="errorShow">{{errorMessage }}</div><div class="errorSpace" v-else></div></div><div class="number hidden" :class="numberClass" :style="numberStyle"><div class="mybtn" @click.stop="handleBlur"><img src="@/assets/keyboard/keyboard_down.png" alt="" /></div><div class="mynum"><div class="num" @click="handleNum('1')">1</div><div class="num" @click="handleNum('2')">2</div><div class="num" @click="handleNum('3')">3</div><div class="num" @click="handleNum('4')">4</div><div class="num" @click="handleNum('5')">5</div><div class="num" @click="handleNum('6')">6</div><div class="num" @click="handleNum('7')">7</div><div class="num" @click="handleNum('8')">8</div><div class="num" @click="handleNum('9')">9</div><div v-if="keyboard == 'card'" class="num" @click="handleNum('X')">X</div><div v-if="keyboard == 'tel'" class="num" @click="handleNum('0')">0</div><div class="num" @click="handleNum('0')">0</div><divclass="num"@click.stop="handleDelete"@touchstart="gtouchstart"@touchend="gtouchend"@touchmove="gtouchmove"><img src="@/assets/keyboard/keyboard_del1.png" alt="" /></div></div></div></div></template><script>export default {props: {// inputS: {// type: String,// default: '',// },// inputH: {// type: String,// default: '2.5rem',// },// inputB: {// type: String,// default: 'none',// },// inputW: {// type: String,// default: '',// },// inputBgc: {// type: String,// default: '#fff',// },// labelS: {// type: String,// default: '',// },// labelC: {// type: String,// default: '',// },// labelW: {// type: String,// default: '',// },// 输入框索引(必填字段)indexNum: {type: Number,default: 0,},// 是否聚焦(true:不聚焦,false:聚焦)numberDis: {type: Boolean,default: false,},// 是否必填(true:出现红星,false:不出现)required: {type: Boolean,default: false,},// 键盘类型(card:身份证,tel:数字)keyboard: {type: String,default: 'card',},// 父组件存的值oldValue: {type: String,default: '',},// 占位符颜色(建议设置和输入框背景同色)zcolor: {type: String,default: '#fff',},// label文字inputLabel: {type: String,default: '',},// 当输入框内无文字时显示placeHolder: {type: String,default: '请输入',},// 错误提示信息errorMessage: {type: String,default: '请输入正确的信息',},// 是否显示错误提示信息errorShow: {type: Boolean,default: false,},// 错误提示信息样式errorStyle: {type: Object,default: function () {return {}},},// 是否显示清除键clearShow: {type: Boolean,default: false,},// label动态类名labelClass: {type: String,default: '',},// label样式labelStyle: {type: Object,default: function () {return {}},},// input动态类名inputClass: {type: String,default: '',},// input样式inputStyle: {type: Object,default: function () {return {}},},// number类名numberClass: {type: String,default: '',},// number样式numberStyle: {type: Object,default: function () {return {}},},},data() {return {inputArea: '',stop: false,clickNum: false,show: false,value: '',inputValue: '',}},watch: {oldValue(val) {if (val != this.inputValue) {this.handleClear()this.handleOld()}},required(val) {this.handleRequired(val)},},created() {this.$toast.clear()},mounted() {this.handleRequired(this.required)this.handleOld()},methods: {// 是否必填handleRequired(val) {const inputLabel =document.getElementsByClassName('input-label')[this.indexNum]if (val) {inputLabel.className = 'input-label required'} else {inputLabel.className = 'input-label'}},// 父组件改变值handleOld() {// 获取父组件存的值后画数字if (this.oldValue != '') {for (const item of this.oldValue) {const span = document.createElement('span') //创建包含值的元素span.className = 'val'span.innerText = itemconst space = document.createElement('span')space.className = 'space'space.innerText = ''span.addEventListener('click', this.moveCursor)const cursor =document.getElementsByClassName('cursor')[this.indexNum]const inputArea =document.getElementsByClassName('inputText')[this.indexNum]inputArea.insertBefore(space, cursor) //插入空列inputArea.insertBefore(span, cursor) //插入值}}const placeHolder =document.getElementsByClassName('place-holder')[this.indexNum]if (this.oldValue == '') {placeHolder.className = 'place-holder'} else {placeHolder.className = 'place-holder hidden'}this.inputValue = this.oldValuethis.$emit('keyboard-input', this.inputValue)},// 聚焦handleFocus(event) {if (!this.numberDis) {this.$emit('indexNum', this.indexNum)const number = document.getElementsByClassName('number')[this.indexNum]number.className = 'number'this.setCursorFlash()this.handleValue()}},//字符插入,在光标前插入字符handleNum(value) {const number = document.getElementsByClassName('number')[this.indexNum]number.className = 'number'const span = document.createElement('span') //创建包含值的元素span.className = 'val'span.innerText = valueconst space = document.createElement('span')space.className = 'space'space.innerText = ''span.addEventListener('click', this.moveCursor)const cursor = document.getElementsByClassName('cursor')[this.indexNum]const inputArea =document.getElementsByClassName('inputText')[this.indexNum]inputArea.insertBefore(space, cursor) //插入空列inputArea.insertBefore(span, cursor) //插入值this.handleValue()},// 失焦handleBlur(e) {clearInterval(this.intervalId)const placeHolder =document.getElementsByClassName('holder')[this.indexNum]placeHolder.className = 'holder showWhite'const number = document.getElementsByClassName('number')[this.indexNum]number.className = 'number hidden'const inputText =document.getElementsByClassName('inputText')[this.indexNum]inputText.className = 'inputText'this.handleValue()const inputArea =document.getElementsByClassName('inputText')[this.indexNum]const reset =document.getElementsByClassName('place-holder')[this.indexNum]const cursor = document.getElementsByClassName('cursor')[this.indexNum] //获取光标const ele = inputArea.replaceChild(reset.previousSibling, cursor)inputArea.insertBefore(ele, reset)},// 移动光标位置moveCursor(event) {const inputArea =document.getElementsByClassName('inputText')[this.indexNum]const cursor = document.getElementsByClassName('cursor')[this.indexNum] //获取光标if (event.currentTarget.className == 'right-space') {const ele = inputArea.replaceChild(event.currentTarget.previousSibling.previousSibling,cursor,)inputArea.insertBefore(ele, event.currentTarget.previousSibling)} else {const tempEle = event.currentTargetconst nodeName = event.currentTarget.nextSibling.nodeNameconst temp = event.currentTarget.previousSiblingconst ele = inputArea.replaceChild(temp, cursor) //把光标替换成当前元素inputArea.insertBefore(ele, event.currentTarget)}},// 删除handleDelete() {const inputArea =document.getElementsByClassName('inputText')[this.indexNum]// this.setCursorFlash()const cursor = document.getElementsByClassName('cursor')[this.indexNum]let n = 2 //两个删除动作while (cursor.previousSibling && n > 0) {inputArea.removeChild(cursor.previousSibling)n--}this.handleValue()},//开始按gtouchstart(e) {this.timeOutEvent = setTimeout(() => {this.longPress()}, 500)return false},gtouchend() {clearTimeout(this.timeOutEvent)clearInterval(this.press)if (this.timeOutEvent != 0) {// alert('你这是点击,不是长按')}return false},gtouchmove() {clearTimeout(this.timeOutEvent)clearInterval(this.press)this.timeOutEvent = 0},longPress() {this.timeOutEvent = 0this.press = setInterval(() => {this.handleDelete()}, 300)},//设置光标定时任务setCursorFlash() {const placeHolder =document.getElementsByClassName('holder')[this.indexNum]let isShowCursor = falseif (this.intervalId) {clearInterval(this.intervalId)}this.intervalId = setInterval(function () {isShowCursor = !isShowCursorif (isShowCursor) {placeHolder.className = 'holder'} else {placeHolder.className = 'holder showWhite'}}, 500)},// 全清handleClear() {const father = document.getElementsByClassName('inputText')[this.indexNum]const child =document.getElementsByClassName('inputText')[this.indexNum].childNodesfor (let i = child.length - 1; i >= 0; i--) {if (child[i].className == 'val' || child[i].className == 'space') {father.removeChild(child[i])}}},// 获取值handleValue() {const val = document.getElementsByClassName('inputText')[this.indexNum].querySelectorAll('.val')const arr = []arr[this.indexNum] = []for (let i = 0; i < val.length; i++) {arr[this.indexNum].push(val[i].innerHTML)}this.inputValue = arr[this.indexNum].toString()this.inputValue = this.inputValue.split(',').join('')this.$emit('keyboard-input', this.inputValue)const placeHolder =document.getElementsByClassName('place-holder')[this.indexNum]if (this.inputValue == '') {placeHolder.className = 'place-holder'} else {placeHolder.className = 'place-holder hidden'}},},}</script><style scoped lang="less">.myKeyboard:focus {outline: none;}.input-container {display: flex;// align-items: center;flex-direction: column;box-sizing: border-box;padding: 1rem;padding-bottom: 0.2rem;width: 100%;border-bottom: 1px solid #eee;background: #fff;font-size: 1.04rem;.acitve {border: 1px solid #2e8fff !important;}.input-top {display: flex;align-items: center;box-sizing: border-box;width: 100%;}.error {color: #ee0a24;font-size: 0.75rem;}.errorSpace {width: 1rem;height: 1.2rem;}.required::before {position: absolute;left: 0.5rem;color: #ee0a24;content: '*';font-size: 0.875rem;}.inputText {position: relative;flex: 1;width: 80%;border: none;}.right-btn {position: absolute;right: 2%;.clear {width: 1.5rem;}// :nth-child(1) {// width: 1.5rem;// }:nth-child(2) {}}.right-space {// color: #fff;}.place-holder {color: #c8c8c8;}}.number {position: fixed;bottom: 0;z-index: 999999;padding-bottom: 2%;width: 100%;background-color: #f0f0f0;font-size: 2rem;.mybtn {height: 2rem;text-align: center;line-height: 2rem;img {height: 100%;}}.mynum {display: flex;flex-wrap: wrap;height: calc(100% - 2rem);.num {display: flex;align-items: center;flex: 1 0 30%;justify-content: center;height: 3.4rem;border-top: 1px solid #eee;border-left: 1px solid #eee;background-color: #fff;text-align: center;&:active {background-color: rgb(202, 202, 202);}img {// height: 100%;pointer-events: none;}}}}.hidden {display: none;}.showWhite {color: #fff;}</style>
效果图
组件使用
引用
和正常引用组件的操作相同
import number from '文件地址'export default {components:{number},data() {return {indexNum: 0, //必填字段,为键盘索引,每个键盘必须具有唯一值oldValue: '' //从父组件传递给子组件的值}},methods:{handleKeyBoard(value) {//value为在输入框里面输入的值console.log(value)this.oldValue = value},}}
使用
<number:index-num="indexNum"@keyboard-input="handleKeyBoard":old-value="oldValue"></number>