刚开始学vue的一篇笔记,闲来无事翻出来瞅瞅,顺便整理下,希望可以帮助刚入门vue的同学吧。
先看一个成熟的表单组件的基本功能
html结构:
<el-form :model="model" :rules="rules">
<el-form-item label="用户名" prop="username">
<el-input v-model="model.username" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input type="password" v-model="model.password" autocomplete="off"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('loginForm')">提交</el-button>
</el-form-item>
</el-form>
vue代码:
在vue的data中定义数据模型和校验规则
data() {
return {
model: { username: "", password: "" },
rules: {
username: [
{ required: true, message: "请输入用户名" }
],
password: [
{ required: true, message: "请输入密码" },
{min: 6,max:12,message:'请输入6~12的密码'}
],
}
};
},
这是elementUI的表单组件,废话也不多写了,下面就仿造这个使用方式去实现一个我们自己的表单组件。
观察上面的html结构,分为最外层的 form
,以及内部的 form-item
和 input
。
form
主要是用来接收绑定数据模型以及校验规则的。
form-item
是用来做校验的,并显示错误提示。
input
就是一个普通的标签,与数据模型双向绑定。
废话不多写了,直接放上代码
App.vue代码:
<template>
<div id="app">
<template>
<!--仿造elementUI的使用方式-->
<my-form :model="model" :rules="rules" >
<my-form-item label="用户名" prop="username">
<my-input v-model="model.username"></my-input>
</my-form-item>
<my-form-item label="密码" prop="password">
<my-input v-model="model.password" type="password"></my-input>
</my-form-item>
</my-form>
</template>
</div>
</template>
<script>
import MyInput from './components/Input.vue';
import MyFormItem from './components/FormItem.vue';
import MyForm from './components/Form.vue';
export default {
name: "app",
components: {
MyInput,
MyFormItem,
MyForm
},
data() {
return {
// 数据模型
model: { username: "", password: "" },
// 校验规则
rules: {
username: [
{required: true, message: "请输入用户名" }
],
password: [
{required: true, message: "请输入密码" },
{min: 6,max:12,message:'请输入6~12的密码'}
],
}
};
}
};
</script>
自定义组件的使用方式是仿造elementUI的。所以内部也按照这种方式去实现。
首先要实现的是自定义input。
Input.vue文件的代码如下:
<template>
<div>
<input :type="type" :value="value" @input="onInput">
</div>
</template>
<script>
export default {
props: {
value: {
type: String,
default: ""
},
type: {
type: String,
default: "text"
}
},
methods: {
onInput(e) {
let value = e.target.value;
this.$emit("input", value);
this.$parent.$emit("validate");
}
}
};
</script>
<style scoped>
</style>
可以看到自定义input组件内部就是一个普通的input,我们要做的就是为这个input实现双向绑定。
- props中的value是在父组件中v-model双向绑定传进来的值。
- props中的type是绑定的输入框的类型,text、password。并且将值绑定到input标签上。
- input标签上的
:value
绑定的就是props传进来的value值。也就是说如果在自定义input数据模型发生改变,也能及时的更新input输入框中的值。 - input标签上的input的事件,如果input标签内容发生改变就去执行onInput方法,onInput函数再去触发input事件,使数据模型也跟着改变,这就实现了双向绑定。
onInput方法就是在input标签的值发生改变时触发,然后获取到改变后的值,触发自定义组件的input事件,并将新值作为参数传递,通知数据模型更新。另外就是触发父组件中的validate
方法,通知上一级组件form-item,“我的值改变了,请重新校验”。
FormItem.vue文件代码如下:
<template>
<div>
<label>{{label}}</label>
<div>
<slot></slot>
<p v-if="errStatus">{{errMessage}}</p>
</div>
</div>
</template>
<script>
import Schema from "async-validator";
export default {
inject: ["myForm"],
props: ["label", "prop"],
data() {
return {
errMessage: "",
errStatus: false
};
},
mounted() {
// 监听下级input组件中触发的事件
this.$on("validate", this.validator);
},
methods: {
// 校验方法
validator() {
const rules = this.myForm.rules[this.prop];
const value = this.myForm.model[this.prop];
// 描述对象
const descriptor = { [this.prop]: rules };
const schema = new Schema(descriptor);
schema.validate({ [this.prop]: value }, errors => {
if (errors) {
this.errMessage = errors[0].message;
this.errStatus = true;
} else {
this.errMessage = "";
this.errStatus = "";
}
});
}
}
};
</script>
首先html结构中预留出放input组件的插槽。
在props中获取到传进来的标题(label)、校验字段。
form-item
组件的核心就是validator
方法,首先方法内部需要拿到form
组件上的校验规则和数据模型,这里通过provide inject
选项,这是vue2.2新增的内容。(这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效(不做展开说明,自行到官方文档查阅))。这里我们inject进来的myForm
,就是在form
组件里provide
的一个变量,如果将form
组件的实例注入进来,是不是就可以拿到校验规则和数据模型了呢(二者都已经在form
组件实例中了)。通过this.prop
当前需要校验的数据模型中的字段名,就可以拿到对应的值和校验规则表中的规则。
校验部分引入第三方库进行校验,此时需要做的就是构造一个供初始化Schema使用的对象,格式就是{字段名:规则}
,如{ [this.prop]: rules };
,用中括号将this.prop扩起来就是要将this.prop的值作为对象的key。
接下来就是调用validate
方法做校验了。
Form.vue文件代码如下:
<template>
<form>
<slot></slot>
</form>
</template>
<script>
export default {
provide(){
return {
myForm: this
}
},
props:{
model:{
type:Object,
required:true
},
rules:{
type:Object
}
}
}
</script>
html结构中预留出form-item组件的插槽,props接收数据模型和校验规则,然后使用provide选项将自身实例传入,供子集使用访问数据模型和校验规则。
到这一个简易的自定义表单组件就完成了。