Vue custom keyboard implementation, according to input positioning

need:

There are many input boxes in the project. Since the built-in keyboard of the system does not meet the requirements, it is necessary to customize the keyboard, and the keyboard is automatically displayed below when the input box is focused.

The plug-in only realizes the function, and the style needs to be debugged by yourself

This example solves the problem that the page scrolling keyboard follows the scrolling, and the specific logic can be understood by yourself

First you need a custom keyboard component cuskeyboard as follows:

<template>
    <div class="keyboardcon" v-if="isShowKeyBoard">
        <div class="number">
            <div
                    :class="active==index?'numberitem changecolor':'numberitem'"
                    v-for="(item,index) in lists"
                    :key="index"
                    @click.stop="choosekey(item,index)"
            >
                {<!-- -->{item.label}}
            </div>
        </div>
    </div>
</template>

<script>
    export default {
        name: 'cuskeyboard',
        data() {
            return {
                lists: [{
                    value: ' + ',
                    label: ' + '
                }, {
                    value: 1,
                    label: '1'
                }, {
                    value: 2,
                    label: '2'
                }, {
                    value: 3,
                    label: '3'
                }, {
                    value: '-',
                    label: '-'
                }, {
                    value: 4,
                    label: '4'
                }, {
                    value: 5,
                    label: '5'
                }, {
                    value: 6,
                    label: '6'
                },
                    {
                        value: 'du',
                        label: 'du'
                    }, {
                        value: 7,
                        label: '7'
                    }, {
                        value: 8,
                        label: '8'
                    }, {
                        value: 9,
                        label: '9'
                    },
                    {
                        value: 'V',
                        label: 'V'
                    },
                    {
                        value: 0,
                        label: '0'
                    }, {
                        value: '.',
                        label: '.'
                    }, {
                        value: 'delete',
                        label: 'delete'
                    }
                ],
                // num: [],
                active: null,
            }
        },
        props: {
            // Whether to display
            isShowKeyBoard: {
                type: Boolean,
                default: false
            },
            // Defaults
            currValue: {
                type: String,
                default: ''
            },
        },
        computed: {
            num() {
                return this.currValue.split('')
            }
        },
        methods: {
            // Get the value of the clicked key
            choosekey(item, index) {
                this.active = index;
                setTimeout(() => {
                    this. active = null;
                }, 100);
                if (item. label === 'delete') {
                    this.num.splice(this.num.length - 1, this.num.length)
                    this.$emit('changekey', this.num);
                } else {
                    this.num.push(item.label);
                    this.$emit('changekey', this.num);
                }
            },
        },
        mounted() {
        }
    }
</script>

<style lang="less" scoped>
    .cuskeyboard {
        width: 100%;
        z-index: 999;
    }

    .keyboardcon {
        position: absolute;
        background-color: #1c6ca1;
        width: 100%;
    }

    .keyboardcon .number {
        width: 100%;
        display: flex;
        justify-content: center;
        align-items: center;
        flex-wrap: wrap;
    }

    .keyboardcon .number .numberitem {
        height: 2.64533333rem;
        box-sizing: border-box;
        border-top: 4px solid #F4F4F4;
        border-right: 4px solid #F4F4F4;
        width: 25%;
        display: flex;
        justify-content: center;
        align-items: center;
    }

    .changecolor {
        background-color: #D7D7D7;
    }
</style>

Notice:

When a single input box is referenced

1) When @focus is used, the attribute name bound to the input box should be passed out

2) Need to set class to ‘KeyboardClass’

3) The ref attribute needs to be set as the attribute name of the input box v-model

The case of v-for when multiple input boxes are referenced

1) When using @focus, you need to combine the index of the current input box and the bound attribute name to pass it out. In this case, it is

`${index}--a`

2) The setting of ref is the same as above `${index}–a`

3) Also set the class to ‘KeyboardClass’

Introduce the plug-in where needed; the code is as follows:

<template>
    <div class="derails-info"
         @click.capture="handleClick"
         style="height:100vh;overflow-y: auto;position: relative">
        <div style="height: 100px">

        </div>
        <el-input v-model="form.input1" readonly ref="input1" class="KeyboardClass"
                  @focus="((e)=>handleFocus(e,'input1'))" placeholder="Please input content"></el-input>

        <el-input v-model="form.input2" readonly ref="input2" class="KeyboardClass"
                  @focus="((e)=>handleFocus(e,'input2'))" placeholder="Please input content"></el-input>

        <el-input
                v-for="(item,index) in arr" :key="index"
                v-model="item.a" readonly
                class="KeyboardClass"
                :ref="`${index}--a`"
                @focus="((e)=>handleFocus(e,`${index}--a`))" placeholder="Please enter the content"></el-input>
        <Keyboard
                :style="keyboardStyle"
                :currValue="currValue"
                :isShowKeyBoard="isShowKeyBoard"
                @changekey="changekey"
        ></Keyboard>
        <div style="height: 800px">

        </div>
    </div>

</template>

<script>
    import Keyboard from '../components/cuskeyboard';

    export default {
        name: "TabDetails",
        data() {
            return {
                // Whether to display the keyboard
                isShowKeyBoard: false,
                currValue: '',
                form: {
                    input1: '',
                    input2: '',
                },
                arr: [{
                    a: ''
                }, {
                    a: ''
                }],
                key: '',
                keyboardStyle: {
                    position: 'absolute',
                    left: '',
                    top: ''
                }
            }
        },
        methods: {
            handleClick(e) {
                if (e.target.className === 'el-input__inner' & amp; & amp;
                    e.target.offsetParent.className.indexOf('KeyboardClass') !== -1) {
                    this.isShowKeyBoard = true
                } else {
                    this.isShowKeyBoard = false
                }
            },
            changekey(value) {
                let val = value.join(""); // join the obtained values
                // Represents that the dynamic ref is bound to an array object
                let splitArr = this.key.split('--')
                if (splitArr. length > 1) {
                    this.arr[splitArr[0]][splitArr[1]] = val
                    this.$refs[this.key][0].focus()
                } else {
                    this.form[this.key] = val;
                    this.$refs[this.key].focus()
                }
            },
            getDistanceOfLeft(obj) {
                let left = 0;
                let top = 0;
                while (obj) {
                    left + = obj.offsetLeft;
                    top += obj.offsetTop;
                    obj = obj.offsetParent;
                }
                return {
                    left: left,
                    top: top
                };
            },
            handleFocus(e, key) {
                this.isShowKeyBoard = true
                this.keyboardStyle.left = this.getDistanceOfLeft(e.target).left + 'px'
                this.keyboardStyle.top = this.getDistanceOfLeft(e.target).top + 40 + 'px'
                this.key = key
                let splitArr = this.key.split('--')
                if (splitArr. length > 1) {
                    this.currValue = this.arr[splitArr[0]][splitArr[1]]
                } else {
                    this.currValue = this.form[this.key]
                }
            }
        },
        components: {
            keyboard
        }
    }
</script>

<style lang="less" scoped>

</style>

The renderings are as follows: