记录 模拟el-form实现过程
<form @submit.prevent>
<slot></slot>
</form>
</template>
<script>
export default {
name: "elForm",
provide() {
return { elForm: this };
},
props: {
model: {
type: Object,
default: () => ({}),
},
rules: {
type: Object,
default: () => ({}),
},
},
methods: {
//el-form 看下内部el-form-item 是否都通过了校验
async validate(cb) {
let children = this.$broadcast("elFormItem");
try {
await Promise.all(
children.map((child) => {
return child.validate();
})
);
cb(true);
} catch {
cb(false);
}
},
},
};
</script>
`
}, }; `
<input type="text" :value="value" @input="handleInput">
</template>
<script>
export default {
name:"elInput",
props:{
value:{
type:String
}
},
methods:{
handleInput(e){
this.$emit('input',e.target.value)
//触发el-form-item的validate
//$dispatch拿到最外层的父组件 $parent
//$broadcast 拿到所有的子组件
this.$dispatch("elFormItem","validate")
}
}
}
</script>
<div id="app">
<!-- ruleForm 数据源 rules规则 -->
<el-form :model="ruleForm" :rules="rules" ref="ruleForm">
<el-form-item label="用户名" prop="username">
<el-input v-model="ruleForm.username"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input v-model="ruleForm.password"></el-input>
</el-form-item>
<el-form-item>
<button @click="submitForm">提交表单</button>
</el-form-item>
</el-form>
</div>
</template>
<script>
//1.掌握插槽的应用 2.props,$emit $parent $children provide inject的使用
//2.组件的双向数据绑定
import elForm from "@/components/el-form";
import elFormItem from "@/components/el-form-item";
import elInput from "@/components/el-input";
export default {
data(){
return {
ruleForm:{
username:"",
password:""
},
rules:{
username:[
{required:true,message:'请输入用户名'},
{min:3,max:5,message:'长度在3到5个字符'}
],
password:[
{required:true,message:"请输入密码"}
]
}
}
},
components:{
"el-form":elForm,
"el-form-item":elFormItem,
"el-input":elInput
},
methods:{
submitForm(){
this.$refs.ruleForm.validate(valid=>{
if(valid){
alert('submit')
}else{
console.log('error submit')
return false;
}
})
}
}
}
</script>
let parent = this.$parent
while(parent){
let name = parent.$options.name;
if(name === componentName ){
break;
}else{
parent = parent.$parent
}
}
if(parent){
if(eventName){
parent.$emit(eventName)
}
return parent //返回父组件
}
}
//拿到componentName所有的子组件并触发对应的事件
Vue.prototype.$broadcast = function(componentName,eventName){
let children = this.$children;
let arr = []
function findChildren(children){
children.forEach(child=>{
if(child.$options.name === componentName){
if(eventName){
child.$emit(eventName)
}else{
arr.push(child)
}
}
if(child.$children){
findChildren(child.$children)
}
})
}
findChildren(children)
return arr;
}