Vue 父子组件通讯

  • 父组件通过 props 属性向子组件传递数据
    props: ["子组件的属性"] //可以是数组(不常用),也可以是对象(常用)
    我们可以设置 prop 是否有默认值,是否是必传值,值得类型
    子组件用 {{prop名}} 在 html 里来接值即可
  • 子组件通过自定义事件向父组件发送消息:
    1. 在子组件中,通过 $emit 来触发事件
      子组件里的某元素事件 @click="clickbutton('aaa')"
      子组件的方法: clickbutton(value) { this.$emit('myevent', value); }
    2. 在父组件中,通过 v-on 来监听子组件事件
      父组件调用子组件的时候 需要绑定的方法 @myevent="dosomething"
      父组件的方法:dosomething(value) {alert(value);}
  • 父组件访问子组件$refs 子组件里设置 ref="aaa" 父组件调用的时候用 $refs.aaa
  • 不常用的访问方式
    • $parent 方法增加了父子组件的耦合性
    • $children 方法是只有想要得到全部子组件的时候才会用的方法
    • $root

Tips:

如果父组件传给子组件的值是不同的,如

父组件1传递给子组件的image 的值是 p1.image

父组件2传递给子组件的image 的值是 p2.show.img

那么子组件接值利用下计算机属性 <img src="showImg" />

props:[product],

computed:{
        showImg(){ return this.product.image || this.product.show.img; }
}

多层组件通讯问题(如爷孙组件)

多层组件通讯有三种方式

1.一层一层的传递

2.通过 Vuex 来改变一个值,然后监听这个值是否发生变化

3.事件总线

  案例:用 Better scroll 的时候想要监听很底层的组件 GoodListItem 的图片是否全部加载完毕。

孙组件  GoodListItem.vue code:

<img @load="imageLoad" />

imageload(){
    this.$bus.$emit('itemImageLoad') //向全局发送了一个 aaa 事件

}

爷组件 Home.vue code:
data(){
    return {
        itemImgListener: null //将函数存储在一个变量中方便取消事件总线
    }
},
mounted(){

    //监听孙组件发来的图片加载完成的事件,注意,这里由于每个图片加载完成之后都要调用一遍 load 喊出,因此要进行防抖操作,具体操作方式参考我的“插件”->"防抖函数"文章
    this.itemImgListener = () =>{
        console.log('接收到了该时间,这里执行');
        //this.$refs.scroll.refresh

    };

    this.$bus.$on('itemImageLoad', this.itemImgListener) 
},
deactivated(){ //如果是不销毁的组件离开之后调用这个函数 deactivated()
    //取消全局事件监听的方法
    //this.$bus.off('itemImageLoad', 函数) //这里函数不传的话,就会取消所有组件中的事假总线 “itemImageLoad” 的监听
    this.$bus.off('itemImageLoad', this.itemImgListener)
}


注:
直接调用 this.$bus 是 undefind。想要调用需要在 main.js 文件中加一句话:

Vue.prototype.$bus = new Vue();

Demo1, 点击子组件2,改变父组件的值和子组件1的值

<div id="app">
    <h2>我是父组件</h2>
    <p>{{message}}</p>
    <h2>父传子</h2>
    <mycpn :title="message" :subtitle="'sdsd'"></mycpn>
    <h2>子传父</h2>
    <mycpn2 @myevent="dosomething"></mycpn2>
  </div>
  <template id="childcpn">
    <div>
      <p>我是子组件 1</p>
      <p>父组件传过来的 title: {{title}} <br>
        父组件传过来的 subtitle: {{subtitle}}</p>
    </div>
  </template>
  <template id="childcpn2">
    <div>
      <p>我是子组件 2</p>
      <button v-for="item in categories" @click="clickbutton(item)">{{item}}</button>
    </div>
  </template>
  <script>
  const vue = new Vue({
    el: '#app',
    data: {
      message: "我是父组件的值"
    },
    methods: {
      dosomething(value) {
        this.message = value;
      }
    },
    components: {
      'mycpn': {
        template: '#childcpn',
        props: {
          title: {
            type: String,
            required: true //必须传值
          },
          subtitle: {
            type: String,
            default: '没有传值就有一个默认值'
          }
        }
      },
      'mycpn2': {
        template: '#childcpn2',
        data() {
          return { categories: ['111', '222', '333'] }
        },
        methods: {
          clickbutton(value) { this.$emit('myevent', value); }
        }
      }
    }
  });
  </script>

Demo 2
父子组件想要实现数据双向绑定,不能采用 v-model 的形式。
需要采用本案例的方法。

本案例需求:
父组件的 input 框发生变化后 子组件变成 父组件的 100倍
子组件的 input 框发生变化后 父组件变成 子组件的 1/100

 <div id="app">
    <h2>我是父组件</h2>
    <p>fatherdata {{fatherdata}}</p>
    <input type="text" :value="fatherdata" @input.enter="fatherchange">
    <mycpn :childdataprop="fatherdata" @childevent="dosomething"></mycpn>
  </div>
  <template id="childcpn">
    <div>
      <p>我是子组件</p>
      <p>childdataprop {{childdataprop}} <br>
        childdata {{childdata}}
      </p>
      <input type="text" :value="childdata" @input.enter="childchange">
    </div>
  </template>
  <script>
  const vue = new Vue({
    el: '#app',
    data: {
      fatherdata: "0",
    },
    methods: {
      dosomething(value) {
        this.fatherdata = value / 100;
      },
      fatherchange(e) { this.fatherdata = e.target.value }
    },
    components: {
      'mycpn': {
        template: '#childcpn',
        data() { return { childdata: "0" } },
        props: ['childdataprop'],
        methods: {
          childchange(e) {
            this.childdata = e.target.value;
            this.$emit('childevent', e.target.value);
          }
        },
        watch: {
          childdataprop(newvalue, oldvalue) {
            this.childdata = newvalue *100;
          }
        }
      }
    }
  });
  </script>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值