vue組件化開發實戰 - 實現簡易ElementUI的Form表單組件


Input 組件

功能:

  • 進行數據雙綁
  • 通知FormItem組件校驗
<template>
  <div>
     <input  :type="type" :value="value" @input="onInput" v-bind="$attrs" >
  </div>
</template>
<script>
export default {
    inheritAttrs:false,
    props:{
        value:{
            type: String,
            default: ''
        },
        type:{
            type: String,
            default: 'text'
        },  
    },
    methods:{
        onInput(e){
            this.$emit('input',e.target.value);
            // 讓父組件自己派發自己監聽該valid事件進行校驗。 
            this.$parent.$emit('valid');
        }
    }
}
</script>

$attrsv-bind="$attrs" 使用

  • $attrs是vue內置屬性用來存儲外部傳向一個組件但沒有被props接收的屬性。
  • 這些屬性都有非prop特性
    1. 會被自動添加到組件的根元素上。
    2. 默認情況下,非prop特性的屬性會覆蓋組件根元素上同名的內容。 對於styleclass有特殊處理:進行合並(但是如果是同名樣式則會覆蓋)
    3. 如果不希望組件根元素繼承非prop特性,可以在組件配置項中配置 inheritAttrs:false ( 該API對style和class沒影響 )

v-bind="$attrs"是對$attrs進行解構賦值的一種方法,解構成:key="value"形式。

FormItem 組件

功能:

  • 校驗
  • label顯示
  • 錯誤顯示
<template>
  <div>
    <label v-if="label">{{label}}</label>
    <slot></slot>      
    <p v-if="error">{{error}}</p>
  </div>
</template>
<script>
  import Schema from 'async-validator'; // 校驗包
  export default {
    inject:['form'],
    props:{
      label:{
        type:String,
        default:''
      },
      prop:{
        type:String,
        default:''
      }
    },
    data(){
      return {
        error:''
      }
    },
    mounted(){
      this.$on('valid',()=>{
          this.validate();
      })
    },
    methods:{
      validate(){
        const rules = this.form.rules[this.prop];
        const value = this.form.model[this.prop];

        const schema = new Schema({[this.prop]:rules});
        // 返回Promise<Boolean>
        return schema.validate({[this.prop]:value},(errors)=>{
          if(errors){
            this.error = errors[0].message;
          }else{
            this.error = '';
          }
        })
      }
    }
  }
</script>   

Form 組件

功能:

  • 提供數值
<template>
    <div>
        <slot></slot>
    </div>
</template>
<script>
export default {
    provide(){
        return {
            form:this  // 把form組件實例傳給后代,后代可以通過該實例訪問該組件上的屬性 model、rule ...
        }
    },
    props:{
        model:{
            type:Object,
            reuqired:true
        },
        rules:{
            type:Object,
        }
    },
    methods:{
        validate(cb){
            const checkRes = this.$children
            .filter(item => item.prop)
            .map(item => item.validate());

            Promise.all(checkRes)
            .then(()=>cb(true))
            .catch(()=>cb(false));
        }
    }
}
</script>

通用庫開發中常用的跨層級傳參方法 provide / inject

  1. 祖代設置provide配置項,該項類似於data的用法,但是它的數據是給后代用的,不是給自己用的。

  2. 后代通過inject配置項獲取祖代提供的數據。

        inject: ['form'] // 祖代provide中的key值
    

通過該方式可以避免第三方庫的引入如vuex,如果層級深也不需要通過props的方法進行繁瑣的傳遞。

使用

<template>
    <div>
        <Form :model="model" :rules="rules" ref="myform">
            <FormItem label="用戶名" prop="username">
                <Input v-model="model.username" placeholder="輸入用戶名" @ev="func" />
            </FormItem>
            <FormItem label="密碼" prop="password" >
                <Input v-model="model.password" placeholder="輸入密碼" type="password" @ev="func" />
            </FormItem>
             <FormItem >
                 <button @click="submitForm('myform')">提交</button>
            </FormItem>
        </Form>
    </div>
</template>
<script>
import Input from '@/components/form/Input'; 
import Form from '@/components/form/Form'; 
import FormItem from '@/components/form/FormItem';
export default {
    components:{
        Input,
        Form,
        FormItem
    },
    data(){
        return{
            model:{
                username:'',
                password:'',
            },
            rules:{
                username:[{required:true,message:'用戶名必填'}],            
                password:[{required:true,message:'密碼必填'}],
            },
        }
    },
    methods:{
        submitForm(form){
            this.$refs[form].validate(valid=>{
                if(valid){
                    alert('校驗通過');
                }else{
                    alert('校驗失敗');
                }
            })
        }
    }
}
</script> 

問題總結

  1. 為什么數據模型model放在form上?
    為了驗證方便,From內的FormItem驗證可能有很多,如果都寫在FormItem上會很繁瑣。
  2. FormItem上為什么要寫prop?
    為了判別是對model里的哪部分進行校驗,也是通過這個prop去獲取規則中的key。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM