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>
$attrs
和 v-bind="$attrs"
使用
$attrs
是vue內置屬性用來存儲外部傳向一個組件但沒有被props接收的屬性。- 這些屬性都有非prop特性:
1. 會被自動添加到組件的根元素上。
2. 默認情況下,非prop特性的屬性會覆蓋組件根元素上同名的內容。 對於style
和class
有特殊處理:進行合並(但是如果是同名樣式則會覆蓋)
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
-
祖代設置
provide
配置項,該項類似於data
的用法,但是它的數據是給后代用的,不是給自己用的。 -
后代通過
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>
問題總結
- 為什么數據模型model放在form上?
為了驗證方便,From內的FormItem驗證可能有很多,如果都寫在FormItem上會很繁瑣。 - FormItem上為什么要寫prop?
為了判別是對model里的哪部分進行校驗,也是通過這個prop去獲取規則中的key。