组件通信
Vue的组件通信主要分为父子组件通信和跨组件通信。
父子组件通信
props/$emit
最常见的通信方式,父组件通过props向子组件传递数据,子组件通过$emit触发自定义事件通知父组件。
$attrs
如果父组件传递了一些props到子组件,但子组件没有声明这些props,则称它们为attribute,这些属性会直接附着在子组件的根元素上。不包括class和style,它们会被特殊处理。
示例:
vue
<!-- 子组件 -->
<template>
<div>
<h1>{{ msg }}</h1>
</div>
</template>
<script>
export default {
name: "HelloWorld",
props: {
msg: String,
},
created() {
console.log(this.$attrs); // { "data-a": "1", "data-b": "2" }
},
}
</script>vue
<!-- 父组件 -->
<template>
<div id="app">
<!-- 除 msg 外,其他均为 attribute -->
<HelloWorld
data-a="1"
data-b="2"
msg="Welcome to Your Vue.js App"
/>
</div>
</template>
<script>
import HelloWorld from "./components/HelloWorld.vue";
export default {
components: {
HelloWorld,
},
}
</script>渲染结果:
html
<div id="app">
<div data-a="1" data-b="2">
<h1>Welcome to Your Vue.js App</h1>
</div>
</div>子组件可以通过在选项中配置inheritAttrs: false,禁止将attribute附着在子组件的根元素上,但不影响通过$attrs获取attribute。
$listeners
子组件可以通过$listeners获取父组件传递过来的所有事件处理函数,如果我们有需要对一些ui组件进行二次封装时,就可以通过$attr和$listeners来将用户的属性和事件传递给ui组件。
示例:
vue
<template>
<el-table
v-bind="$attrs"
v-on="$listeners">
<slot></slot>
</el-table>
</template>v-model
用于给表单控件或组件进行双向数据绑定。
sync修饰符
sync修饰符类似于v-model,用于双向数据绑定,不同的是,v-model只能绑定一个数据,sync修饰符可以绑定多个。当我们希望子组件注册的事件只是修改属性时,就可以使用sync修饰符。
vue
<!-- 子组件 -->
<template>
<div>
<p>
<button @click="$emit(`update:num1`, num1 - 1)">-</button>
{{ num1 }}
<button @click="$emit(`update:num1`, num1 + 1)">+</button>
</p>
<p>
<button @click="$emit(`update:num2`, num2 - 1)">-</button>
{{ num2 }}
<button @click="$emit(`update:num2`, num2 + 1)">+</button>
</p>
</div>
</template>
<script>
export default {
props: ["num1", "num2"],
};
</script>vue
<template>
<div id="app">
<Numbers :num1.sync="n1" :num2.sync="n2" />
<!-- 等同于 -->
<Numbers
:num1="n1"
@update:num1="n1 = $event"
:num2="n2"
@update:num2="n2 = $event"
/>
</div>
</template>
<script>
import Numbers from "./components/Numbers.vue";
export default {
components: {
Numbers,
},
data() {
return {
n1: 0,
n2: 0,
};
},
};
</script>$parent 和 $children
通过$parent和$children可以获取当前组件的父组件实例和子组件实例。
slot
插槽能够让父组件访问子组件抛出的数据
vue
<!-- 子组件 -->
<template>
<span>
<slot v-bind:user="user">
{{ user.lastName }}
</slot>
</span>
</template>vue
<!-- 父组件 -->
<template>
<current-user>
<template v-slot:default="slotProps">
{{ slotProps.user.firstName }}
</template>
</current-user>
</template>ref
通过ref可以获取子组件实例或DOM元素。
跨组件通信
provide/inject
provide/inject只适用于祖先组件与其子孙后代组件通信。
js
// 父级组件提供 'foo'
var Provider = {
provide: {
foo: 'bar'
},
// ...
}
// 子组件注入 'foo'
var Child = {
inject: ['foo'],
created () {
console.log(this.foo) // => "bar"
}
// ...
}router
如果一个组件改变了地址栏,所有监听地址栏的组件都会做出相应反应。
最常见的场景就是通过点击router-link组件改变了地址,router-view组件就渲染其他内容。
vuex
适用于大型项目的状态管理工具。
eventbus
组件通知事件总线发生了某件事,事件总线通知其他监听该事件的所有组件运行某个函数。