自定义数字键盘组件化方案(使用计算属性及sync)
实现场景:点击输入框,弹出自定义数字键盘,输入数字后点击确定,输入框中显示对应数字。如果输入框中有值,则默认带到小键盘中。
其中:数字键盘为子组件。输入框公用该子组件。
效果图如下:
难点:
1、props传入数字键盘组件中的值,无法直接修改。需要通过计算属性进行修改。
2、公用键盘时,保证符合预期,数字不会错乱。使用v-for,巧用name属性,通过点击时更改传入的参数,达到目的。
下面时完整代码:
index.vue
<template> <view class="content"> <image class="logo" src="/static/logo.png"></image> <view v-for="(value,name) in numValuelist" :key="name"> <view class="text-area" v-if="name=='X'"> 默认正:<input :value="value" @click="showKeyPad(name,'0')"> </view> <view class="text-area" v-if="name=='Y'"> 默认负:<input :value="value" @click="showKeyPad(name,'1')"> </view> </view> <NumKeypad :enteringIsShow="enteringIsShow" :inputname="inputname" fontSize="20px" :isminus="isminus" :passNum="numValue" @NumValue="GetNumValue"></NumKeypad> </view> </template> <script> import NumKeypad from "../Keypad/NumKeypad.vue"; export default { data() { return { title: 'Hello', enteringIsShow:false,//控制键盘显示隐藏 inputname:'', isminus:'0',//是否为负数 1为负数 numValue:'', numValuelist:{"X": "","Y": ""}, } }, onLoad() { }, components:{ NumKeypad }, methods: { GetNumValue(value,inputname) { this.numValuelist[this.inputname]=value; this.enteringIsShow=false; }, showKeyPad(v,i,t){ this.enteringIsShow=true; this.inputname=v; this.numValue=this.numValuelist[this.inputname]; this.isminus=i; }, } } </script> <style> .content { display: flex; flex-direction: column; align-items: center; justify-content: center; } .logo { height: 200rpx; width: 200rpx; margin-top: 200rpx; margin-left: auto; margin-right: auto; margin-bottom: 50rpx; } .text-area { display: flex; justify-content: center; } .title { font-size: 36rpx; color: #8f8f94; } </style>
NumKeyPad.vue
<template> <view v-if="enteringIsShow"> <!-- v-if="enteringIsShow" --> <view class="con-backdrop"> <view class="view-backdrop uni-ellipsis">{{ChangeNum}}</view> <view class="btnBox"> <view class="btn-backdrop" @tap="Compute('1')">1</view> <view class="btn-backdrop" @tap="Compute('2')">2</view> <view class="btn-backdrop" @tap="Compute('3')">3</view> <view class="btn-backdrop" @tap="Compute('clear')">清空</view> <view class="btn-backdrop" @tap="Compute('4')">4</view> <view class="btn-backdrop" @tap="Compute('5')">5</view> <view class="btn-backdrop" @tap="Compute('6')">6</view> <view class="btn-backdrop" @tap="Compute('delete')">退格</view> <view class="btn-backdrop" @tap="Compute('7')">7</view> <view class="btn-backdrop" @tap="Compute('8')">8</view> <view class="btn-backdrop" @tap="Compute('9')">9</view> <view class="btn-backdrop" @tap="Compute('.')">.</view> <view class="btn-backdrop" @tap="Compute('-')">-</view> <view class="btn-backdrop" @tap="Compute('0')">0</view> <view class="btn-backdrop" @tap="Compute('+')">+</view> <view class="btn-backdrop color-blue" @tap="Compute('ok')">确认</view> </view> </view> </view> </template> <script> export default { data (){ return { entering:'', isFirstRender:true } }, props:{ enteringIsShow:{ type: Boolean, default: false }, fontSize: { type: String, default: "20px" }, isminus: { type: String, default: "0" }, inputname:{ type: String, default: "" }, passNum:{ type: String, default: "" } }, computed: { ChangeNum () { this.isFirstRender?this.entering=this.passNum:null return this.entering } }, methods: { Compute(e) { this.isFirstRender=false if (e == 'ok') { //确认 if ((this.entering.length == 1 && (this.entering[0] == '+' || this.entering[0] == '-'))||this.entering.substring(this.entering.length-1)==".") { return } this.$emit('NumValue', this.entering,this.inputname); this.isFirstRender = true; } else if (e == 'delete') { //退格 this.entering = this.entering.substring(0, this.entering.length - 1); } else if (e == '+' || e == '-') { //正负号 this.entering[0] != '+' && this.entering[0] != '-' ? this.entering = e + this.entering : this.entering = this.entering.substr(0, 0) + e + this.entering.substr(1) } else if (e == '.') { //小数点 let temBoolean = true; for (let i = 0; i < this.entering.length; i++) { this.entering[i] == '.' ? temBoolean = false : null } this.entering.length == 0 || (this.entering.length == 1 && this.entering[0] == '+') || (this.entering.length == 1 && this.entering[0] == '-') ? temBoolean = false : null, temBoolean ? this.entering += e : null }else if (e == 'clear') { //清空 this.entering = '' }else { //数字 if(e=="0"&&this.entering.length==0)//首位是0 { this.entering= this.entering+"0."; } else{ this.entering += e; } if(this.isminus=='1'&&this.entering[0]!="+"&&this.entering[0]!="-"){//默认是负数 this.entering="-"+this.entering; } } }, } } </script> <style> /* 数字键盘弹出 */ .backdrop { width:100%; height: 100%; background: #333; opacity: 0.5; z-index: 998; } .delete { width: 100%; height: 120px; line-height: 120px; text-align: center; position: absolute; top: 100%; } .delete image { width: 40px; height: 40px; vertical-align: middle; } .con-backdrop { width:100%; height: 305px; position: fixed; bottom: 0; left: 0; margin: auto; z-index: 999; background: #f7f7f7; border-radius: 6px; } .btnBox { padding: 0 15px; display: flex; justify-content: space-between; flex-wrap: wrap; } .btn-backdrop { width: 23%; height: 50px; line-height: 50px; text-align: center; font-size: 20px; background: #fff; margin-bottom: 10px; border-radius: 6px; border: solid 1px #eee; cursor: pointer; } .btn-backdrop:hover { background: #efefef; } .view-backdrop { width: 90%; height: 40px; line-height: 40px; text-align: right; font-size: 25px; padding: 5px 15px; } .color-blue{ color: #fff; background: #0078ff; } /* 文本溢出隐藏 */ .uni-ellipsis {overflow: hidden; white-space: nowrap; text-overflow: ellipsis;} </style>
20200924修改
使用.sync方法也可以修改props ,详细说明参考
父组件
<NumKeypad :passNum.sync="numValue"></NumKeypad>
子组件
//props对象不变 props:{ passNum:{ type: String, default: "" } }, //点击事件中 this.$emit('update:passNum',value);