1. 父子组件
方法一:
父组件传递参数给子组件通过props如下:
// 父组件
<template>
<div>
<hello-world msg="hello world"/>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue';
export default {
name: 'App',
components: {
HelloWorld
},
}
</script>
// 子组件使用参数
<template>
<div>
<h1>{{ msg }}</h1>
</div>
</template>
<script>
export default {
name: "HelloWorld",
props: {
msg: String
},
};
</script>
子组件要跟父组件通信:
子组件可以用emit发出事件广播,父组件监听即可
// 父组件增加监听方法
<template>
<div>
<hello-world msg="hello world" @click-it="handleClick" />
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue';
export default {
name: 'App',
components: {
HelloWorld
},
setup() {
const handleClick = (param) => {
console.log('你点我干嘛!!', param);
}
return {
handleClick
}
}
}
</script>
// 子组件
<template>
<div>
<h1 @click="handleClick">{{ msg }}</h1>
</div>
</template>
<script>
export default {
name: "HelloWorld",
props: {
msg: String
},
// vue3.0写法,通过上下文context的emit方法,触发事件
// 或者不用setup,在methods里写方法,通过this.$emit触发
setup(props, context) {
const handleClick = () => {
context.emit('click-it', 12);
}
return {
handleClick
}
}
};
</script>
方法二:
通过ref或者$parent / $children访问父子实例
ref如果用在普通DOM元素,引用的就是该DOM元素,如果用在子组件上,引用的就是组件实例
// 父组件通过ref调用子组件的方法
<template>
<div>
<!-- vue2.0写法 -->
<!-- <hello-world msg="hello world" ref="helloWorldRef" @dblclick="handleClick" /> -->
<hello-world msg="hello world" ref="helloWorldRef" @dblclick="handleClick" />
</div>
</template>
<script>
import { ref } from 'vue';
import HelloWorld from './components/HelloWorld.vue';
export default {
name: 'App',
components: {
HelloWorld
},
// vue2.0写法
// methods: {
// handleClick() {
// this.$refs.helloWorldRef.handleClick();
// }
//}
setup() {
const helloWorldRef = ref('hello');
const handleClick = () => {
helloWorldRef.value.handleClick();
}
return {
handleClick,
helloWorldRef
}
}
}
</script>
// 子组件
<template>
<div>
<h1>{{ msg }}</h1>
</p>
</div>
</template>
<script>
export default {
name: "HelloWorld",
props: {
msg: String
},
setup(props, context) {
const handleClick = () => {
console.log('你点我干嘛!!');
}
return {
handleClick
}
}
};
</script>
2. 兄弟组件
通过EventBus,定义一个vue
实例作为事件中心,触发和监听事件,可以实现父子,兄弟,隔代组件之间的通信
// vue 2.0
const eventBus = new Vue()
eventBus.$emit('some-action', value);
eventBus.$on('some-action', (value) => {})
3. 隔代组件
隔代组件也可以通过EventBus来实现,也可以通过$attrs / $listeners
在vue2.0中:
孙子组件的$attrs
中包含了父组件中,不在props
中指定过的属性,如果父组件没有设置props,则$attrs
就包含了祖先组件传入的所有属性;
在父级组件中,可以通过v-bind="$attrs"
来把属性传入子级组件。
同理:
$listeners
是所有绑定的方法,可以通过v-on="$listeners"
传入子级组件
在vue3.0中
$attrs / $listeners
都继承到了setup(props, context)
的context
上下文对象的attrs
属性里(属性和方法都在一起)
// -------------------
// 祖先组件
<template>
<div>
// 往子组件传入参数,属性值和方法都可以
<hello-world msg="hello world" ref="helloWorldRef" @dblclick="handleClick" />
</div>
</template>
<script>
import { ref } from 'vue';
import HelloWorld from './components/HelloWorld.vue';
import { eventBus } from './utils/eventBus';
export default {
name: 'App',
components: {
TodoList,
HelloWorld
},
setup() {
const helloWorldRef = ref('hello');
const handleClick = () => {
helloWorldRef.value.handleClick();
}
return {
handleClick,
helloWorldRef
}
}
}
</script>
// -----------------------
//父级组件
<template>
<div>
<h1>{{ msg }}</h1>
// 通过v-bind="attrs"传递到孙级组件
<vote v-bind="attrs"/>
<button @click="count++">count is: {{ count }}</button>
<p>
Edit
<code>components/HelloWorld.vue</code> to test hot module replacement.
</p>
</div>
</template>
<script>
import Vote from './vote.vue';
import { watchEffect } from "vue";
export default {
name: "HelloWorld",
components: {
Vote
},
props: {
// props里指定的属性,不会通过v-bind="attrs"传递到下一级组件
// msg: String
},
setup(props, context) {
// vue3.0中,attrs属性绑定在context上下文对象上
console.log(context.attrs)
const handleClick = () => {
console.log('你点我干嘛!!');
}
return {
// 暴露出attrs对象,便于模板中传递给下一级组件
attrs: context.attrs,
handleClick
}
}
};
</script>
// -----------------------------
// 孙级组件
// 创建组件方式跟以前一样
<template>
<div>
<h3>{{msg}}投票</h3>
</div>
</template>
<script>
import { ref, reactive, computed } from 'vue';
export default {
// 设置props接收属性,便于模板里直接使用
props: {
msg: String,
},
setup(props, context) {
// cann't use this
console.log(context.attrs);
return {
// 。。。
}
},
}
</script>
vue2.0用法差不多,只不过$attrs, $listeners挂在this上
4. 不管几代都能通信的方法:
-
vuex
-
Vue.observable()
observable返回的是一个响应式数据
如下:在需要的组件里引入store响应式数据,同时引用mutations里的方法修改数据即可。
import Vue from 'vue';
const initialStore = {
count: 0,
}
export const store = Vue.observable(initialStore);
export const mutations = {
countAdd() {
store.count += 1;
},
countMinus() {
store.count -= 1;
}
}
- provide / inject
https://cn.vuejs.org/v2/api/#provide-inject
provide在祖先组件中指定,可以是一个对象,也可以是一个返回对象的方法;该对象包含可注入其子孙的 property
inject在子代组件中指定,可以是一个数组或者一个对象
这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效,跟react里的context差不多
// 父级组件提供 'foo'
var Provider = {
provide: {
foo: 'bar'
},
// ...
}
// 子组件注入 'foo'
var Child = {
inject: ['foo'],
created () {
console.log(this.foo) // => "bar"
}
// ...
}
特别注意:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的 property 还是可响应的