**vue 父子间通信 总结**
优化了之前的内容,添加了新的组件通信方式,共7种方式,感兴趣的小伙伴可以慢慢积累,总有用得到的时候。
组件之间通信
组件是 vue.js 强大的功能,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用。
根据组件传递数据的方向不同,分为父组件向子组件传值,子组件向父组件传值。
这两种传值方向,是通过props、$ref, $emit,provide和inject,vuex,eventBus,以及 $attrs/ $listeners 来实现的。
父组件向子组件传值(父传子)
props
- 子组件的props选项能够接收来自父组件数据。
- props是单向绑定的,即只能父组件向子组件传递,不能反向。
- 传递的方式也分为两种:一种为静态数据,一种为动态传递
父组件
<template>
<div class="father">
<el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
<el-form-item label="密码" prop="pass">
<el-input type="password" v-model="ruleForm.pass" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="确认密码" prop="checkPass">
<el-input type="password" v-model="ruleForm.checkPass" autocomplete="off"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('ruleForm')">提交</el-button>
<el-button @click="resetForm('ruleForm')">重置</el-button>
</el-form-item>
</el-form>
<!-- 调用子组件 -->
<!-- 当父组件数据填写完成之后,点击提交,调用子组件 -->
<div v-if="show">
<!-- 1.静态传递 -->
<Child password='更改成功'></Child> <!-- 通过自定义属性传递数据 -->
<!-- 2.动态传递 -->
<Child :password='this.ruleForm.checkPass'></Child>
<Child v-bind:password='this.ruleForm.checkPass'></Child>
</div>
</div>
</template>
<script>
// 引入子组件
import Child from './Child';
export default {
data() {
// 对表单提交,进行简单的校验,可忽略
var validatePass = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入密码'));
} else {
if (this.ruleForm.checkPass !== '') {
this.$refs.ruleForm.validateField('checkPass');
}
callback();
}
};
var validatePass2 = (rule, value, callback) => {
if (value === '') {
callback(new Error('请再次输入密码'));
} else if (value !== this.ruleForm.pass) {
callback(new Error('两次输入密码不一致!'));
} else {
callback();
}
};
// 对表单提交,进行简单的校验,可忽略
return {
// 表单中绑定的数据
ruleForm: {
pass: '',
checkPass: '',
age: ''
},
// 对表单提交,进行简单的校验,可忽略
rules: {
pass: [
{ validator: validatePass, trigger: 'blur' }
],
checkPass: [
{ validator: validatePass2, trigger: 'blur' }
]
},
// 对表单提交,进行简单的校验,可忽略
show: false,
};
},
// 引入子组件
components: {
Child
},
methods: {
// 点击提交,调用方法
submitForm(formName) {
// 对表单提交,进行简单的校验,可忽略
this.$refs[formName].validate((valid) => {
// 对表单提交,进行简单的校验,可忽略
if (valid) {
// 当校验成功时,显示子组件
// console.log('submit!');
this.show = true;
} else {
console.log('error submit!!');
return false;
}
});
},
resetForm(formName) {
this.$refs[formName].resetFields();
}
}
}
</script>
子组件
<template>
<div class="child">
<el-alert
title="新密码:"
type="success">
<span>{{password}}</span>
<!-- 可直接使用从父组件接收的数据 -->
</el-alert>
</div>
</template>
<script>
import Child from './Child';
export default {
data() {
return {
show: false,
password: ''
};
},
props: {
password: String
// 声明一个自定义的属性
},
}
</script>
子组件通过props选项来声明一个自定义的属性,然后父组件就可以在嵌套标签的时候,通过这个属性往子组件传递数据了。
实现的效果图
父组件输入密码
子组件接收数据
子组件向父组件传值(子传父)
$emit( eventName, […args] )
- $emit绑定一个自定义事件event,当这个这个语句被执行到的时候,就会将参数arg传递给父组件,父组件通过@event监听并接收参数。
- 也就是子组件绑定父组件中的方法,通过回调,将数据传递给父组件。
子组件
methods: {
handleClick () {
// 向父组件传值
this.$emit('getChild', this.message);
}
}
父组件
// 调用方法,接收传值
getSuccess (value) {
console.log(value);
this.$message({
message: value,
type: 'success'
});
},
可以定义一个事件来触发响应的$emit,使父组件可以知道有事件改变,进而接收对应的参数。
兄弟组件之间的传值
兄弟组件之间的传值和父子组件之间的传值非常相似,都是通过$emit;
原理是:vue一个新的实例,类似于一个站,连接着两个组件,也就是一个中央事件总线。
子组件
import Child from './Child';
import Brother from './Borther';
methods: {
handleClick () {
// 向父组件传值
this.$emit('getChild', this.message);
// 兄弟组件传值
Brother.$emit('getChild', this.message);
}
}
兄弟组件接收方式与父组件接收方式一样。
父组件调用子组件方法并传值
父组件
// 调用子组件的方法
this.$refs.child.getMessage(this.detail);
- child为子组件在父组件的名称,保持一致。
- getMessage(this.detail) 中,getMessage为子组件中的方法,this.detail为父组件传给子组件方法的数据。
- 实现父组件给子组件传参,并调用方法。
上面三种方式是我们常用的vue通信方式,为什么又添加了现在这些方法呢?因为上面三种是基础,后面的方式是进阶。可以慢慢积累起来。
provide和inject
provide和inject组件传值,适用于有跨度的组件传值,比如祖父组件—>孙子组件,跨级访问的情况给下使用。
单向传值,由provide传递给inject
-
provide:是一个对象,或者是一个返回对象的函数。里面呢就包含要给子孙后代的东西,也就是属性和属性值。
-
inject:一个字符串数组,或者是一个对象。属性值可以是一个对象,包含from和default默认值。
// 父组件
provide() {
return {
message: "this is demo",
};
},
// 孙组件、子组件
inject: ["message"],
关于provide和inject的传参,在实际应用场景中很方便,但是在使用的过程中,因为项目中可能有很多组件需要传参,如果用provide可能会导致我们inject拿到参数的时候,不知道是哪个组件传递的。(仅代表个人研发过程中的观点)
事件车——非父子之间传值
- 创建eventBus.js文件
import Vue from "vue";
export default new Vue()
2.注册事件车
在main.js中将事件绑定在vue上
import Vue from "vue";
Vue.prototype.$eventBus = new Vue();
到这一步已经创建好了eventBus事件车了,接下来可以使用了
$emit触发一个事件,自定义一个事件,第二个参数是我们将要传递的数据
this.$eventBus.$emit("myFun", data);
$on接收传递的参数
this.$eventBus.$on("myFun", (data) => {
console.log(data)
// 这个地方可以写接收data后想要执行的方法和操作
});
vuex
vuex是状态管理,数据存储,项目需要的话可以使用vuex
$attrs和 $listeners
$attrs: 包含了父作用域中不被prop所识别的特性绑定,当组件没有声明任何prop时,这里会包含所有的父作用域的绑定,通过v-bind=‘ $attrs’ 传入内部组件,配个interitAttrs选项一起使用
$listeners
$listeners:包含了父作用域中的v-on事件监听器,可以通过v-on=’ $listeners’ 传入内部组件
需要关闭自动性挂在在组件根元素的没有prop声明的属性
interitAttrs: false
总结
- 父子组件通信需要一定的媒介,也就是中间站。
- 调用方法进行传值。