vue子父组件之间通信

一、vue2.0

  1. 父 ==> 子 通信 (props、$refs、this.$children)
    • 方式一:props:传值 单向绑定的,即只能父组件向子组件传递,不能反向。而传递的方式也分为两种:

    • 方式二:**$ref** (可以调用子组件的方法跟改变属性值

      • 如果ref用在子组件上,指向的是组件实例,可以理解为对子组件的索引,通过$ref可能获取到在子组件里定义的属性和方法。
      • 如果ref在普通的 DOM 元素上使用,引用指向的就是 DOM 元素,通过$ref可能获取到该DOM 的属性集合,轻松访问到DOM元素,作用与JQ选择器类似。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      <!-- 父组件 -->

      <template>
      <div>
      <h1>我是父组件!</h1>
      <child ref="msg"></child>
      </div>
      </template>

      <script>
      import Child from '../components/child.vue'
      export default {
      components: {Child},
      mounted: function () {
      console.log( this.$refs.msg);
      this.$refs.msg.getMessage('我是子组件一!')
      }
      }
      </script>
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
       <!-- 子组件 -->

      <template>
      <h3>{{message}}</h3>
      </template>
      <script>
      export default {
      data(){
      return{
      message:''
      }
      },
      methods:{
      getMessage(m){
      this.message=m;
      }
      }
      }
      </script>
    • 方式三:this.$children(应急用)

      • 如果ref用在子组件上,指向的是组件实例,可以理解为对子组件的索引,通过$ref可能获取到在子组件里定义的属性和方法。
      • 如果ref在普通的 DOM 元素上使用,引用指向的就是 DOM 元素,通过$ref可能获取到该DOM 的属性集合,轻松访问到DOM元素,作用与JQ选择器类似。
  2. 子 ==> 父通信 (**$emit**、this.$parent.event、函数绑定 )
    • 方式一:$emit 在子组件里用$emit向父组件触发一个事件,父组件监听这个事件就行了(最常用)
      • 不带参

        1
        vm.$emit( event, arg )
      • 带参(子向父传值:this.$emit(“name”,“值”); 父接收:@name:name (自定义方法接收);)

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        子组件:

        <template>
        <h3>我是子组件!</h3>
        </template>
        <script>
        export default {
        mounted: function () {
        this.$emit('getMessage', '我是父组件!')
        }
        }
        </script>
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        父组件:

        <template>
        <div>
        <h1>{{title}}</h1>
        <child @getMessage="showMsg"></child>
        </div>
        </template>

        <script>
        import Child from '../components/child.vue'
        export default {
        components: {Child},
        data(){
        return{
        title:''
        }
        },
        methods:{
        showMsg(title){
        this.title=title;
        }
        }
        }
        </script>
    • 方式二:父组件把方法传入子组件中,在子组件里直接调用这个方法
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      父组件:

      <template>
      <div>
      <child :fatherMethod="fatherMethod"></child>
      </div>
      </template>
      <script>
      import child from '~/components/dam/child';
      export default {
      components: {
      child
      },
      methods: {
      fatherMethod() {
      console.log('测试');
      }
      }
      };
      </script>
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      子组件:

      <template>
      <div>
      <button @click="childMethod()">点击</button>
      </div>
      </template>
      <script>
      export default {
      props: {
      fatherMethod: {
      type: Function,
      default: null
      }
      },
      methods: {
      childMethod() {
      if (this.fatherMethod) {
      this.fatherMethod();
      }
      }
      }
      };
      </script>
    • 方式三:this.$parent.event 直接在子组件中来调用父组件的方法
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      父组件:

      <template>
      <div>
      <child></child>
      </div>
      </template>
      <script>
      import child from '~/components/dam/child';
      export default {
      components: {
      child
      },
      methods: {
      fatherMethod() {
      console.log('测试');
      }
      }
      };
      </script>
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      子组件:

      <template>
      <div>
      <button @click="childMethod()">点击</button>
      </div>
      </template>
      <script>
      export default {
      methods: {
      childMethod() {
      this.$parent.fatherMethod();
      }
      }
      };
      </script>

二、vue3.0

  1. 父 ==> 子 通信 (props、$refs、this.$children)
    • 方式一:props:传值 单向绑定的,即只能父组件向子组件传递,不能反向。而传递的方式也分为两种:
      • 静态传递:不使用v-bind eg: message=”我是子组件一!”
      • 动态传递: 使用v-bind动态绑定 例子:v-bind:message=“mess”
    • 方式二:this.$children(应急用)
  2. 父 ==> 孙 通信 (provide / inject)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    父组件中:

    template:

    <b><b>

    import b from './b.vue'
    import { reactive, provide } from 'vue'

    components: {
    b
    },
    setup () {
    const mmm = reactive({
    list: [
    111,
    222,
    333
    ]
    })
    provide('mmm', mmm.list)
    },
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    子组件中:

    <template>
    <c></c>
    </template>
    <script>
    import c from './c.vue'
    export default {
    components: {
    c
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    孙子组件中:

    <template>
    <ul>
    <li v-for="(item, index) in list" :key="index">{{item}}</li>
    </ul>
    </template>
    <script>
    import { inject } from 'vue'
    export default {
    setup () {
    const list = inject('mmm')
    const parentClick = (e) => {
    alert(1)
    }
    return {
    list,
    parentClick
    }
    }
    }
    </script>
  3. 子 ==> 父通信 (emit、$parent.event 、函数绑定 )
    • 方式一:emit 在子组件里用emit向父组件触发一个事件,父组件监听这个事件就行了(最常用)

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      父组件:

      <template>
      <!-- 父组件 -->
      <div class="parent">
      <Child :num="count" @handle="changeValue" />
      <button @click="add">父组件的按钮</button>
      </div>
      </template>
      <script lang="ts">
      import Child from './components/child.vue'
      import { defineComponent, reactive, toRefs } from 'vue'
      export default defineComponent({
      name: '',
      props: {},
      components: { Child },
      setup () {
      const state = reactive({
      count: 1
      })

      const add = (): void => {
      state.count += 1
      }

      const changeValue = (num: number) => {
      state.count += num
      }
      return {
      ...toRefs(state),
      add,
      changeValue
      }
      }
      })
      </script>
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      子组件:

      <template>
      <div class="child">
      <h1> 父组件传入的值:{{ num }}</h1>
      <button @click="changeParentNum('1111')">子组件的按钮</button>
      </div>
      </template>
      <script lang="ts">
      import { defineComponent } from 'vue'
      export default defineComponent({
      name: 'child',
      props: {
      num: Number
      },
      setup (props, ctx) {
      const changeParentNum = () => {
      // 通过ctx调用emit事件 需要注意的是Vue2.x中使用 $emit切勿混淆
      ctx.emit('handle', 2)
      }
      return {
      changeParentNum
      }
      }
      })
      </script>
    • 方式二:父组件把方法传入子组件中,在子组件里直接调用这个方法(同vue2.0)

    • 方式三:**$parent.event** setup里面不支持直接使用this,使用getCurrentInstance 实例, 直接在子组件中来调用父组件的方法或者字段

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      父组件:

      <template>
      <div>
      <child></child>
      </div>
      </template>
      <script>
      import child from '~/components/dam/child';
      export default {
      components: {
      child
      },
      methods: {
      fatherMethod() {
      console.log('测试');
      }
      }
      };
      </script>
      1
      2
      3
      4
      5
      6
      7
      8
      9
      子组件:

      import { getCurrentInstance } from 'vue'
      setup (props, ctx) {
      const { proxy } = getCurrentInstance()
      proxy.$parent.fatherMethod('我调用父亲') //调用父组件的方法
      或者
      proxy.$parent.state //调用父组件的属性
      }
  4. 通过依赖注入实现父子组件数据共享(比如mitt)