组件通信边界情况
demo github地址:feature/communicationOther 分支
- $parent 、 $children 、$root 、$refs
- 非Props特性(不需要Props)
$attrs ( 祖先(定义属性名) --> 父(v-bind="$attrs") --> 子($attrs.祖先属性名) )
$listeners ( 祖先(定义事件) --> 父(v-on="$listeners") --> 子($listeners.祖先事件) ) - provide / inject (跨层传参)
- $parent 、 $children 、$root 、$refs
<!--- main.js -->
new Vue({
router,
store,
render: h => h(App),
methods : {
handleRoot() { <!-- 为子组件提供根组件方法 -->
return 'event from root'
}
}
}).$mount('#app')
<!-- Parent.vue -->
<template>
<div>
<p>Parent</p>
<button @click="getChildVal">获取子传给父的值(this.$children[0].toParent)</button><br/>
<p v-if="childVal">{{childVal}}</p>
<button @click="getChildByRefs">获取子传给父的值(this.$refs.child1.toParentRefs)</button><br/>
<p v-if="childRefsVal">{{childRefsVal}}</p>
<hr/>
<Child ref="child1"></Child>
</div>
</template>
<script>
import Child from "../components/Child";
export default {
components: {
Child
},
data() {
return {
childVal: '',
childRefsVal: ''
};
},
methods: {
handleParent() {
return "event for parent!";
},
getChildVal() {
//children 是一个数组, 对于异步子组件或者按需加载子组件 children的下标 有可能不准
this.childVal = this.$children[0].toParent();
},
getChildByRefs() {
this.childRefsVal = this.$refs.child1.toParentRefs();
}
},
};
</script>
<!-- Child.vue -->
<template>
<div>
<p>Child</p>
<button @click="getParent">执行父组件方法(this.$parent.handleParent())</button><br/>
<p v-if="parent">父组件方法的返回值 : {{parent}}</p>
<button @click="getRoot">执行根组件方法(this.$root.handleRoot())</button>
<p v-if="root">根组件方法的返回值 : {{root}}</p>
</div>
</template>
<script>
export default {
data() {
return {
parent: '',
root: '',
count: 1
}
},
methods: {
getParent() {
this.parent = this.$parent.handleParent();
},
getRoot() {
this.root = this.$root.handleRoot();
},
toParent() {
return `children value to parent ${this.count++}`
},
toParentRefs(){
return 'children refs value to parent'
}
},
};
</script>
- $attrs 、$listeners 非Props特性
<!-- grandpa.vue -->
<template>
<div>
<h2>Grandpa</h2>
<hr/>
<Parent msg="把这个消息传送给我孙子" other="这个消息也别用props传了" @testOne="test1" @testTwo="test2"></Parent>
</div>
</template>
<script>
import Parent from "../components/grandpa/Parent"
export default {
components:{
Parent
},
methods: {
test1() {
alert('grandpa 传给 孙子的 第一个事件!');
},
test2() {
alert('grandpa 传给 孙子的 第二个事件!');
}
},
};
</script>
<!-- parent.vue -->
<template>
<div>
<h2>Parent</h2>
<hr/>
<Child v-bind="this.$attrs" v-on="this.$listeners"></Child>
</div>
</template>
<script>
import Child from "./Child";
export default {
components: {
Child
}
};
</script>
<!-- child.vue -->
<template>
<div>
<h2>Child</h2>
<p>这个是爷爷传给孙子的信息($attrs):<i>{{$attrs}}</i></p>
<button @click="childOne">执行grandpa的test1()</button>
<button @click="$listeners.testTwo()">执行grandpa的test2()</button>
<button @click="$emit('testOne')">执行grandpa的test1()</button>
</div>
</template>
<script>
export default {
methods: {
childOne() {
this.$listeners.testOne();
}
}
};
</script>
3.provide / inject (跨层传参)
<!-- 第一层 grandpa.vue -->
<script>
export default {
provide() {
return {
grandpa:'提供跨层参数'
}
}
}
</script>
<!-- 第三层 孙子辈儿 child.vue -->
<script>
<template>
<div>
<p>{{grandpa}}</p>
</div>
</template>
export default {
//inject : ['grandpa'],
inject: {
grandpa: {
type: String,
default: ""
}
}
}
</script>