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

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

你可能感兴趣的:(vue,vue,自定义组件,inject,provide)