vue基础之自定义组件
刚开始学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><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选项将自身实例传入,供子集使用访问数据模型和校验规则。
到这一个简易的自定义表单组件就完成了。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
