目录
项目需求 : 使用的饿了么组件库的 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”
- 存在的问题
- type="number" 允许输入 e
- maxlength 属性会不生效
- 可以输入1.1.....11...1
第二种、使用 oninput
<el-input v-model='inputValue' oninput="value=value.replace(/[^\d]/g,'')" maxLength='9' />
- 存在的问题
测试的时候偶然发现,有时候会出现输入框的值没有绑定到 v-model 上
暂时不知道原因,也比较难复现,而且输入汉字时数字可能会被删除
绑定的 @input 事件 , 有时会失效 , 暂时不知原因。
第三种、使用 onkeypress
<el-input v-model="length" :maxlength="3" placeholder="长 cm" onkeypress='return( /[\d]/.test(String.fromCharCode(event.keyCode)))' />
- 存在的问题
这个代码一开始可以输中文 , 只有输数字时才不可以输入其他
第四种、使用 onafterpaste
<el-input v-model='inputValue' onafterpaste="this.value=this.value.replace(/[\D]/g,'')" maxLength='9' />
- 存在的问题
- @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>