移动端自定义输入框的vue组件 ----input

<style scoped lang="less">
    .keyboard {
        font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", STHeiti, "Microsoft Yahei", Tahoma, Simsun, sans-serif;
        user-select: none;
        font-size: 16px;
        width: 100%;
    }

    .input-box {
        display: flex;
        align-items: center;
        justify-content: space-between;
        line-height: 120px;
        background-color: #fff;
        border-radius: 8px;
        font-size: 64px;
        .label {
            text-align: center;
            width: 119px;
            position: relative;
            &::after {
                content: "";
                position: absolute;
                /* display: inline-block; */
                height: 64px;
                top: 28px;
                right: 0;
                width: 2px;
                background-color: rgb(221, 221, 221);
            }
        }
        .content {
            display: flex;
            flex: 1;
            .input {

                color: #313131;
            }
            .cursor {
                background-color: #4788c5;

                width: 2px;
                height: 64px;
                margin-top: 28px;
                margin-left: 2px;
            }
            .placeholder {
                height: 120px;
                padding-left: 38px;
            }
            .currency {}
        }
    }
</style>
<template>
    <div class="keyboard">
        <!-- 自定义输入框 -->
        <div class="input-box" @touchstart.stop="focus">
            <!-- 左侧标签 -->
            <p class="label">¥ </p>
            <!-- 右侧内容 -->
            <div class="content">

                <p class="placeholder" v-show="val.length === 0">
                    {{value}}
                </p>
                <!-- 光标 -->
                <p class="cursor" :style="{visibility: cursor ? 'visible' : 'hidden'}"></p>
            </div>
        </div>


    </div>

</template>
<script>

    export default {
        name: 'KeyboardInput',
        components: {

        },
        created() {
            /*闪烁光标*/
            this.blinkCursor();
            // document.addEventListener('touchstart', () => {
            //     this.blur();
            // });
        },
        props: {
            value: '',
            inter: {
                default: 5
            },
            decimal: {
                default: 2
            },
            // label: {
            //     default: '消费金额'
            // },
            placeholder: {
                default: '158898'
            }
        },
        data() {
            return {
                cursor: false,
                keyboard: false,
                /*value 在组件中的值*/
                val: '',
                aIllegal: ['00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '0..', '.'],
                cursorDuration: 600,
                bodyHeight: '',
                bodyOverflow: ''
            }
        },
        methods: {
            /*focus*/
            focus() {
                /*显示键盘*/
                this.showKeyboard();
                /*显示光标*/
                this.showCursor();

            },
            blinkCursor() {
                clearInterval(this.intervalID);
                this.intervalID = setInterval(() => {
                    this.cursor = !this.cursor;
                }, this.cursorDuration);
            },
            unblinkCursor() {
                clearInterval(this.intervalID);
            },
            /*blur*/
            blur() {
                /*隐藏光标*/
                this.hideCursor();
                /*停止光标闪烁*/
                this.unblinkCursor();
                /*隐藏键盘*/
                this.hideKeyboard();
                /*
                    附加 00, 如果用户输入了一个以 . 结尾的值就点完成了, 
                    那么这个时候就在后面加上00
                */
                this.toCompletion();
                /*通知父组件, 老子值出来了*/
                /*
                    校验用户输入的金额是不是为 0, 如果是的话, 直接重置
                */
                this.checkValue();
                this.notify();

            },
            showKeyboard() {
                this.keyboard = true;
            },
            hideKeyboard() {
                this.keyboard = false;
            },
            showCursor() {
                this.cursor = true;
            },
            hideCursor() {
                this.cursor = false;
            },
            checkValue() {
                if (parseFloat(this.val) === 0) {
                    this.val = '';
                }
            },
            /*判读是否需要加0*/
            toCompletion() {
                let list = this.value.split('.');
                if (typeof list[1] === 'undefined') {
                    if (this.val !== '') {
                        this.val = this.val + '.';
                        this.completion(this.decimal);
                    }
                } else {
                    if (list[1].length < this.decimal) {
                        this.completion(this.decimal - list[1].length);
                    }
                }
            },
            completion(len) {
                let v = '';
                for (let i = 0; i < len; i++) {
                    v = v + '0';
                }
                this.val = this.val + v;
            },
            notify() {
                this.$emit('input', this.val);
            },
            del() {
                /*删除值并不会触发值的校验, 所以需要手动再触发一次*/
                this.val = this.val.slice(0, -1);
                this.notify();
            },
            /*输入*/
            typing(value) {
                /*如果是点击删除*/
                if (value === '') {
                    this.del();
                }
                /*保存旧的值*/
                let oldValue = this.val;
                /*获取新的值*/
                this.val = this.val + value;
                /*检验新值, 如果没有通过检测, 恢复值*/
                if (!this.passCheck(this.val)) {
                    this.val = oldValue;
                    return;
                }
                /*为了让外界同步输入, 需要发送事件*/
                this.notify();
            },
            passCheck(val) {
                /*验证规则*/
                let aRules = [
                    this.illegalInput,
                    this.illegalValue,
                    this.accuracy
                ]
                return aRules.every((item) => {
                    return item(val);
                });
            },
            illegalInput(val) {
                if (this.aIllegal.indexOf(val) > -1) {
                    return false;
                }
                return true;
            },
            /*非法值*/
            illegalValue(val) {
                if (parseFloat(val) != val) {
                    return false;
                }
                return true;
            },
            /*验证精度*/
            accuracy(val) {
                let v = val.split('.')
                if (v[0].length > this.inter) {
                    return false;
                }
                if (v[1] && (v[1].length) > this.decimal) {
                    return false;
                }
                return true;
            }
        }
    }

</script>

转载于:https://www.cnblogs.com/jerrypig/p/9140324.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在Vue中实现自定义组件的双向绑定(v-model),你可以使用`model`选项。下面是一个简单的例子,演示如何创建一个自定义组件并将其包装在v-model中使用: ```html <!-- 父组件 --> <template> <div> <custom-input v-model="message"></custom-input> <p>Message: {{ message }}</p> </div> </template> <script> import CustomInput from './CustomInput.vue'; export default { components: { CustomInput }, data() { return { message: '' } } } </script> ``` ```html <!-- CustomInput.vue --> <template> <input :value="value" @input="$emit('input', $event.target.value)"> </template> <script> export default { props: ['value'] } </script> ``` 在上面的例子中,父组件通过`v-model="message"`将`message`作为属性传递给子组件`CustomInput`。子组件接收该属性作为`value`,并在输入事件触发时通过`$emit('input', $event.target.value)`将新的值传递回父组件。 这样,当用户在子组件中输入文本时,父组件的`message`属性会自动更新,实现了双向绑定。 请注意,使用`v-model`时,子组件内部的属性名必须为`value`,而不是其他名字。这是因为`v-model`默认会使用`value`作为属性名来传递值,并使用`input`事件来更新值。如果你想要使用不同的属性名,可以在子组件中使用`model`选项来自定义。 ```html <!-- CustomInput.vue --> <template> <input :value="internalValue" @input="updateValue($event.target.value)"> </template> <script> export default { model: { prop: 'customValue', event: 'customInput' }, props: { customValue: String }, computed: { internalValue: { get() { return this.customValue; }, set(newValue) { this.$emit('customInput', newValue); } } }, methods: { updateValue(value) { this.internalValue = value; } } } </script> ``` 通过在子组件中使用`model`选项,你可以自定义属性名和事件名,以实现更灵活的双向绑定。在上面的例子中,父组件可以这样使用: ```html <custom-input v-model="message"></custom-input> ``` 这会将父组件的`message`属性传递给子组件的`customValue`属性,并使用`customInput`事件来更新值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值