自定义数字键盘组件化方案(使用计算属性及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);

 

posted @ 2020-04-14 00:11  梁涛999  阅读(397)  评论(0编辑  收藏  举报