子组件调用父组件方法
1、直接在子组件中通过 this.$parent.event 来调用父组件的方法
父组件:
<template>
<p>
<child></child>
</p>
</template>
<script>
import child from '~/components/dam/child';
export default {
components: {
child
},
methods: {
fatherMethod() {
console.log('测试');
}
}
};
</script>
子组件:
<template>
<p>
<button @click="childMethod()">点击</button>
</p>
</template>
<script>
export default {
methods: {
childMethod() {
this.$parent.fatherMethod();
}
}
};
</script>
2、父组件使用 v-on 监听事件,子组件使用 $emit 件触发事件
@ 是 v-on 的缩写
父组件:
<template>
<p>
<child @method1="fatherMethod"></child>
</p>
</template>
<script>
import child from '~/components/dam/child';
export default {
components: {
child
},
methods: {
fatherMethod(params) {
console.log('测试', params);
}
}
};
</script>
子组件:
<template>
<p>
<button @click="childMethod()">点击</button>
</p>
</template>
<script>
export default {
methods: {
childMethod() {
this.$emit('method1', params); // params为参数,可不传
// this.$emit('method1');
}
}
};
</script>
3、父组使用 v-bind 绑定事件,子组件用 props 接收事件
: 是 v-bind 的缩写
父组件:
<template>
<p>
<child :method1="fatherMethod"></child>
</p>
</template>
<script>
import child from '~/components/dam/child';
export default {
components: {
child
},
methods: {
fatherMethod() {
console.log('测试');
}
}
};
</script>
子组件:
<template>
<p>
<button @click="childMethod()">点击</button>
</p>
</template>
<script>
export default {
props: {
method1: {
type: Function,
default: null
}
},
methods: {
childMethod() {
if (this.method1) {
this.method1();
}
}
}
};
</script>
父组件调用子组件方法
1、通过 ref 直接调用子组件的方法
父组件:
<template>
<div>
<Button @click="fatherMethod">点击调用子组件方法</Button>
<Child ref="child"/>
</div>
</template>
<script>
import Child from './child';
export default {
methods: {
fatherMethod() {
this.$refs.child.childMethod();
},
},
}
</script>
子组件:
<template>
<div>我是子组件</div>
</template>
<script>
export default {
methods: {
childMethod() {
console.log('我是子组件的方法');
},
},
};
</script>
2、通过组件的$emit、$on方法(可以,但是没必要)
父组件:
<template>
<div>
<Button @click="fatherMethod">点击调用子组件方法</Button>
<Child ref="child"/>
</div>
</template>
<script>
import Child from './child';
export default {
methods: {
fatherMethod() {
this.$refs.child.$emit("getChildMethod") //子组件$on中的名字
},
},
}
</script>
子组件:
<template>
<div>我是子组件</div>
</template>
<script>
export default {
mounted() {
this.$nextTick(function() {
this.$on('getChildMethod', this.childMethod);
});
},
methods: {
childMethod() {
console.log('我是子组件方法');
}
}
};
</script>
兄弟组件
-
方法1、通过父组件作为中转
-
通过 ref 和 $parent
-
通过 provide 和 inject
-
-
方法2、使用 EventBus 事件总线
-
方法3、vuex
EventBus 使用方式
1、初始化——全局定义
全局定义
可以将 eventBus 绑定到 vue 实例的原型上,也可以直接绑定到 window 对象上
//main.js
//注册方式一
Vue.prototype.$EventBus = new Vue();
//注册方式二
window.EventBus = new Vue();
2、监听事件
//使用方式一
this.$EventBus.$on('eventName', (param1, param2, ...) => {
//需要执行的代码
})
//使用方式二
EventBus.$on('eventName', (param1, param2, ...) => {
//需要执行的代码
})
3、触发事件
//使用方式一
this.$EventBus.$emit('eventName', param1, param2,...)
//使用方式二
EventBus.$emit('eventName', param1, param2,...)
4、移除监听事件
为了避免在监听时,事件被反复触发,通常需要在页面销毁时移除事件监听。或者在开发过程中,由于热更新,事件可能会被多次绑定监听,这时也需要移除事件监听。
//使用方式一
this.$EventBus.$off('eventName');
//使用方式二
EventBus.$off('eventName');
//移除所有
EventBus.$off();
示例
简单示例一:
<!--ComponentA.vue-->
<script>
import bus from 'bus.js'
export default {
mounted() {
// 监听事件
bus.$on('custom-event', this.handleEvent)
},
methods: {
handleEvent(data) {
console.log(data)
}
}
}
</script>
<!--ComponentB.vue-->
<template>
<button @click="handleClick">触发事件</button>
</template>
<script>
import bus from 'bus.js'
export default {
data() {
return {
str: '我来自 B 组件'
}
}
methods: {
handleClick() {
// 触发事件
bus.$emit('custom-event', this.str)
}
}
}
</script>
示例二:
假设兄弟组件有三个,分别是 A、B、C 组件,A 组件如何获取 B 或者 C 组件的数据
这时候就可以使用 EventBus。EventBus 是一种发布/订阅模式,用于在组件之间传递事件和数据。A 组件可以监听由 B 或 C 组件发布的事件,并在事件处理函数中获取传递的数据。
思路:
A 组件中使用 Event.$on 监听事件
B、C 组件中使用 Event.$emit 触发事件
// A.vue
<template>
<div>A 接收到的数据: {{ receivedData }}</div>
</template>
<script>
import { EventBus } from './event-bus.js';
export default {
data() {
return {
receivedData: null
};
},
mounted() {
// 监听事件
EventBus.$on('custom-event', (data) => {
this.receivedData = data.message;
});
},
beforeDestroy() {
// 组件销毁前,移除事件监听器
EventBus.$off('custom-event');
}
};
</script>
// B.vue 和 C.vue
<template>
<button @click="sendData">发送数据</button>
</template>
<script>
export default {
methods: {
sendData() {
const data = { message: 'I am from B' };
// 触发事件
EventBus.$emit('data-from-a', data);
}
}
};
</script>
多层组件(爷孙)
provide() 和 inject[]
主要用作孙组件调用爷组件方法。
爷/父:
<script>
export default {
name: 'parent',
components: { Child },
provide() {
return {
parentEvent1: this.myEvent1,
parentEvent2: this.myEvent2,
};
},
methods: {
myEvent1(params1, params2) {
console.log(params1, params2)
}
myEvent2() {
console.log(2)
}
}
};
</script>
子/孙:
<template>
<el-button @click="handleClick">测试</el-button>
</template>
<script>
export default {
name: 'child',
injectL: ["parentEvent1", "parentEvent2"],
methods: {
handleClick() {
this.parentEvent1('参数1', '参数2');
this.parentEvent2()
}
}
};
</script>
$attrs
使用场景:
-
$attrs ['ətrz] 是在 Vue2.40 版本以上添加的。
-
主要用作爷组件向孙组件传递数据。
作用:
包含了父作用域中没有被 prop 接收的所有属性(不包含 class 和 style 属性)。可以通过 v-bind="$attrs" 直接将这些属性传入内部组件。
爷:
<!-- A 组件 -->
<template>
<div>
<div class="a">
<p>A组件</p>
<p>A: {{params1}}</p>
<p>A: {{params2}}</p>
<el-button @click="handleClick">传递</el-button>
<B :params1="params1" :params2="params2"></B>
</div>
</div>
</template>
<script>
import B from './B.vue';
export default {
name: 'A',
components: { B },
data() {
return {
params1: '111',
params2: '222'
};
},
mounted() {
console.log("A $attrs:", this.$attrs); // {} 空的
},
methods: {
handleClick() {
this.params1 = "params1"
this.params2 = "params2"
}
}
};
</script>
<style lang="less" scoped>
.a {
border: 1px solid red;
}
</style>
父:
<!-- B 组件 -->
<template>
<div class="b">
<p>B组件</p>
<p>B: {{ $attrs.params1 }}</p>
<p>B: {{ $attrs.params2 }}</p>
<C v-bind="$attrs"></C>
</div>
</template>
<script>
import C from "./C.vue";
export default {
components: { C },
name: "B",
inheritAttrs: true, // 默认值是 true
// 如果 B 组件使用 props 接收了数据,那么 C 组件的 $attrs 就接收不到了
// props: {
// params1: {
// type: String,
// dedault: "",
// },
// params2: {
// type: String,
// dedault: "",
// },
// },
mounted() {
console.log("B $attrs:", this.$attrs); // { "params1": "111", "params2": "111" }
// console.log("b params1:", this.params1);
// console.log("b params2:", this.params2);
},
};
</script>
<style lang="less" scoped>
.b {
border: 1px solid #000;
}
</style>
子:
<!-- C组件 -->
<template>
<div class="c">
<p>C组件</p>
<p>C: {{ params1 }}</p>
<p>C: {{ params2 }}</p>
</div>
</template>
<script>
export default {
name: "C",
inheritAttrs: true,
// C 组件用 props 接收 A 组件传递的值
props: {
params1: {
type: String,
dedault: "",
},
params2: {
type: String,
dedault: "",
},
},
mounted() {
/*
如果 C 组件用 props 接受收了值,则 this.$attrs 是空的
不用 props 接收值,则可以直接使用 $attrs.xxx 接收
*/
console.log("C $attrs:", this.$attrs); // {} 空的
console.log("C params1:", this.params1); // params1: 111
console.log("C params2:", this.params2); // params2: 222
},
};
</script>
<style lang="less" scoped>
.c {
border: 1px solid blue;
}
</style>
页面:
执行顺序:
inheritAttrs: true 的作用:
官方解释:如果使用 $arrts 给子组件传递的数据,子组件不使用 props 接收,那么这些数据将作为子组件的特性,这些特性绑定在组件的 HTML 根元素上,在 vue2.40 版本之后,可以通过 inheritAttrs = false(默认是 true) 来控制这些特性是否显示在 DOM 元素上
作用:inheritAttrs为true:继承除props之外的所有属性;inheritAttrs为false:只继承class属性
$listeners
作用:
包含所有父组件中的 v-on 事件监听器 (不包含.native修饰器的) ,可以通过v-on="$listeners"传入内部组件。
与 $attrs 类似,$attrs 是传递属性,$listeners 是传递方法。
例如:
<!--父-->
<template>
<div class="outer">
<h3>父组件</h3>
<div>myData:{{ myData }}</div>
<child @changeData="changeMyData"></child>
</div>
</template>
<script>
import Child from "./Child";
export default {
name: 'Parent',
components: {Child},
data() {
return {
myData: 100
};
},
methods: {
changeMyData(val) {
this.myData = val;
}
}
}
</script>
<!--子-->
<template>
<div class="outer">
<h3>子组件</h3>
<grand-child v-on="$listeners"></grand-child>
</div>
</template>
<script>
import GrandChild from "./GrandChild";
export default {
components: {GrandChild}
}
</script>
<!--孙-->
<template>
<div class="outer">
<h3>孙组件</h3>
<input v-model="data1" @input="edit"/>
</div>
</template>
<script>
export default {
name: "GrandChild",
data() {
return {
data1: 200,
}
},
methods: {
edit() {
// 发送事件
this.$emit("changeData", this.data1);
}
}
}
</script>