美文网首页
vue——如何编写自定义组件

vue——如何编写自定义组件

作者: _BuzzLy | 来源:发表于2020-04-27 19:07 被阅读0次

    刚开始学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-iteminput
    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选项将自身实例传入,供子集使用访问数据模型和校验规则。

    到这一个简易的自定义表单组件就完成了。

    相关文章

      网友评论

          本文标题:vue——如何编写自定义组件

          本文链接:https://www.haomeiwen.com/subject/xlbuwhtx.html