背景
最近产品想要在页面上加一个input输入框,想要手动输入,也想要扫码枪扫描输入,大家都知道扫码枪扫描后会自动出发input的回车enter事件的,我当初也是这么认为的,所以在input上就直接绑定了keyup enter事件,在里面做一些接口请求之类的动作,后来这个页面被投放到门店的收银机,问题出现了:当机器为windows系统并且搜狗输入法中文时,扫码枪没有监听到自动回车事件,导致扫描枪没反应
解决方案
password的Input可以忽略输入法的中英文,所以password框里的内容,我们需要一个覆盖在上面的div来实时展示,这个div要像一个input存在,所以要模拟一个失焦和聚焦的闪烁光标,光标闪烁时真正聚焦的是password input框
需求设计
- 一个div和一个type为password ,两者数据实时绑定
- div覆盖在password上,设定一个伪类来实现div的闪烁光标
- password的focus和blur方法中控制div的光标是否显示
- div的不设宽度,促使光标紧随div内容后面
代码
先写一个barcode.vue的子组件
<template>
<div style="position: relative;width: 200px;">
<el-input
type="password"
v-model="barCode"
autocomplete="off"
class="pad-input"
ref="barcodeScanRef"
@keyup.enter.native="enterHandle"
@focus="handleInputFocus"
@blur="handleInputBlur"
></el-input>
<div id="show" disabled>
<span>{{ barCode }}</span>
</div>
</div>
</template>
<script>
export default {
props: {
enterHandle: {
type: Function,
default: () => () => {},
},
},
data() {
return {
barCode: '',
};
},
methods: {
handleInputBlur() {
this.handleMymove('0');
},
handleInputFocus(e) {
this.handleMymove('1');
},
handleMymove(num) {
let style = document.createElement('style');
document.head.appendChild(style);
let sheet = style.sheet;
sheet.addRule('#show:after', `opacity:${num};animation:${num==='0'?'null':'mymove 1.2s infinite'} `);
sheet.insertRule(`#show:after{opacity:${num};animation:${num==='0'?'null':'mymove 1.2s infinite'}}`);
},
},
};
</script>
<style lang="less">
#show {
padding-left: 14px;
position: absolute;
left: 2px;
top: 50%;
transform: translate(0, -50%);
border: none;
height: 30px;
line-height: 30px;
pointer-events: none;
background: #fff;
width: 98%;
}
#show:after {
content: '';
display: inline-block;
height: 15px;
position: relative;
border-right: solid 1px #666;
top: 2px;
left: 1px;
opacity: 0;
}
.pad-input {
height: 28px;
width: 100%;
border: none;
background: none;
}
@keyframes mymove {
0% {
opacity: 0;
}
25% {
opacity: 0;
}
75% {
opacity: 1;
}
100% {
opacity: 0;
}
}
</style>
父组件调用,传递一个子组件回车事件enterHandle
<template>
<el-form-x v-bind="formProps" @submit.native.prevent ref="form">
<el-form-item label="分配单号" prop="paperCode" :wrapper-col="{ span: 6 }">
<barcode-scan :enterHandle="handleAdd" ref="barcodeRef"></barcode-scan>
</el-form-item>
<div class="pseudo-form-item">
<el-button type="primary" @click="handleAdd">添加 </el-button>
</div>
</el-form-x>
</template>
<script>
import barcodeScan from '../../components/barcode-scan.vue';
export default {
components: {
barcodeScan,
},
methods: {
async handleAdd() {
let barcodeRef = this.$refs.barcodeRef;
if (!barcodeRef.barCode && !barcodeRef_data.barCode) {
return this.$message.error('请输入单号');
}
this.formProps.model.paperCode = barcodeRef.barCode || barcodeRef_data.barCode;
try {
const { paperCode } = this.formProps.model;
if (!paperCode) return;
...//发送请求处理数据
} catch (e) {
e.data && this.$message.error(e.data.msg);
}
//请求完之后再自动去聚焦
barcodeRef.$refs.barcodeScanRef.select();
barcodeRef.$refs.barcodeScanRef.focus();
barcodeRef.barCode = '';
barcodeRef._data.barCode = '';
},
};
</script>
这样就可以解决vue框架下面的扫描枪或者手动输入遇到的搜狗输入法兼容性问题
到了这里你以为就结束了么?过了不久,门店的人又来反馈了: 当鼠标聚焦时,"输入框"旁边会出现密码自动填充的弹窗,这是浏览器自带的,事情变的有趣了…
VUE扫码枪中文输入法兼容自动回车事件(下)