vue组件之间的多种通讯方式

一、父组件传递参数给子组件

  • 1、父组件传递参数

    <template>
      <div>
        <Son1
          :name="name"
          :age="20"
          :bookList="['三国演义', '西游记']"
          :details="{'name': '张三', address: '广东深圳'}"
          :isActive="false"
        />
      </div>
    </template>
    
  • 2、在子组件中定义接收

    <template>
      <div>
        <hr />
        <h3>我是子组件</h3>
        <p>{{name}}</p>
        <p>{{age}}</p>
        <p>{{bookList}}</p>
        <p>{{details}}</p>
        <p>{{isActive}}</p>
      </div>
    </template>
    
    <script>
      export default {
        name: 'son1',
        props: {
          name: {
            type: String,
            default: '',
          },
          age: {
            type: Number,
            default: 0,
          },
          bookList: {
            // 如果是对象或者数组必须使用下函数生成的方式
            type: Array,
            default: () => [],
          },
          details: {
            type: Object,
            default: () => ({}),
          },
          isActive: {
            type: Boolean,
            default: false,
          },
        },
        mounted() {
          console.log(this);
        },
      };
    </script>
    
    <style scoped></style>
    

二、子组件修改父组件传递的数据

由于vue属于单向数据流,子组件中不直接修改父组件的数据,而是在组件触发事件或者派发通知到父组件,通知父组件修改数据,父组件数据被修改了,传递到子组件中,子组件的数据也被修改了。

方式一、直接在子组件中定义方法,然后通过emit发出一个事件到父组件中修改(类似回调函数的方式)
  • 1、在子组件中

    <template>
      <div>
        <hr />
        <h3>我是子组件</h3>
        <p>{{name}}</p>
        <button @click="change">修改</button>
      </div>
    </template>
    
    <script>
      export default {
        name: 'son1',
        props: {
          name: {
            type: String,
            default: '',
          },
        },
        mounted() {
          console.log(this);
        },
        methods: {
          change() {
            // 对父组件派发一个change事件
            this.$emit('change', '哈哈,我是子组件过来的');
          },
        },
      };
    </script>
    
    <style scoped></style>
    
  • 2、在父组件中使用,然后修改数据

    <template>
        <div>
        	<!--在父组件中使用change事件-->  
          <Son1 :name="name" @change="change" />
        </div>
    </template>
      
      <script>
        import Son1 from './Son1';
        export default {
          name: 'parent1',
          data() {
            return {
              name: '哈哈',
            };
          },
          methods: {
            change(value) {
              this.name = value;
            },
          },
          mounted() {
            console.log(this);
          },
          components: {
            Son1,
          },
        };
    </script>
      
      <style scoped></style>
    
方式二、子组件中派发的事件名称叫input:value(和方式一一样的)
  • 1、子组件中

      // 子组件中派发一个input:value的事件给父组件
      this.$emit('input:value', '?哈哈');
    
  • 2、父组件中

    html
      <template>
        <div>
          <!--父组件接收子组件的input:value事件-->
          <Son1 :name="name" @input:value="change"></Son1>
          <!-- 
            或者直接将函数写在行间
            <Son1
              :name="name"
              @input:value="(val)=>this.name=val"
            ></Son1> 
          -->
        </div>
    </template>
      
      <script>
        import Son1 from './Son1';
        export default {
          name: 'parent1',
          data() {
            return {
              name: '哈哈',
            };
          },
          methods: {
            change(value) {
              this.name = value;
            },
          },
          mounted() {
            console.log(this);
          },
          components: {
            Son1,
          },
        };
    </script>
      
    <style scoped></style>
    
方式三、使用修饰符sync数据同步,注意点:子组件必须派发的是update:属性事件
  • 1、子组件中派发的事件名称

    <template>
      <div>
        <h1>
          我是子组件内容
        </h1>
        <button @click="change1">使用sync的方式</button>
      </div>
    </template>
    <script>
      export default {
        methods: {
          change1() {
            this.$emit('update:name', '?哈哈');
          },
        },
      };
    </script>
    
  • 2、父组件中

    <template>
      <div>
        <!-- 使用的方式一 -->
        <Son1 :name="name" @update:name="(val)=>this.name=val"></Son1>
        <!-- 使用的方式二 -->
        <Son1 :name.sync="name"></Son1>
      </div>
    </template>
    
方式四、子组件中接收的是value属的时候,派发的事件是input
  • 1、子组件

    <template>
      <div>
        <hr />
        <h3>我是子组件</h3>
        <p>{{value}}</p>
        <button @click="change">修改</button>
      </div>
    </template>
    
    <script>
      export default {
        name: 'son1',
        props: {
          value: {
            // 必须是value属性
            type: String,
            default: '',
          },
        },
        mounted() {
          console.log(this);
        },
        methods: {
          change() {
            // 发送的事件也是定死的input
            this.$emit('input', '哈哈,我是子组件过来的');
          },
        },
      };
    </script>
    
    <style scoped></style>
    
  • 2、父组件中

    <template>
      <div>
        <Son1 :value="name" @input="(val)=>this.name=val"></Son1>
        <!-- 可以进一步简写成这样 -->
        <Son1 v-model="name"></Son1>
      </div>
    </template>
    <script>
      import Son1 from './Son1';
      export default {
        name: 'parent1',
        data() {
          return {
            name: '哈哈',
          };
        },
      };
    </script>
    

三、孙组件修改父父组件的数据

主要的思路是孙组件派发事件通知父组件修改数据,父组件派发事件通知父组件修改

方式一、孙组件中使用$parent.$emit派发事件
  • 1、孙组件

    ...
    changeVal () {
      this.$parent.$emit('input', '孙组件修改的');
    },
    changeAge () {
      this.$parent.$emit('changeAge', 40);
    }
    ...
    
  • 2、父组件

    <template>
      <div>
        <hr />
        <h3>我是子组件</h3>
        <p>{{value}}==={{age}}</p>
        <hr />
        <h3>孙组件</h3>
        <Grandson1 :value="value" :age="age" />
      </div>
    </template>
    <script>
      import Grandson1 from './Grandson1';
      export default {
        name: 'son1',
        props: {
          value: {
            type: String,
            default: '',
          },
          age: {
            type: Number,
            default: 0,
          },
        },
        methods: {},
        components: {
          Grandson1,
        },
      };
    </script>
    
    <style scoped></style>
    
  • 3、父父组件

    <template>
      <div>
        <Son1 v-model="name" :age="age" @changeAge="val => this.age = val"></Son1>
      </div>
    </template>
    
方式二、使用自己扩展到Vue原型上的$dispatch方法
  • 1、扩展方法

    import App from './App';
    import Vue from 'vue';
    
    Vue.prototype.$dispatch = function(eventName, value) {
      let parent = this.$parent;
      // 循环递归派发事件
      while (parent) {
        parent.$emit(eventName, value);
        parent = parent.$parent;
      }
    };
    const vm = new Vue({
      el: '#app',
      render: (h) => h(App),
    });
    
  • 2、孙组件中使用

    ...
    methods: {
      changeVal () {
        this.$dispatch('input', '孙孙组件修改的')
      },
      changeAge () {
        this.$dispatch('changeAge', 40)
      }
    },
    ...
    
  • 3、父父组件中

    <Son1 v-model="name" :age="age" @changeAge="val => this.age = val"></Son1>
    

四、自定义广播

类似angularjs中的广播,其实也就是一个发布者与订阅者的关系,发布一个消息,订阅的组件就执行

  • 1、在main.js中扩展方法

    Vue.prototype.$broadcast = function(enevtName, value) {
      // 递归查找全部的子组件
      const broadcast = (children) => {
        children.forEach((child) => {
          child.$emit(enevtName, value);
          if (child.$children) {
            broadcast(child.$children);
          }
        });
      };
      broadcast(this.$children);
    };
    
  • 2、组件中订阅广播

    <template>
      <div>
        <Grandson1 :value="value" :age="age" @say="say" />
      </div>
    </template>
    <script>
      ...
      methods: {
        say (val) {
          console.log(`我是孙组件中的广播,接收的消息是:${val}`)
        }
      },
      ...
    </script>
    
  • 3、发出一个广播通知

    ...
    mounted () {
      this.$broadcast('say', '放假了');
    },
    ...
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

水痕01

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值