基于vue封装触屏电脑键盘(keyboards)组件
先上效果图
1.支持光标选中位置,中间断点输入,删除等;
组件代码:
<template>
<transition name="slide" mode="in-out">
<div class="keyboards">
<ul class="key_wrapper" >
<li class="key_rows" v-for="(item,index) in keys" :key="index">
<span class="key_btn" v-for="(items, indexInner) in item" :key="indexInner"
@click="getVal(items,$event)"
:class="{
capslock:((items[0] == 'capslock' && capslock) ? true : false),
shift:((items[0] == 'shift' && shift) ? true : false),
cap_btn:items[0] == 'capslock' ? true :false,
shift_btn:items[0] == 'shift' ? true :false,
del_btn:items[0] == 'delete' ? true :false,
submit_btn:items[0] == '完成' ? true :false,
}"
>{{items.constructor == Array ? (!capslock ? items[0] : items[1]) : ''}}</span>
</li>
</ul>
</div>
</transition>
</template>
<script>
/*
* handelChange 父组件 绑定输入改变事件
*handelSave 父组件点击确定事件(处理键盘组件显示/隐藏等)
*innerVal: 子组件props,接收当前input的内容
*start: 子组件props,接受当前鼠标光标位置
*/
export default {
props:['innerVal','start'], //初始值, 起始位置;
data() {
return {
showKeys:true,
keys:[
[
['`','~'],
['1','!'],
['2','@'],
['3','#'],
['4','$'],
['5','%'],
['6','^'],
['7','&'],
['8','*'],
['9','('],
['0',')'],
['-', '_'],
['=','+'],
['delete','delete']
],
[
['q',"Q"],
['w',"W"],
['e',"E"],
['r',"R"],
['t',"T"],
['y',"Y"],
['u',"U"],
['i',"I"],
['o',"O"],
['p',"P"],
['[','{'],
[']','}']
],
[
['capslock','capslock'],
['a','A'],
['s','S'],
['d','D'],
['f','F'],
['g','G'],
['h','H'],
['j','J'],
['k','K'],
['l','L'],
[';',':'],
["'",'"'],
['\\','|']
],
[
// ['shift','shift'],
['z','Z'],
['x','X'],
['c','C'],
['v','V'],
['b','B'],
['n','N'],
['m','M'],
[',','<'],
['.','>'],
['/','?'],
['完成','完成']
]
],
capslock:false, //默认大写
shift:false, //默认shift
innerHTML:"", //输入的值
tmpPoint:0,
}
},
watch:{
innerVal(news){
this.innerHTML = news;
},
start(news){
this.tmpPoint = news;
},
innerHTML(news){
this.$emit("handelChange",news)
}
},
methods: {
getVal(items,e){
let val = items.constructor == Array ? items[0] : items; //当前选中的值
if( val == 'capslock' ){
this.capslock = ! this.capslock;
}else if(val == 'shift'){
this.shift = !this.shift;
}else if(val == '完成'){
this.$emit("handelSave")
}else{
let vals = e.target.innerHTML;
let start_ = this.innerHTML.length >0 ? this.innerHTML.substr(0,this.tmpPoint) : "";
let end = this.innerHTML.length > 0 ? this.innerHTML.substr(this.tmpPoint) : "";
if( vals == 'delete'){
if(this.tmpPoint >=1 && start_.length > 0){
this.tmpPoint-=1;
this.innerHTML = this.innerHTML.slice(0,start_.length-1)+end;
}
}else{
this.tmpPoint+=1;
this.innerHTML = start_+vals+end;
}
}
}
},
}
</script>
<style lang="scss">
.slide-enter,
.slide-leave-to {
opacity: 0;
transform:translateY(2rem);
}
.slide-enter-active,
.slide-leave-active {
transition: all .5s;
}
.keyboards{
width: 100%;
height: 2rem;
background: #fff;
position: absolute;
bottom: 0px;
.key_wrapper{
height: 100%;
width: 100%;
.key_rows{
text-align: center;
}
}
.key_btn{
user-select: none;
cursor: pointer;
padding:.1rem 0;
width: .3rem;
font-size: .14rem;
display: inline-block;
margin: .03rem;
border: 1px solid #ccc;
}
.del_btn{
width: .6rem;
}
.shift_btn{
width: .4rem;
}
.cap_btn{
width: .7rem;
}
.submit_btn{
width: .4rem;
background: rgb(44, 79, 175);
color: #fff;
}
.capslock,.shift{
background: rgb(44, 79, 175);
color: #fff;
}
}
</style>