基础知识
组件通信方法
props --父子
$emit/$on --子父自定义事件 派发/监听事件
evuent bus --事件总线
vuex
$parent $children --有强耦合性 减少使用
$root
$ref
provide/inject
非prop特性: $attrs $listeners
兄弟节点可以通过祖辈搭桥
//brother1
this.$parent.$emit('foo')
//brother2
this.$parent.$on('foo',handle)
$attrs $listeners 属性透传
//v-bind v-on 可以将对象直接展开
<grandson v-bind="$attrs" v-on="$listeners" />
provide/inject 隔代传参
//grandpa
export default{
provide(){
return {
foo:'this is foo',
grandpa:this
}
}
}
//grandson
export default{
inject:['foo','grandpa'],
inject:{
'alias':{}
}
}
插槽 内容分发
匿名插槽
//comp1 子组件占位符
<div>
<slot></slot>
</div>
//parent
<comp>helllo</comp>
具名插槽
//comp1 子组件占位符
<div>
<slot></slot>
<slot name='content'></slot>
</div>
//parent
<comp>
<template v-slot:default>默认不带名字的</template>
<template v-slot:content>内容</template>
</comp>
作用域插槽
//comp1 子组件占位符
<div>
<slot :foo="foo "></slot> //被替换的对象
</div>
//parent
//有一部分的数据来自于子组件 v-slot为作用域上下文对象
<comp>
<template v-slot:default=“slotProps”> //函数(参数)
子组件数据 {{slotProps.foo}}
</template>
</comp>
通用表单组件
实现内容:收集和校验数据
index页面
<template>
<MForm :model="model" :rules="rules" ref="loginForm">
<MFormItem label="用户名:" prop="username">
<MInput v-model="model.username" placeholder="请输入"</MInput>
</MFormItem>
<MFormItem>
<button @click="onLogin">登录</button>
</MFormItem>
</MForm>
</template>
<script>
import MInput from './MInput'
import MFormItem from './MFormItem'
import MForm from './MForm'
export default{
components:{
MForm,
MFormItem,
MInput
},
data(){
return {
model:{
username:'',
rules:{
username:[{
required:true,message:"用户名必填"
}]
}
}
}
},
methods:{
onLogin(){
this.$refs.loginForm.validate(isValid=>{
if(isValid){
//login
}else{
console.log('失败!')
}
})
}
}
}
</script>
[input组件] 双向绑定组件
<template>
<div>
<input type="text" :value="value" @input="onInput"
v-bind="$attrs"
/>
</div>
</template>
<script>
inheritAttrs:false,//不要将属性赋值到根组件上
export default{
props:{
value:{
type:String,
default:''
}
},
methods:{
onInput(e){
this.$emit('input',e.target.value)
//通知校验
// this.dispatch('el-form-item','validate') //源码的方法 不断找parent,根据组件名字找
this.$parent.$emit('validate')
}
}
}
</script>
<style></style>
[my-form-item]检验执行、显示错误
<template>
<div>
<label v-if="label">{{label}}</label>
<slot></slot>
<p v-if="error">{{error}}</p>
<p>{{form.rules[prop]}}</p>
</div>
</template>
<script>
import Validator from 'async-validator'
export default{
inject:['form'],
props:{
label:{
type:String,
default:''
},
prop:String
},
data(){
return {
error:'
}
},
mounted(){
this.$on('validate',()=>{
this.validate()
})
},
methods:{
validate(){
//检验库 async-validator
//获取规则和值
const rules = this.form.rules[this.prop]
const value = this.form.model[this.prop]
//校验器
//键值对 对什么检验
const validator = new Validator({[this.prop]:rules})
//return promise
return validator.validate({[this.prop]:value},(errors)=>{
if(errors){
this.error = errors[0].message
}else{
this.error=''
}
})
}
}
}
</script>
[my-form] model、rules
<template>
<div>
<slot></slot>
</div>
</template>
<script>
export default{
components:{
},
props:{
model:{
type:Object,
required:true
},
rules:Object
},
//隔代传下去 到form item
provide(){
return{
form:this
}
},
data(){
return {
}
},
methods:{
validate(cb){
//遍历所有有prop属性的item校验方法
const promises=this.$children.filter(item=>item.prop)
.map(item=>item.validate())
//全部通过则通过
Promise.all(promises).then(()=>cb(true)).catch(()=>cb(false))
}
}
}
</script>