父子组件传值 | 字节青训营

49 阅读3分钟

这是我参与「第五届青训营」伴学笔记创作活动的第 14 天

父传子:父组件引入子组件注册后在子组件标签上v-bind要传的属性,子组件用props对象接收

子传父:子组件通过绑定事件出发函数,设置this.$emit('事件名',传递值),父组件在子组件标签上@事件名并绑定事件触发的methods方法接收

兄弟:主要有两种,通过eventbus或vuex;eventbus是创建一个空的vue并暴露出去,作为公共bus成为兄弟组件的桥梁,在兄弟组件中分别引入刚才创建的bus,在组件A中通过bus.emit(事件,传递值)发送数据,组件B中通过bus.emit('事件名',传递值)发送数据,组件B中通过bus.on('事件名',function(v){//v即要接收的值})接收数据;vuex中组件通过dispatch到actions,然后actions是异步操作,在actions中通过commit到mutations,mutations在通过逻辑操作改变state,从而同步到组件,更新数据状态。

this.$emit('itemClick',index)//子触发事件来通知父组件改变数据,index为传的参数
@itemClick="childClick"     //父标签里绑定改变
  • 组件使用三步骤:
  1. 创建组件构造器 Vue.extend()
  2. 注册组件Vue.component()
  3. 使用组件,Vue实例作用范围内使用

方式总结

1、props

2、.sync子组件可以修改父组件内容

3、父v-model + 子$emit也可双向绑定,相当于.sync语法糖

4、ref,如果在dom元素引用指向的是该dom元素,在子组件指向的是子组件实例,父组件可以通过 ref 主动获取子组件的属性或者调用子组件的方法

5、父v-on或@ + 子$emit

6、attrs+attrs + listeners:多层嵌套组件传递数据时,如果只是传递数据,而不做中间处理的话就可以用这个,比如父组件向孙子组件传递数据时

7、children+children+parent:获取到一个包含所有子组件(不包含孙子组件)的 VueComponent 对象数组,可以直接拿到子组件中所有数据和方法等

8、provide / inject:是依赖注入,在一些插件或组件库里被常用,provide:可以让我们指定想要提供给后代组件的数据或方法;inject:在任何后代组件中接收想要添加在这个组件上的数据或方法,不管组件嵌套多深都可以直接拿来用

要注意的是 provideinject 传递的数据不是响应式的,也就是说用 inject 接收来数据后,provide 里的数据改变了,后代组件中的数据不会改变,除非传入的就是一个可监听的对象 所以建议还是传递一些常量或者方法

9、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()
    }
})
​
// 在需要向外部发送自定义事件的组件内用$emit
<template>
    <button @click="handlerClick">按钮</button>
</template>
import Bus from "./Bus.js"
export default{
    methods:{
        handlerClick(){
            // 自定义事件名 sendMsg
            Bus.$emit("sendMsg", "这是要向外部发送的数据")
        }
    }
}
// 在需要接收外部事件的组件内用$on
import Bus from "./Bus.js"
export default{
    mounted(){
        // 监听事件的触发
        Bus.$on("sendMsg", data => {
            console.log("这是接收到的数据:", data)
        })
    },
    beforeDestroy(){
        // 在组件销毁时别忘了解除事件绑定
        Bus.$off("sendMsg")
    }
}

10、vuex

import { mapGetters, mapMutations } from "vuex"
export default{
    computed:{
        // 方式一 然后通过 this.属性名就可以用了
        ...mapGetters(["引入getters.js里属性1","属性2"])
        // 方式二
        ...mapGetters("user", ["user模块里的属性1","属性2"])
    },
    methods:{
        // 方式一 然后通过 this.属性名就可以用了
        ...mapMutations(["引入mutations.js里的方法1","方法2"])
        // 方式二
        ...mapMutations("user",["引入user模块里的方法1","方法2"])
    }
}
​
// 或者也可以这样获取
this.$store.state.xxx
this.$store.state.user.xxx

11、$root:访问根组件中的属性或方法 12、slot插槽:把子组件的数据通过插槽的方式传给父组件使用,然后再插回来

父子组件之间的生命周期执行顺序

初次渲染就会触发的生命周期

  • beforeCreate() , created()
  • beforeMount() , mounted()

组件的调用顺序都是先父后子,渲染完成的顺序是先子后父。 组件的销毁操作是先父后子,销毁完成的顺序是先子后父。

加载渲染过程 子组件在父组件的beforeMount和Mounted之间渲染

- 父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted

子组件更新过程

- 父beforeUpdate->子beforeUpdate->子updated->父updated

父组件更新过程

- 影响到子组件: - 父beforeUpdate -> 子beforeUpdate->子updated -> 父updted
- 不影响子组件: - 父beforeUpdate -> 父updated

销毁过程

- 父beforeDestroy->子beforeDestroy->子destroyed->父destroyed