一、12种方法汇总
- 1.通过属性传值prop
- 2.修饰符 .sync
- 3.v-model
- 4.通过 ref 注册子组件引用
- 5.通过$parent获取父组件实例的方法或者属性
- 6.$children
- 7.通过事件传值 $emit
- 8.Vuex
- 9.eventBus
- 10.provide / inject
- 11.通过 $root 访问根实例
- 12. attrs与listenter
1.prop
父组件向子组件传送数据最常用的方法
// 父组件 List.vue
<template>
<div>
<List-item :str="str" :obj="obj" :arr="arr"></List-item>
</div>
</template>
<script>
import ListItem from "./ListItem";
export default {
data() {
return {
str: "给子组件传值",
obj: {msg: "给子组件传值"},
arr: [1, 2, 3]
}
},
components: {
ListItem
}
}
</script>
// 子组件 ListItem.vue
<template>
<div>
<div>{{msg}}</div>
<div>{{obj}}</div>
<div>{{arr}}</div>
</div>
</template>
<script>
export default {
props: {
msg: String, // props是字符串
obj: Object, // props是对象
arr: Array // props是数组
}
}
</script>
2、3. v-model和 .async
v-model 和 .async 的通信方式和区别可以看我另一篇文章详解 juejin.cn/post/710648…
4.ref
尽管存在 prop 和事件,有的时候你仍可能需要在 JavaScript 里直接访问一个子组件。为了达到这个目的,可以通过 ref 特性为这个子组件赋予一个 ID 引用
<template>
<div>
<List-item ref="item" :title="title"></List-item>
<div>{{data}}</div>
</div>
</template>
<script>
import ListItem from "./List-item";
export default {
data() {
return {
title: "我是title",
data: ""
}
},
components: {
ListItem
},
mounted() {
this.data = this.$refs.item.message;
}
}
</script>
5.$parent
这种方式,从严格意思上讲不是值的传递,而是一种"取"(不推荐直接通过实例进行值的获取)。
可以通过 Vue 的实例属性 $parent 获得父组件的实例,借助实例可以调用父实例中的方法,或者获取父实例上的属性,从而达到取值的目的。
// 父组件 List.vue
...
<script>
export default {
data() {
return {
message: "hello children",
msg: "hello"
}
},
methods: {
sendMessage() {
return this.message;
}
}
}
</script>
// 子组件 ListItem.vue
<template>
<div>
<div>{{data}}</div>
<div>{{msg}}</div>
</div>
</template>
<script>
export default {
data() {
return {
data: "",
msg: ""
}
},
mounted() {
this.data = this.$parent.sendMessage(); // 调用父实例中的方法
this.msg = this.$parent.msg; // 获取父实例中的属性
}
}
</script>
- 通过
$parent获取父实例this.$parent.event。 - 通过
props传递方法。 - 通过
$emit监听父组件中的方法this.$emit("event")。
6.$children
获取父组件下的所有子组件的实例,返回的是一个数组 使用范围:该属性只针对vue组件,与js中childNodes还是有区别的。
$ildren: 获取子组件实例集合
hildNodes: 获取子节点集合
使用方法:
<template>
<A></A>
<B></B>
</template>
<script>
export default{
data(){},
mounted(){
// 通过$children可以获取到A和B两个子组件的实例
console.log('children:',this.$children)
}
}
</script>
其中,
this.$children[0]
可以获取到A组件的实例,一样的,我们可以使用A组件的属性以及他的方法。
7.$emit
子组件使用 $emit 发送一个自定义事件,事件名称是一个字符串。
父组件使用指令 v-on 绑定子组件发送的自定义事件。
// 父组件 List.vue
<template>
<div>
<!-- 监听自定义事件 -->
<List-item v-on:welcome="getWelcome"></List-item>
</div>
</template>
<script>
import ListItem from "./List-item";
export default {
components: {
ListItem
},
methods: {
getWelcome(data) {
alert(data)
}
}
}
</script>
// 子组件 ListItem.vue
<template>
<button @click="handleClick">Click me</button>
</template>
<script>
export default {
methods: {
handleClick() {
// 使用 $emit 发送自定义事件 welcome
this.$emit('welcome', 'hello');
}
}
}
</script>
8.Vuex
// store/index.js
import { createStore } from "vuex"
export default createStore({
state:{ count: 1 },
getters:{
getCount: state => state.count
},
mutations:{
add(state){
state.count++
}
}
})
// main.js
import { createApp } from "vue"
import App from "./App.vue"
import store from "./store"
createApp(App).use(store).mount("#app")
// Page.vue
// 方法一 直接使用
<template>
<div>{{ $store.state.count }}</div>
<button @click="$store.commit('add')">按钮</button>
</template>
// 方法二 获取
<script setup>
import { useStore, computed } from "vuex"
const store = useStore()
console.log(store.state.count) // 1
const count = computed(()=>store.state.count) // 响应式,会随着vuex数据改变而改变
console.log(count) // 1
</script>
9.eventBus
eventBus够简化各组件间的通信,让我们的代码书写变得简单,能有效的分离事件发送方和接收方(也就是解耦的意思),能避免复杂和容易出错的依赖性和生命周期问题
// 方法一
// 抽离成一个单独的 js 文件 Bus.js ,然后在需要的地方引入
// Bus.js
import Vue from "vue"
export default new Vue()
// 方法二 直接挂载到全局
// main.js
import Vue from "vue"
Vue.prototype.$bus = new Vue()
// 方法三 注入到 Vue 根对象上
// main.js
import Vue from "vue"
new Vue({
el:"#app",
data:{
Bus: new Vue()
}
})
// 在需要向外部发送自定义事件的组件内
<template>
<button @click="handlerClick">按钮</button>
</template>
import Bus from "./Bus.js"
export default{
methods:{
handlerClick(){
// 自定义事件名 sendMsg
Bus.$emit("sendMsg", "这是要向外部发送的数据")
}
}
}
// 在需要接收外部事件的组件内
import Bus from "./Bus.js"
export default{
mounted(){
// 监听事件的触发
Bus.$on("sendMsg", data => {
console.log("这是接收到的数据:", data)
})
},
beforeDestroy(){
// 取消监听
Bus.$off("sendMsg")
}
}
10. provide / inject
provide / inject 为依赖注入
provide:可以让我们指定想要提供给后代组件的数据或
inject:在任何后代组件中接收想要添加在这个组件上的数据,不管组件嵌套多深都可以直接拿来用
// Parent.vue
<script setup>
import { provide } from "vue"
provide("name", "沐华")
</script>
// Child.vue
<script setup>
import { inject } from "vue"
const name = inject("name")
console.log(name) // 沐华
</script>
11.$root
通过 $root,任何组件都可以获取当前组件树的根 Vue 实例,通过维护根实例上的 data,就可以实现组件间的数据共享。
//main.js 根实例
new Vue({
el: '#app',
store,
router,
// 根实例的 data 属性,维护通用的数据
data: function () {
return {
author: ''
}
},
components: { App },
template: '<App/>',
});
<!--组件A-->
<script>
export default {
created() {
this.$root.author = '于是乎'
}
}
</script>
<!--组件B-->
<template>
<div><span>本文作者</span>{{ $root.author }}</div>
</template>
注意:通过这种方式,虽然可以实现通信,但在应用的任何部分,任何时间发生的任何数据变化,都不会留下变更的记录,这对于稍复杂的应用来说,调试是致命的,不建议在实际应用中使用。
12. attrs 与attrs与listenter
多层嵌套组件传递数据时,如果只是传递数据,而不做中间处理的话就可以用这个,比如父组件向孙子组件传递数据时
$attrs:包含父作用域里除 class 和 style 除外的非 props 属性集合。通过this.attrs获取父作用域中所有符合条件的属性集合,然后还要继续传给子组件内部的其他组件,就可以通过v−bind = " attrs 获取父作用域中所有符合条件的属性集合,然后还要继续传给子组件内部的其他组件,就可以通过 v-bind="attrs获取父作用域中所有符合条件的属性集合,然后还要继续传给子组件内部的其他组件,就可以通过v−bind="attrs"
$listeners:包含父作用域里 .native 除外的监听事件集合。如果还要继续传给子组件内部的其他组件,就可以通过 v-on=“$linteners”
使用方式是相同的:
// Parent.vue
<template>
<child :name="name" title="1111" ></child>
</template
export default{
data(){
return {
name:"小解"
}
}
}
// Child.vue
<template>
// 继续传给孙子组件
<sun-child v-bind="$attrs"></sun-child>
</template>
export default{
props:["name"], // 这里可以接收,也可以不接收
mounted(){
// 如果props接收了name 就是 { title:1111 },否则就是{ name:"小解", title:1111 }
console.log(this.$attrs)
}
}
常见使用场景可以分为三类:
- 父子组件通信:
props、$parent / $children、provide / inject、ref \ $refs、$attrs / $listeners - 兄弟组件通信:
eventBus、vuex、自己实现简单的 Store 模式 - 跨级通信:
eventBus、Vuex、自己实现简单的 Store 模式、provide / inject、$attrs / $listeners