VUE输入验证限制

2,173 阅读3分钟

什么是输入验证限制

vue输入验证限制,即在输入框输入的过程中,对字符进行限制,去除不符合要求的字符,保留我们想要的数据。这是我们经常遇到的需求,也是辅助表单验证的一种方式。

为何说是辅助表单验证的一种方式?

假设表单的某个输入框,我们只允许输入数字,那么做了输入限制后,那么表单验证,我们就只需做必填验证就可以了。


接下来,让我们通过几个示例,逐步了解输入验证:

vue输入验证限制 - 正整数限制

准备前置资源

  • vue.js
        <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.min.js"></script>
    
  • Dom结构
    ...
    <body>
        <div id="app">
            <input ref="text"  :value="text" @input="inputChange" placeholder="正整数"></input>
            {{text}}
        </div>
    </body>
    
  • js
        new Vue({
            el: '#app',
            data: function() {
                return {
                    text: ''
                }
            },
            methods: {
                inputChange(e) {
                    this.text = e.target.value;
                }
            }
    
        })
    
    

验证输入数据

接下来改造 inputChange方法:

    ...,
    methods: {
        inputChange(e) {
            let reg = /^[0-9]*$/;
            if (reg.test(e.target.value)) {
                // 只有输入数字时才会同步数据
                this.text = e.target.value;
            }
        }
    },
    ...

方法改造后,我们会发现,输入数字时才会将数据同步到 text, 但是input输入框内数据与 text数据并未保持一致;

那出现这种UI没有更新的情况,我们怎么办呢?

  1. 手动更新

    手动更新,即直接操作DOM改变input的数据

        ...,
        inputChange(e) {
            let reg = /^[0-9]*$/;
            if (reg.test(e.target.value)) {
                // 只有输入数字时才会同步数据
                this.text = e.target.value;
                return;
            }
            console.log('UI value - before: ', e.target.value);
            // 更新DOM数据
            // this.$refs.text.value = this.text;
            e.target.value = this.text;
            console.log('UI value - after: ', e.target.value);
        }
        ...
    

  1. 制造UI更新的条件

    根据Vue的更新机制,我们知道当数据产生 变动 时,就会触发UI的更新,那么我们可以这么做:

        ...,
        inputChange(e) {
            let reg = /^[0-9]*$/;
            if (reg.test(e.target.value)) {
                // 只有输入数字时才会同步数据
                this.text = e.target.value;
                return;
            }
            console.log('dom update before = ', e.target.value);
            // 制造数据变动,触发更新机制
            this.text += '$';
            // this.text += ' ';
            console.log('add $ = ', this.text);
            // await this.$nextTick();
            // this.text = this.text.trim();
            this.text = String(this.text).substring(0, this.text.length - 1);
            console.log('remove $ = ', this.text);
            this.$nextTick( () => {
              console.log('dom update after = ', e.target.value);
            });
    
        }
        ...
    

数据粘贴问题

做完了以上操作后,我们已经可以保证,输入的时候只能输入整数了。

但是如果我们复制一段包含文字、数字及其它字符到上面的输入框时,你会发现我们无法粘贴到里面,那么如果我们想在粘贴时,提取数字到输入框中改怎么做呢?

我们换种数据赋值的方式:

    ...,
    inputChange(e) {
        // 根据正则替换掉 0-9以外的数据
        this.text = e.target.value.replace(/[^0-9]/g,'');
        // 更新UI
        e.target.value = this.text;
    }
    ...

修改之后就可以达到我们想要的效果,不过如果没有特别的要求,大可不必使用这种方式。

输入中文的问题

当我们用输入法输入中文时,你会发现,输入框会先在输入框中添加占位,然后再将占位替换为对应的中文,而在以上的数据框中,输入中文,我们会发现,占位符被替换掉了,导致我们非预期的结果。

出现这种情况,主要是因为,我们在输入中文的过程中,input方法仍然会触发,导致占位符被替换掉导致的。

为了解决这种问题,我们可以使用两种方法解决:

  1. 手动绑定 compositionstart、compositionend方法

    compositionstart 可以监听我们是否在输入中文 compositionend 可以监听输入的中文是否进入了输入框, 而input方法的触发时机,正好在这两个方法中间,那么:

        <div id="app">
            <input ref="text"
                :value="text" @input="inputChange" placeholder="正整数"
                @compositionstart="onCompositionStart"
                @compositionend="onCompositionEnd"
            ></input>
            {{text}}
        </div>
    
        ...,
        methods: {
            ...,
            onCompositionStart(e) {
                e.target.composing = true;
            },
            onCompositionEnd(e) {
                if (!e.target.composing) { return }
                e.target.composing = false;
                // 输入中文完成后, 数据处理
                this.inputChange(e);
            },
            inputChange(e) {
                if (e.target.composing) {
                    // 输入中文过程不做数据处理
                    return;
                }
                // 根据正则替换掉 0-9以外的数据
                this.text = e.target.value.replace(/[^0-9]/g,'');
                // 更新UI
                e.target.value = this.text;
            }
    
            ...
        },
        ...
    

  2. 用 v-model 进行数据绑定

其实我们我们没有必要自己绑定 compositionstart、compositionend 方法,当我们使用 v-model进行双向绑定时,vue已为我们绑定了对应事件,详情请看 vue文档

        ...
        <input ref="text" v-model="textCpu" placeholder="v-model"></input>
        ...
    ...,
    computed: {
        textCpu: {
            get() {
                return this.text;
            },
            set(val) {
                this.text = val.replace(/[^0-9]/g,'');
                this.$refs.text.value = this.text;
            }
        }    
    },
    ...

这样我们就可以直接省略第一种方法的步骤了,当然实现原理是我们需要了解掌握的。

vue输入验证限制 - 浮点数限制

有了上面的经验,那我们尝试实现一个只能输入浮点数输入框。

    ...
    <input ref="num" v-model="text2Cpu" placeholder="输入小数"></input>
    ...
    // 提取字符串中符合符合浮点数的数据
    function getFloatStr(str = '', digit = 2) {
        // 是否已经出现了小数点
        var hasPoint = false;
        // 去除 数字 和 . 之外的字符
        str = str.replace(/[^0-9\.]/g, '');
        str = str.replace(/\.*/g, function(v) {
            if (v) {
                // 第一次出现的 1 到多个小数点 保留/替换为一个
                if (!hasPoint) {
                    // 第一次出现的 1 到多个小数点 保留/替换为一个
                    hasPoint = true;
                    return '.';
                }
                // 去掉其它小数点
                return '';
            }
            // 去掉其它小数点
            return v;
        });

        // var reg = new RegExp(`^\\d+\\.?\\d{0,${digit}}`);
        var reg = new RegExp('^\\d+\\.?\\d{0,'+ digit +'}');
        let m = str.match(reg);
        // console.log(m, '--');
        return !!m ? m[0] : '';
        // let r = parseFloat(str);
        // return r ? r.toFixed(digit) : '';
    }

    ...,
      data: function() {
        return {
            text: '',
            num: ''
        }
      },
      computed: {
        ...
        text2Cpu: {
            get() {
                return this.num;
            },
            set(val) {
                console.log('data before: ', val);
                this.num = getFloatStr(val, 2);
                this.$refs.num.value = this.num;
                console.log('data after: ', this.num);
            }
        }

      },

    ...

至此我们就完成了,输入框输入保留2位小数的输入限制操作。

总结

根据上面的示例,我们可以看出,输入验证对我们的考验有两个:

  1. 保持绑定数据与UI的同步。
  2. 熟练使用正则进行数据匹配、替换等。

基于以上,我想我们可以做更多类似的事情,如:

  • 只允许输入英文
  • 只允许输入16进制字符
  • 只允许输入中文
  • 不允许输入空格
  • 不允许输入特殊字符
  • 控制输入数字最小值
  • 控制输入数字最大值
  • 控制输入长度

...

必要的时候,我们可以封装成组件,便于使用。

至此,希望可以为大家提供举一反三的灵感,解决更多的问题。