Vue 父子组件传值&自定义事件

因为vue 的数据是单向流动的,这是为了避免数据污染。在官方文档中也说到:所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。

大致归纳一下:父传子--传值、子传父--传事件

父传子:父组件可以传递任何类型的数据给子组件

如果传递的数据是对象格式的,那么在子组件 内部监听 watch  的时候,需要使用深度监听,也就是添加 deep : true ,也就是下面的子组件的监听方式,如果是别的格式的,例如,字符串、数字、布尔值、 数组格式等,那就是普通监听就好了

父组件代码:在父组件中 通过 v-bind 的缩写形式  :listData='listData'   绑定了data 内部的数据,第一个  listData 只是一个名字,为了方便辨认,所以写的相同。 第二个 listData  则是 data 内部的数据

<template>
  <div>
    <h3>我是father</h3>
    <Children :listData='listData' :xxx='xxx' :listObj='listObj'></Children> 
    //子组件传递了一个数组、一个字符串、一个对象
  </div>
</template>

<script>
import Children from './children'  //引入子组件
export default {
  data () {
    return {
      xxx:'123',
      listData: [{
          id: 1,
          name: "TCL彩电",
          price: 1000,
          num: 1,
          img: "../../../assets/a.jpg"
        }],
      listObj: {
          name: "aaa",
          age: 18
      }
    }
  },
  components : {
    Children //注册子组件
  },
}
</script>

子组件代码:

1、通过 props  接收父组件传递过来的数据,规范要求写出数据的类型以及默认值,如果数据是数组或对象形式的,需要使用函数返回,不然控制台会报错。

2、props 接收数据之后,需要使用数据,这个时候需要用到  watch  监听器。对象监听需要用到 deep 深度监听,如果需要组件第一次进来之后就开始监听数据,那么需要 添加 immediate: true 

<template>
  <div>
    <h3>我是children</h3>
  </div>
</template>

<script>
export default {
  props: {
    listData: {
      type: Array,
      default: () => []
    },
    xxx:{
      type:String,
      default : ''
    },
    listObj:{
      type: Object,
      default: () => {}
    }
  },
  watch: {
    listData:{
      handler(n,o) {
        console.log(n,o)
      }
    },
    xxx:{
      handler(n) {
        console.log(n)
      }
    },
    listObj:{
      handler(n,o) {
        console.log(n,o)
      },
      deep: true,
      immediate: true,
    },
  }
};
</script>

子传父--传事件:子组件传递数据给父组件时存在三种方式,但是都是通过事件传递

1、父组件传递 函数类型的props 给子组件,实现子组件向父组件传递数据           

在父组件中引入子组件,向子组件中 通过 v-bind( 简写为 : ) 绑定一个 test 属性 ,该 test 属性对应的值则是 methods 中定义的方法。

<template>
  <div id="app">
    <School :test="test"/>
  </div>
</template>

methods: {
  test(val) {
    console.log(val,'这是子组件传递过来的数据')
  },
},

 定义子组件,以及子组件事件

<template>
  <div>
    <p class="demo" @click="goto">School组件</p>
  </div>
</template>

在子组件中接收该 test 属性,定义数据,定义组件方法。其实props 可以直接写成一个数组,不去定义类型,默认值以及是否必传,但是推荐还是写全一点,这样编译的时候会校验,提高代码质量

export default ({
  // props:['test'],
  props: {
    test: {
      type: Function,
      default: () => {},
      required: true,
    }
  },
  data() {
    return {
      msg:'子组件数据'
    }
  },
  methods: {
    goto() {
      this.test(this.msg)
    }
  },
})

点击触发 goto 事件,找到当前 props 中接收的 test 函数 ( props 接收的参数,都被Vue 底层处理过之后放在了 当前组件实例对象上,所以可以直接通过 this.xxx 拿到 )

控制台上打印了子组件数据。可以看到子组件传递的数据被打印了,表示父组件中绑定的 test 事件被执行了

2、通过 v-on( @ ) 与 $emit  实现子组件向父组件传递数据

App 组件中引入 School 子组件,且绑定 自定义事件 test。

<School @test="test"/>

test(val) {
    console.log(val,'这是子组件传递过来的数据')
},

子组件模板、数据、样式不变,只是 goto 方法内部逻辑变更

methods: {
  goto() {
    this.$emit('test',this.msg)
  }
},

 点击触发 goto 事件,通过 $emit 触发 test 事件,根据名称找到 父组件中的 test 属性对应的方法,执行该方法。结果与 props 传递函数参数一致

3、通过 ref 以及 $on、$emit 三个 api 实现 父组件通过 自定义事件接收子组件参数

$on :监听当前实例上的自定义事件。事件可以由 vm.$emit 触发。回调函数会接收所有传入事件触发函数的额外参数。

$emit :触发当前实例上的事件。附加参数都会传给监听器回调。

App 组件中引入 Schoo 组件,且给 School 子组件添加了 ref 属性,定义 test 函数

<School ref='student'/>

test(val) {
    console.log(val,'这是子组件传递过来的数据')
},

 如果想使用这个方法去获取子组件数据,就需要用到 $on() 这个方法。现在假设,当父组件挂载时,我就要获取到子组件的值,我就应该在 父组件 的 mounted 生命周期中 使用 this.$refs.xxx来获取当前组件的实例对象,至于 $on() 这个方法,则是 挂载到 Vue 实例对象的原型上的,所以 组件实例对象 和 Vue 实例对象 都能使用 $on() 。

在这里就是 通过 $on 注册或者叫创建了一个 qwe 的自定义事件,且该自定义事件的回调函数是写在 methods 中的 getname

mounted() {
  this.$refs.student.$on('qwe', this.test)
}

父组件的工作已经完了,现在该看看子组件了。子组件更简单了,和上面 第二种方法一样,通过 $emit() 这个方法来触发父组件定义的 qwe 方法,且将子组件 数据传递出去。

goto() {
   this.$emit('test',this.msg)
}

 当我点击 School 组件时,执行 goto 方法,通过 $emit 触发父组件自定义的 qwe 方法,且将参数传递给父组件。

父组件通过 $on 监听 qwe 方法,发现被触发了,执行其回调函数 this.test,且 $emit 传递的参数,都会当做形参传递到回调函数中

$on 和 v-on 的区别

 这么一看哈,其实我在子组件上使用 v-on( @ ) 和我使用 $on 做到的事情是一样的啊,那为啥还要来个 $on 这个玩意。

第一点:$on 只能监听当前实例上的自定义事件,而 v-on 用在普通元素上时,只能监听原生 DOM 事件。用在自定义元素组件上时,也可以监听子组件触发的自定义事件。

第二点:$on 更加灵活,如果我想要我的自定义事件异步绑定,通过 v-on 是无法做到的,因为    v-on 指令在 模板编译的时候,就被Vue 底层处理过了,在渲染的时候直接就会绑定事件,但是 $on 的自由度更高。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值