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

 更新时间:2024年08月16日 14:43:51   作者:白桃味稠鱼烧  
这篇文章主要介绍了Vue父子组件传值&自定义事件方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

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 的自由度更高。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Vue中如何优雅的捕获 Promise 异常详解

    Vue中如何优雅的捕获 Promise 异常详解

    这篇文章主要为大家介绍了Vue中如何优雅的捕获 Promise 异常详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-10-10
  • Vue+Openlayers自定义轨迹动画

    Vue+Openlayers自定义轨迹动画

    这篇文章主要为大家详细介绍了Vue+Openlayers自定义轨迹动画,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-09-09
  • vue脚手架及vue-router基本使用

    vue脚手架及vue-router基本使用

    这篇文章主要介绍了vue脚手架及vue-router基本使用,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2018-04-04
  • Vue-cli框架实现计时器应用

    Vue-cli框架实现计时器应用

    这篇文章主要为大家详细介绍了Vue-cli框架实现计时器应用,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • element的el-date-picker组件实现只显示年月日时分效果(不显示秒)

    element的el-date-picker组件实现只显示年月日时分效果(不显示秒)

    最近遇到这样的需求使用element的el-date-picker组件,只显示时分,不显示秒,下面小编给大家分享element的el-date-picker组件实现只显示年月日时分效果,感兴趣的朋友一起看看吧
    2024-08-08
  • openlayers6之地图覆盖物overlay详解

    openlayers6之地图覆盖物overlay详解

    overlay就是在地图上以另外一种形式浮现在地图上,常见的地图覆盖物为这三种类型,如:popup 弹窗、label标注信息、text文本信息等,接下来跟随小编看下openlayers6之地图覆盖物overlay详解,一起看看吧
    2021-09-09
  • 解决vue-photo-preview 异步图片放大失效的问题

    解决vue-photo-preview 异步图片放大失效的问题

    这篇文章主要介绍了解决vue-photo-preview 异步图片放大失效的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-07-07
  • 基于Vue+Webpack拆分路由文件实现管理

    基于Vue+Webpack拆分路由文件实现管理

    这篇文章主要介绍了基于Vue+Webpack拆分路由文件实现管理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-11-11
  • 渲染函数 & JSX详情

    渲染函数 & JSX详情

    本篇文章来讲解渲染函数 & JSX,Vue 推荐在绝大多数情况下使用模板来创建你的 HTML。然而在一些场景中,你真的需要 JavaScript 的完全编程的能力。这时我们可以用渲染函数,它比模板更接近编译器,需要的朋友可以参考一下
    2021-09-09
  • vue实现动态路由的方法及路由原理解析

    vue实现动态路由的方法及路由原理解析

    这篇文章主要介绍了路由原理及vue实现动态路由,Vue Router 提供了丰富的 API,可以轻松地实现路由功能,并支持路由参数、查询参数、命名路由、嵌套路由等功能,可以满足不同应用程序的需求,需要的朋友可以参考下
    2023-06-06

最新评论