Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vue 之 父子组件通信与事件触发(最全实用总结) - 掘金 #220

Open
xiaodongxier opened this issue Jan 3, 2024 · 0 comments

Comments

@xiaodongxier
Copy link
Owner

之前写过一篇关于基于 微信小程序的父子组件传值通信与事件触发,今天整理一片关于 Vue 的父子组件的相关内容。

一、组件

子组件

<template>
  <div style="border:1px solid black;width:400px; height: 130px;">
    <h3>我是子组件</h3>
    <button>子组件将值传递给父组件</button>
    <div>子组件接收父组件的值:</div>
  </div>
</template> 

父组件

<template>
 <div style="border:1px solid red;padding:2rem;width:400px;margin:0 auto;">
    <h3>我是父组件</h3>
    <div>子组件向父组件传递的值:</div>
    <Child></Child>
  </div>
</template>

<script>
import Child from './Child';
export default {
    components: {
        Child
    }
}
</script>

效果展示:
通过这张图可以看出父子组件的结构,下面我们来实习父子组件通信。


二、父子组件通信

父组件给子组件通信

实现思路:子组件通过 props 来接受父组件传过来的值。

  1. 在父组件中,定义一个data变量,在子组件标签中动态绑定这个值。

    // Father.vue
    <template>
     <div style="border:1px solid red;padding:2rem;width:400px;margin:0 auto;">
        <h3>我是父组件</h3>
        <div>子组件向父组件传递的值:{{ChildMsg}}</div>
        <Child :FatherMsg="data"></Child>
      </div>
    </template>
    
    <script>
    import Child from './Child';
    export default {
        data() {
            return {
                data: 'I am your father',
            }
        },
        components: {
            Child
        }
    }
    </script>
  2. 接着在子组件里通过 props 来接收,这样子组件就接收到了父组件传递过来的值了。

    // Child.vue
    <template>
      <div style="border:1px solid black;width:400px; height: 130px;">
        <h3>我是子组件</h3>
        <button>子组件将值传递给父组件</button>
        <div>父组件向子组件传递的值:{{FatherMsg}}</div>
      </div>
    </template> 
    
    <script>
    export default {
        data() {
            return {
                data: 'I am your children',
            }
        },
        props: ['FatherMsg']
    }
    </script>


可以看到,我们父组件向子组件通信已经实现了,接下来就是子组件向父组件通信了,这个就要使用到 this.$emit 方法了。

子组件向父组件通信

实现思路:通过在子组件中使用 this.$emit 来触发自定义事件并传值,然后在父组件中监听该事件即可。

  1. 在子组件中给 button 按钮添加 click 事件,来通过 this.$emit 自定义事件,并传入一个参数:

    <template>
      <div style="border:1px solid black;width:400px; height: 130px;">
        <h3>我是子组件</h3>
        <button @click="send">子组件将值传递给父组件</button>
        <div>父组件向子组件传递的值:{{FatherMsg}}</div>
      </div>
    </template> 
    
    <script>
    export default {
        data() {
            return {
                data: 'I am your children',
            }
        },
        props: ['FatherMsg'],
        methods: {
          send() {
            this.$emit('ListenChild', this.data);
          }
        }
    }
    </script>
  2. 在父组件中的子组件标签里,先在 data 里定义一个变量接收这个值,然后监听在子组件中自定义的事件,并接受这个参数赋值给定义的变量:

    <template>
     <div style="border:1px solid red;padding:2rem;width:400px;margin:0 auto;">
        <h3>我是父组件</h3>
        <div>子组件向父组件传递的值:{{ChildMsg}}</div>
        <Child :FatherMsg="data" @ListenChild="ListenChild"></Child>
      </div>
    </template>
    
    <script>
    import Child from './Child';
    export default {
        data() {
            return {
                data: 'I am your father',
                ChildMsg: '',
            }
        },
        components: {
            Child
        },
        methods: {
            ListenChild(data) {
                console.log("子组件传递过来的值:" , data);
                this.ChildMsg = data;
            }
        }
    }
    </script>

点击子组件中的“子组件将值传递给父组件”,就可看到如下效果:


三、父子组件事件触发

父组件调用子组件中的事件方法

  1. 通过 ref 直接调用子组件的方法:

    // Child.vue 
    <template>
      <div style="border: 1px solid black; width: 150px; margin: 10px auto">
        我是子组件
        <div style="color: red"> {{ msg }} </div>
      </div>
    </template>
    <script>
    export default {
        data() {
            return {
                msg: '',
            }
        },
      methods: {
        childFun() {
          console.log('我是子组件的方法 childFun');
          this.msg = '我的方法被调用了'
        },
      },
    };
    </script>

    在子组件标签上添加 ref 属性,然后在方法中通过 this.$refs 找到绑定 ref 的属性调用该子组件内的方法即可。

    // Father.vue
    <template>
      <div style="border: 1px solid red; width: 200px; padding: 10px; margin: 0 auto">
        我是父组件
        <Button @click="handleClick">点击调用子组件方法</Button>
        <Child ref="child" />
      </div>
    </template>    
    
    <script>
    import Child from './Child';
    
    export default {
        components: {
            Child
        },
        methods: {
            handleClick() {
                this.$refs.child.childFun();
            },
        },
    }
    </script>
  2. 通过组件的 $emit$on 方法:

    // Child.vue 
    <template>
      <div style="border: 1px solid black; width: 150px; margin: 10px auto">
        我是子组件
        <div style="color: red"> {{ msg }} </div>
      </div>
    </template>
    <script>
    export default {
        data() {
            return {
                msg: '',
            }
        },
      mounted() {
        this.$on('childFun', function() {
            console.log('我是子组件方法');
            this.msg = '我的方法被调用了'
        });
      }
    };
    </script>

    在子组件中使用 $on 绑定一个方法,然后在父组件中通过 $emit 找到绑定 $on 上面的事件名即可,但是也需要 ref 的配合。

    // Father.vue
    <template>
      <div style="border: 1px solid red; width: 200px; padding: 10px; margin: 0 auto">
        我是父组件
        <Button @click="handleClick">点击调用子组件方法</Button>
        <Child ref="child" />
      </div>
    </template>    
    
    <script>
    import Child from './Child';
    
    export default {
        components: {
            Child
        },
        methods: {
            handleClick() {
            	
                this.$refs.child.$emit("childFun")    
            },
        },
    }
    </script>

两种实现方式效果一致。

调用方法前:
调用方法后:

子组件调用父组件中的事件方法

  1. 直接在子组件中通过 this.$parent 来调用父组件的方法

    // Father.vue
    <template>
      <div style="border: 1px solid red; width: 200px; padding: 10px; margin: 0 auto" >
        我是父组件
        <Child></Child>
        <div style="color: red"> {{ msg }} </div>
      </div>
    </template>
    <script>
      import Child from './Child';
      export default {
          data() {
              return {
                  msg: ''
              }
          },
        components: {
          Child
        },
        methods: {
          fatherMethod() {
            console.log('我的父组件中的方法');
            this.msg = '我的方法被子组件调用了';
          }
        }
      };
    </script>
    // Child.vue
    <template>
      <div style="border: 1px solid black; width: 150px; margin: 10px auto">
        我是子组件
        <button @click="childMethod">点击调用父组件方法</button>
      </div>
    </template>
    <script>
      export default {
        methods: {
          childMethod() {
            this.$parent.fatherMethod();
          }
        }
      };
    </script>
  2. 在子组件里用 $emit 向父组件触发一个事件,父组件监听这个事件(推荐使用)

    // Father.vue
    <template>
      <div style="border: 1px solid red; width: 200px; padding: 10px; margin: 0 auto" >
        我是父组件
        <Child @fatherMethod="fatherMethod"></Child>
        <div style="color: red"> {{ msg }} </div>
      </div>
    </template>
    <script>
      import Child from './Child';
      export default {
          data() {
              return {
                  msg: ''
              }
          },
        components: {
          Child
        },
        methods: {
          fatherMethod() {
            console.log('我的父组件中的方法');
            this.msg = '我的方法被子组件调用了';
          }
        }
      };
    </script>

    子组件可以使用 $emit 触发父组件的自定义事件。

    // Child.vue
    <template>
      <div style="border: 1px solid black; width: 150px; margin: 10px auto">
        我是子组件
        <button @click="childMethod">点击调用父组件方法</button>
      </div>
    </template>
    <script>
      export default {
        methods: {
          childMethod() {
            
            this.$emit('fatherMethod'); 
          }
        }
      };
    </script>
  3. 父组件把方法传入子组件中,在子组件里直接调用这个方法:

    // Father.vue
    <template>
      <div style="border: 1px solid red; width: 200px; padding: 10px; margin: 0 auto" >
        我是父组件
        <Child :fatherMethod="fatherMethod"></Child>
        <div style="color: red"> {{ msg }} </div>
      </div>
    </template>
    <script>
      import Child from './Child';
      export default {
          data() {
              return {
                  msg: ''
              }
          },
        components: {
          Child
        },
        methods: {
          fatherMethod() {
            console.log('我的父组件中的方法');
            this.msg = '我的方法被子组件调用了';
          }
        }
      };
    </script>

    父组件可以将事件绑定到子组件标签上,子组件使用 props 接收父组件的事件。

    // Child.vue
    <template>
      <div style="border: 1px solid black; width: 150px; margin: 10px auto">
        我是子组件
        <button @click="childMethod">点击调用父组件方法</button>
      </div>
    </template>
    <script>
      export default {
        props: {
          fatherMethod: {
            type: Function,
            default: null
          }
        },
        methods: {
          childMethod() {
            if (this.fatherMethod) {
              this.fatherMethod();
            }
          }
        }
      };
    </script>

以上三种实现方式效果一致。

调用方法前:
调用方法后:


四、总结

至此,Vue 父子组件之间大部分的操作都涉及到了,我们在程序的开发过程中对于该部分内容可以游刃有余了。

之前还写过一篇关于微信小程序的父子组件传值通信与事件触发 的文章,感兴趣的小伙伴可以前往查看。

希望以上内容可以帮助到大家。有任何问题欢迎讨论留言。

各位 加油!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant