UI组件库Form表单_数字类型验证之坑&实现数字框

目录

Input 输入框

实现数字框封装使用


项目需求 : 使用的饿了么组件库的 input 框 , 但是想要 实现用户只能输入 数字 的功能

So 看到了数字类型的验证 (缺点 :不能阻止用户输入非数字内容 , 只能是给提示警告而已)

但今天在项目里对照着组件库示例代码写都能频繁报错 ,简直大无语啊 。 。 。

所以自己整理一下 , 免得自己以后掉坑 。 。 。

<template>
  <div class="formBox">
    <div class="infos">
      <div class="infoBox">
        <el-form
          :model="numberValidateForm"
          ref="numberValidateForm"
          label-width="100px"
          class="demo-ruleForm"
          label-position="left"
        >
          <el-form-item label="姓名" prop="name" :rules="name">
            <el-input
              v-model="numberValidateForm.name"
              autocomplete="off"
              placeholder="请输入姓名"
            ></el-input>
          </el-form-item>
          <el-form-item label="联系电话" prop="phone" :rules="phone">
            <el-input
              v-model="numberValidateForm.phone"
              autocomplete="off"
              placeholder="请输入电话号码"
            ></el-input>
          </el-form-item>
          <el-form-item label="树龄" prop="number" :rules="number">
            <el-input
              type="number"
              v-model.number="numberValidateForm.number"
              autocomplete="off"
              placeholder="请输入树龄"
            ></el-input>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" @click="submitForm('numberValidateForm')"
              >提交</el-button
            >
            <el-button @click="resetForm('numberValidateForm')">重置</el-button>
          </el-form-item>
        </el-form>
      </div>
    </div>
  </div>
</template>
<script>
const cryptoJs = new CryptoJs();
export default {
  data() {
    let checkValue = (rule, value, callback) => {
      if (!value) {
        return callback(new Error("值不能为空"));
      }
      setTimeout(() => {
        if (!Number.isInteger(value)) {
          callback(new Error("请输入数字值"));
        } else {
          if (value < 1) {
            callback(new Error("值必须大于1"));
          } else {
            callback();
          }
        }
      }, 200);
    };
    return {
      numberValidateForm: {
        name: "", // 姓名
        phone: "", // 电话
        number: null, // 数量
      },
      name: { required: true, message: "姓名不能为空" },
      phone: { required: true, message: "联系电话不能为空" },
      number: [
        { required: true, validator: checkValue, trigger: ["change", "blur"] },
      ],
    };
  },
  methods: {
    submitForm(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          let params = this.numberValidateForm;
          console.log("验证成功,参数为", params);
        } else {
          console.log("数据验证不成功");
          return false;
        }
      });
    },
    //重置
    resetForm(formName) {
      this.$refs[formName].resetFields();
    },
  },
};
</script>
<style lang="scss" scoped>
@import "./index.scss";
</style>


百度的各种写法 :(希望有一个能用得上吧)

<template>
  <div class="formBox">
    <div class="infos">     
      <div class="infoBox">
        <el-form
          :model="numberValidateForm"
          ref="numberValidateForm"
          label-width="100px"
          class="demo-ruleForm"
          label-position="left"
        >        
        <el-form-item label="姓名" prop="name" :rules="name">
            <el-input
              v-model="numberValidateForm.name"
              autocomplete="off"
              placeholder="请输入姓名"
            ></el-input>
          </el-form-item>
          <el-form-item label="联系电话" prop="phone" :rules="phone">
            <el-input
              v-model="numberValidateForm.phone"
              autocomplete="off"
              placeholder="请输入电话号码"
            ></el-input>
          </el-form-item>  
          <el-form-item label="树龄" prop="number" :rules="number">
            <el-input
              type="number"
              v-model.number="numberValidateForm.number"
              autocomplete="off"
              placeholder="请输入树龄"
            ></el-input>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" @click="submitForm('numberValidateForm')"
              >提交</el-button
            >
            <el-button @click="resetForm('numberValidateForm')">重置</el-button>
          </el-form-item>
        </el-form>
      </div>
    </div>
  </div>
</template>
<script>
const cryptoJs = new CryptoJs()
export default {
  data () {
    let checkValue = (rule, value, callback) => {
      if (!value) {
        return callback(new Error('值不能为空'))
      }
      setTimeout(() => {
        if (!Number.isInteger(value)) {
          callback(new Error('请输入数字值'))
        } else {
          if (value < 1) {
            callback(new Error('值必须大于1'))
          } else {
            callback()
          }
        }
      }, 200)
    }
    return {
      numberValidateForm: {
        name: '', // 姓名
        phone: '', // 电话
        number: null // 数量
      },
      name: { required: true, message: '姓名不能为空' },
      phone: { required: true, message: '联系电话不能为空' },
      number: [{ required: true, validator: checkValue, trigger: ['change', 'blur'] }]
    }
  },
  methods: {
    submitForm (formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          let params = this.numberValidateForm
         console.log('验证成功,参数为',params)
        } else {
            console.log('数据验证不成功')
          return false
        }
      })
    },
    //重置
    resetForm (formName) {
      this.$refs[formName].resetFields()
    }
  }
}
</script>
<style lang="scss" scoped>
@import "./index.scss";
</style>

form 表单 rules 验证

1. el-form ,设置 :rules="rules"   ref="ruleForm"

2. el-form-item ,设置 :prop="name"

3. 具体需验证的字段中 , v-model="name"

4. script 的 data 中 ,

rules:{
        name:[
             {required:true,message:'不能为空,请选择菜单名称',trigger:'change'},
         ],
  }

5. 提交按钮中 ,@click="submit('ruleForm')

6. methods 中 ,

submit(formName) {
       this.$refs[formName].validate((valid) => {
       if (valid) {
            console.log('submit')
       }else{
             console.log('error submit');
              return false;
       }
 })

7. 重置校验,在取消按钮或取消事件中,

 this.$refs['ruleForm'].resetFields()

以下是完整例子 : 需要注意以下几点:
 :model 一定要绑定一个 对象 , 本例子是 editForm , 同时要验证字段的 v-model 绑定数据一定要在 editForm 中 .
同时 prop 绑定的名字要和 v-model 绑定的名字一样 , 这个是很重要, 一般做法是 prop 和 rules 规则还有 v-model 绑定的数据 所有的名称都一样
直观方便, 且不容易出错. 

<template>
  <div>
    <el-form
      :model="editForm"
      ref="editForm"
      :rules="rules"
      label-position="left"
      label-width="100px"
    >
      <el-row :gutter="24">
        <el-col :span="12">
          <el-form-item label="姓名">
            <el-input
              v-model="multipleSelectionStudent"
              placeholder="请选择"
            ></el-input>
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="地区" prop="selectSources">
            <el-cascader
              v-model="editForm.selectSources"
              placeholder="请选择"
              :clearable="true"
              :options="options.resourceGroup"
              change-on-select
              :props="cascaderProp"
              class="el-cascader-100p"
            ></el-cascader>
          </el-form-item>
        </el-col>
      </el-row>
      <button @click="submit">提交</button>
    </el-form>
  </div>
</template>

<script>
export default {
  data() {
    return {
      editForm: {
        selectSources: [],
      },
      rules: {
        selectSources: [
          { required: true, message: "请选择", trigger: "change" },
        ],
      },
    };
  },
  methods: {
    submitForm(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          alert("submit!");
        } else {
          console.log("error submit!!");
          return false;
        }
      });
    },
  },
};
</script>

<style lang="scss" scoped>
</style>

使用过程中遇到的各种报错信息 :

Property or method "numberValidateForm" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components , by initializing the property.

属性或方法“numberValidateForm”未在实例上定义,但在渲染期间被引用。通过初始化属性,确保此属性在数据选项中或对于基于类的组件是被动的。


[Vue warn]: Invalid prop: type check failed for prop "model". Expected Object, got String with value "".

[Vue warn]:无效道具:道具“模型”的类型检查失败。应为对象,获取了值为“”的字符串。


最后自己在项目中所用代码 :

<template>
  <!-- 自定义校验规则 -->
  <div class="formBox">
    <!-- :model 绑定的一定要是一个 对象 numberValidateForm: {}
否则会报错 : 类型检查失败。应为对象,获取了值为 “” 的字符串 -->
    <el-form
      label-position="top"
      :model="numberValidateForm"
      ref="numberValidateForm"
      label-width="200px"
      class="demo-ruleForm"
    >
      <el-form-item size="mini">
        <!-- 文本类型输入框 -->
        <el-input
          v-if="item.quInputType === '1'"
          v-model="item.modelValue"
          type="textarea"
          :style="`width:${item.answerInputWidth}px`"
          :rows="item.answerInputRow"
          placeholder="请输入内容"
        ></el-input>
        <!-- 日期类型输入框 -->
        <el-date-picker
          v-if="item.quInputType === '2'"
          :readonly="true"
          v-model="item.dateValue"
          type="date"
          placeholder="请选择日期"
        ></el-date-picker>
        <!-- 数字类型输入框 -->
        <!-- prop 要跟 rules 规则里的名字对应一致 -->
        <el-form-item
          v-if="item.quInputType === '3'"
          prop="numValue"
          :rules="numValue"
        >
          <el-input
            size="small"
            autocomplete="off"
            type="numValue"
            v-model.number="item.numberValidateForm.numValue"
            :maxlength="item.numDigit"
            @input="handleNumInput('numberValidateForm')"
            placeholder="请输入数字"
          ></el-input>
        </el-form-item>
      </el-form-item>
    </el-form>
  </div>
</template>
<script>
export default {
  data() {
    return {
      // 在 item 中的数据字段
      numberValidateForm: {
        numValue: "", // 数字输入框的绑定值
      },
      quInputType: "1", // input 类型 : 1.文本 2.日期 3.数字
      modelValue: "", // 默认文本域绑定值
      answerInputWidth: "300", // input 宽度
      answerInputRow: "1", // input 高度
      dateValue: "", // 日期选择器绑定值
      numValue: [
        { required: true, message: "内容不能为空" },
        { type: "number", message: "内容必须为数字" },
      ],
      numValue: "", // 数字输入框绑定值
      numDigit: "1", // 控制数字位数
    };
  },
  methods: {
    handleNumInput(formName) {
      // 输入时实时校验
      /* 注意 : 这里有个大坑啊, 我的 this.$refs[formName]. 一直提示报错 : 不是一个函数
      通过打印才发现层级出现了点问题, 改成 this.$refs[formName][0] 就 OK 了
      也不知道是不是只有我的是如此 (如果你也出现了类似情况, 不妨就加上 [0] 试一试吧) */
      this.$refs[formName][0].validate((valid) => {
        if (valid) {
          let params = this.numberValidateForm;
          console.log("验证成功,参数为", params);
        } else {
          console.log("数据验证不成功");
          return false;
        }
      });
    },
  },
};
</script>
<style lang="scss" scoped>
</style>

后来呢 , 因为这种方法只能给到一个提示作用 ,却并不能阻止到用户继续输入非数字内容 ,

所以继续百度搜寻方法 ,=>  Vue 只能输入数字

不过呢这个有个问题就是使用的 v-bid: value  , 来控制的输入框输入内容 , 

所以无法再使用 v-model  来进行双向绑定了 (缺点)

<template>
  <div class="formBox">
    <el-form label-position="top" label-width="200px" class="demo-ruleForm">
      <el-form-item size="mini">
        <!-- 文本类型输入框 -->
        <el-input
          v-if="item.quInputType === '1'"
          v-model="item.modelValue"
          type="textarea"
          :style="`width:${item.answerInputWidth}px`"
          :rows="item.answerInputRow"
          placeholder="请输入内容"
        ></el-input>
        <!-- 日期类型输入框 -->
        <el-date-picker
          v-if="item.quInputType === '2'"
          :readonly="true"
          v-model="item.dateValue"
          type="date"
          placeholder="请选择日期"
        ></el-date-picker>
        <!-- 数字类型输入框 -->
        <!-- :value 导致 v-model 双向绑定失效 -->
        <!-- v-model.number="item.numValue" -->
        <el-input
          v-if="item.quInputType === '3'"
          size="small"
          :maxlength="item.numDigit"
          @input="handleNumInput"
          :value="inputNum"
          placeholder="请输入数字"
        ></el-input>
      </el-form-item>
    </el-form>
  </div>
</template>
<script>
export default {
  data() {
    return {
      // 在 item 中的数据字段
      numValue: "", // 数字输入框的绑定值
      quInputType: "1", // input 类型 : 1.文本 2.日期 3.数字
      modelValue: "", // 默认文本域绑定值
      answerInputWidth: "300", // input 宽度
      answerInputRow: "1", // input 高度
      dateValue: "", // 日期选择器绑定值
      numValue: "", // 数字输入框绑定值
      numDigit: "1", // 控制数字位数
      oldInputNum: "" /* 数字类型输入框初始值 */,
    };
  },
  computed: {
    inputNum() {
      return this.oldInputNum;
    },
  },
  methods: {
    handleNumInput(event) {
      /* 此方法因为使用了 v-bind:value , 所以原本的 v-model 双向绑定就不能使用了 , 
      否则此方法会不生效 , 因此就需要我们自己去获取到用户最后输入的值了 */
      // 缺点就是没有了双向绑定的便利性了
      // let val = event.target.value.trim();
      let val = event.trim();
      // 只能是正整数或空,可根据需求修改正则
      // item = e.target.value.replace(/[^\d]/g,'')
      if (/^[1-9]\d*$|^$/.test(val)) {
        this.oldInputNum = val;
      } else {
        // event.target.value = this.oldInputNum;
        event = this.oldInputNum;
      }
    },
  },
};
</script>
<style lang="scss" scoped>
</style>

最后试用了老项目里的代码方法 , 直接在 输入框上写 oninput 事件

    <el-input
      oninput="this.value=this.value.replace(/\D/g,'')"
      onafterpaste="this.value=this.value.replace(/\D/g,'')"
    ></el-input>

但是此方法不知为何 , 用户在输入完一些数字之后 , 再输入汉字时 , 可能会将所输入的数字删除掉 , 可能是正则的 replace 导致的 , 因此这可能会影响到 v-model 的正常取值

只能通过获取用户最后一次输入的值赋值给 v-model 绑定的值了

<template>
  <div>
    <!-- 数字类型输入框 -->
    <el-input
      v-if="item.quInputType === '3'"
      size="small"
      :maxlength="item.numDigit"
      v-model.number="item.numValue"
      oninput="this.value=this.value.replace(/\D/g,'')"
      @change="handleNumInput($event, item)"
      placeholder="请输入数字"
    ></el-input>
  </div>
</template>

<script>
export default {
  data() {
    return {
      // 在 item 中的数据字段
      numValue: "", // 数字输入框的绑定值
      quInputType: "1", // input 类型 : 1.文本 2.日期 3.数字
      modelValue: "", // 默认文本域绑定值
      answerInputWidth: "300", // input 宽度
      answerInputRow: "1", // input 高度
      dateValue: "", // 日期选择器绑定值
      numValue: "", // 数字输入框绑定值
      numDigit: "1", // 控制数字位数
    };
  },
  methods: {
    handleNumInput(event, item) {
      // 为了防止 v-model 失效 , 只好将最后一次输入的值赋值给绑定值了
      item.numValue = event;
    },
  },
};
</script>

<style lang="scss" scoped>
</style>

另外的一些解决思路及存在问题 :

Input 输入框

通过鼠标或键盘输入字符

基础用法


需求 :输入框限制用户只能输入数字

这个问题我使用过很多办法, 每一种都去尝试,但是结果都不太理想
比如以下的几种方法

注:我要的效果是,输入框内只可输入数字,除了数字其他什么都不可输入,

包括标点符号,英文在内

第一种、使用 el-input 原生自带的  type=“number”

  • 存在的问题
  1. type="number" 允许输入 e
  2. maxlength 属性会不生效
  3. 可以输入1.1.....11...1

第二种、使用 oninput

<el-input
 v-model='inputValue'
 oninput="value=value.replace(/[^\d]/g,'')"
 maxLength='9'
/>
  • 存在的问题
  1. 测试的时候偶然发现,有时候会出现输入框的值没有绑定到 v-model 上

  2. 暂时不知道原因,也比较难复现,而且输入汉字时数字可能会被删除

  3. 绑定的 @input 事件 , 有时会失效 , 暂时不知原因。

第三种、使用 onkeypress

<el-input
 v-model="length" :maxlength="3" placeholder="长 cm" 
 onkeypress='return( /[\d]/.test(String.fromCharCode(event.keyCode)))' />
  • 存在的问题
  1. 这个代码一开始可以输中文 , 只有输数字时才不可以输入其他

第四种、使用 onafterpaste

<el-input
 v-model='inputValue'
 onafterpaste="this.value=this.value.replace(/[\D]/g,'')"
 maxLength='9'
/>
  • 存在的问题
  1. @input 绑定的 input 输入事件 , 会获取到你输入的最后一个非数字内容

第五种、监听 v-model 绑定值


侧面解决方案 :

利用 form 表单自带的校验功能

ElementUI - Form 表单 - 数字类型验证

缺点 : 不会限制用户输入非数字内容 , 只是会给警告提示 , 达不到预期需求效果

<el-form :model="numberValidateForm" ref="numberValidateForm" label-width="100px" class="demo-ruleForm">
  <el-form-item
    label="年龄"
    prop="age"
    :rules="[
      { required: true, message: '年龄不能为空'},
      { type: 'number', message: '年龄必须为数字值'}
    ]"
  >
    <el-input type="age" v-model.number="numberValidateForm.age" autocomplete="off"></el-input>
  </el-form-item>
  <el-form-item>
    <el-button type="primary" @click="submitForm('numberValidateForm')">提交</el-button>
    <el-button @click="resetForm('numberValidateForm')">重置</el-button>
  </el-form-item>
</el-form>
<script>
  export default {
    data() {
      return {
        numberValidateForm: {
          age: ''
        }
      };
    },
    methods: {
      submitForm(formName) {
        this.$refs[formName].validate((valid) => {
          if (valid) {
            alert('submit!');
          } else {
            console.log('error submit!!');
            return false;
          }
        });
      },
      resetForm(formName) {
        this.$refs[formName].resetFields();
      }
    }
  }
</script>


解决方案 :

试验了两天时间 , 才搞出来了自我感觉良好的效果 :(查阅各种资料 , 综合总结)

" ^[0-9]*[1-9][0-9]*$ " //正整数

上代码 , 自行体会哦

<template>
  <div class="formBox">
    <!-- 阻止回车提交行为 -->
    <el-form label-position="top" @submit.native.prevent>
      <el-form-item size="mini">
        <!-- 文本类型输入框 -->
        <el-input
          v-if="item.quInputType === '1'"
          v-model="item.modelValue"
          type="textarea"
          :style="`width:${item.answerInputWidth}px`"
          :rows="item.answerInputRow"
          placeholder="请输入文本内容"
        ></el-input>
        <!-- 日期类型输入框 -->
        <el-date-picker
          v-if="item.quInputType === '2'"
          :readonly="true"
          v-model="item.dateValue"
          type="date"
          placeholder="请选择日期"
        ></el-date-picker>
        <!-- 数字类型输入框 -->
        <el-input
          v-if="item.quInputType === '3'"
          size="small"
          :maxlength="item.numDigit"
          v-model.number="item.numValue"
          @input="handleNumInput($event, item)"
          placeholder="请输入正整数"
        ></el-input>
      </el-form-item>
    </el-form>
  </div>
</template>
<script>
export default {
  data() {
    return {
      // 在 item 中的数据字段
      numValue: "", // 数字输入框的绑定值
      quInputType: "1", // input 类型 : 1.文本 2.日期 3.数字
      modelValue: "", // 默认文本域绑定值
      answerInputWidth: "300", // input 宽度
      answerInputRow: "1", // input 高度
      dateValue: "", // 日期选择器绑定值
      numValue: "", // 数字输入框绑定值
      numDigit: "1", // 控制数字位数
    };
  },
  methods: {
    handleNumInput(event, item) {
      if (!/^[0-9]*[1-9][0-9]*$/.test(event)) {
        // 如果是非数字内容则 replace 切除掉
        item.numValue = event.replace(/\D/g, "");
      }
    },
  },
};
</script>
<style lang="scss" scoped>
</style>

实现数字框封装使用

开始封装 :

<!-- 作者 : 小灰狼
     功能 : 数字框
     时间 : 2022/04 -->
<template>
  <div>
    <el-input
      v-if="inputShow"
      :readonly="readonly"
      :disabled="disabled"
      :size="inputSize"
      :style="inputStyle"
      :maxlength="maxlength"
      :placeholder="placeholder"
      v-model="modelValue.val"
      @input="handleNumInput($event, modelValue.val)"
    >
    </el-input>
  </div>
</template>

<script>
// 导入数字型输入框封装函数
import { digitalInput } from "../../utils/digitalInput";

export default {
  name: "numInput",
  props: {
    inputShow: {
      // 控制是否显示数字框
      type: Boolean,
      required: true,
      default: false,
    },
    readonly: {
      // 控制数字框是否只读
      type: Boolean,
      required: true,
      default: false,
    },
    disabled: {
      // 控制数字框是否禁用
      type: Boolean,
      default: false,
    },
    inputSize: {
      // 控制数字框大小
      type: String,
      required: true,
      default: "small",
    },
    inputStyle: {
      // 控制数字框样式
      type: Object,
      required: true,
      default: {},
    },
    maxlength: {
      // 控制数字框内容长度
      type: String,
      required: true,
      default: "1",
    },
    placeholder: {
      // 数字框提示文本
      type: String,
      required: true,
      default: "正整数",
    },
    modelValue: {
      // 数字框绑定值
      // type: Object,
      required: true,
      default: {},
    },
  },
  methods: {
    handleNumInput(event, val) {
      // 限制用户输入非数字内容
      this.modelValue.val = digitalInput(event, val);
      // this.$emit("handleNumInput", digitalInput(event, val));
    },
  },
};
</script>

<style lang="scss" scoped>
</style>

digitalInput.js 文件

/** 数字型输入框
 * @param {} event 事件对象
 * @param {} modelValue 输入框绑定值
 * @return {} 处理好的内容
 */
// 限制用户只能输入数字
export const digitalInput = (event, modelValue) => {
  // 限制用户输入非数字内容
  if (!/^[0-9]*[1-9][0-9]*$/.test(event)) {
    modelValue = event.replace(/\D/g, "");
  }
  console.log(modelValue, "封装函数");
  return modelValue;
};

开始使用 :

<template>
  <div>
    <!-- 数字框组件 -->
    <num-input
      :inputShow="quInputType === '3'"
      :readonly="false"
      :inputSize="'small'"
      :inputStyle="{ width: '300px' }"
      :maxlength="numlength"
      :placeholder="'请输入正整数'"
      :modelValue="modelValue"
    ></num-input>
  </div>
</template>
 
<script>
// 导入数字框组件
import numInput from "../../../components/common/numInput.vue";
 
export default {
  name: "container",
  components: {
    numInput, // 数字框组件
  },
  data() {
    return {
      quInputType: "3", // 类型
      numlength: "1", // 控制数字位数
      modelValue: {
        val: "1",
      },
    };
  },
  methods: {},
};
</script>
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值