Vue 子组件与父组件通信,v-for生成的子组件通信,v-on/@事件参数问题

目录

引言

 总结

v-for生成的子组件

事件参数问题

子传父数据

事件函数传参问题

最终测试代码


引言

我们知道了子组件可以通过$emit,来触发父组件上给子组件绑定的自定义事件,并在$emit时附上参数的形式来实现子组件给父组件数据。今天我们来带上v-for生成子组件的情况,探讨一下各种情况吧。


 总结

老样子 先给总结。吉吉国王先看总结,能用直接拿去。

v-for生成的子组件

当v-for的item和index需要传入函数中,且函数是由v-for中的子组件触发时,使用$event即可拿到第一个参数(仅第一个参数)

//父组件
<test-component @sayHi="say(index,item.name,$event)"></test-component>

//子组件
this.$emit("sayHi",this.data)

事件参数问题

1、函数名带括号时候,父组件传参优先级更高,此时子组件参数不能通过$emit传入父组件

/*父组件*/ 
//写法一 正常传参
 <test-component ref="component" @sayHi="say"></test-component>

/*只有父传入的参数生效*/
//写法二 
 <test-component ref="component" @sayHi="say()"></test-component>
//写法三
 <test-component ref="component" @sayHi="say(index,item.name)"></test-component>

 2、无论是父组件还是子组件触发事件,都会按照事件函数定义时的方式传参。比如定义时有加入父组件的参数,则子组件触发时,无须子组件来定义参数,也会传入父组件参数。

  • 如果在父组件上触发事件,$event拿到的是该dom元素
  • 自定义子组件里$emit触发父组件绑定在子组件的事件,$event拿到的组件$emit时返回的第一个参数
//父组件
<button @click="say(index,item.name,$event)">父组件来触发</button>
<test-component ref="component" @sayHi="say(index,item.name,$event)"></test-

PS:提一嘴,v-for生成的ref,this.$refs.xx是一个数组,可以搭配index,this.$refs.xx[index]拿到对应的dom元素


子传父数据

父组件代码

<template>
  <div>
    <div class="container" v-for="(item,index) of list" :key="index">
      我是{
   
   {index}}号{
   
   {item.name}}
       <test-component 
       ref="component"
       @sayHi="say">
       </test-component>
    </div>
  </div> 
</template>

<script>
import testComponent from '@/components/testComponent.vue';
export default {
  components:{testComponent},
  data(){
    return{
      list:[
        {
        name:'爸爸'
        },
        {
        name:'爷爷'
        },
      ]
    }
  },
  methods:{
    say(){
      console.log(...arguments)
    }
  }
}
</script>

子组件

<template>
    <div class="component">
        <div>我是组件 {
   
   {data}}</div>
        <button @click="back">返回组件数据</button>
    </div>
</template>

<script>
export default {
    props:[],
    data(){
        return{
            data:'我是帅哥',
            sex:'男'
        }
    },
    methods:{
        //一顿对Data操作后
        back(){
            this.$emit("sayHi",this.data)
        }
    }
}
</script>

这是正常情况下的子组件向父组件传参。

但是新的需求下来了,有时候需要把v-for生成的index或者item传进来,进行进一步的数据的处理。

于是我们把代码改成这样

<test-component ref="component" @sayHi="say(index,item)"></test-component>

我们来看看结果

index和item是拿到了,但是子组件向父组件的值弄丢了,那我们有什么办法可以解决这种冲突的情况呢。

  • 方法一 暴力解决 把数据传入子组件再打包返回
//父组件内
<test-component ref="component" :myIndex="index" :myItem="'item'" @sayHi="say"></test-component>
....

//子组件内
....
 props:['myItem','myIndex'],
    data(){
        return{
            data:'我是帅哥',
            sex:'男'
        }
    },
    methods:{
        //一顿对Data操作后
        back(){
            let data={
                data:this.data,
                item:this.myItem,
                index:this.myIndex,
            }
            this.$emit("sayHi",data)
        }
    }

 结果如下

我们确实成功拿到了,但是这种办法非常的笨,于是有了第二种办法

  • 方法二 使用$event获取自定义组件的返回参数(仅限第一个参数)

我们只要定义事件时参数加上了$event即可,该方法在普通元素中会拿到相应的dom元素,但在子组件的自定义事件上使用能拿到子组件传入的参数。(有些组件依然可以拿到相应的dom元素,如uniapp的官方组件,此时可以使用detail.value或target.value拿到参数)

<test-component ref="component" @sayHi="say(index,item.name,$event)"></test-component>

 注意:此方法只能获取传入的第一个参数,若这样写

this.$emit("sayHi",'美女',this.data)

data是拿不到的


事件函数传参问题

此时,可能有人疑虑了,这vue的事件函数带括号写法不带写法 在本文的情况下有什么区别吗?我们逐个来验证。

/*父组件*/ 
//写法一
 <test-component ref="component" @sayHi="say"></test-component>

//写法二
 <test-component ref="component" @sayHi="say()"></test-component>

//写法三
 <test-component ref="component" @sayHi="say(index,item.name)"></test-component>


//子组件
  this.$emit("sayHi",'美女',this.data)
  • 第一种情况便是最普通的,我们能顺利拿到子传父的参数,并且不限参数数量

  • 第二种带括号但是不传入参数,子组件传入的参数一个都没拿到
say(){
      console.log(...arguments)
      if(arguments.length==0)console.log('哦噢,没有参数哦')
 }

  • 第三种带括号且传入参数,能拿到父组件参数,但拿不到子组件参数

到这,大家应该应该心领神会了。有括号时候,父组件传参优先级更高,能正常拿到index和item。

我们再来两种情况来强化一下认识。讨论父组件触发事件子组件触发事件的区别。

//父组件
<button @click="say(index,item.name,$event)">父组件来触发</button>
<test-component ref="component" @sayHi="say(index,item.name,$event)"></test-

  • 如果在父组件上触发事件,$event拿到的是该dom元素
  • 自定义子组件里$emit触发父组件绑定在子组件的事件,$event拿到的组件$emit时返回的第一个参数

无论是父组件还是子组件触发事件,都会按照事件函数定义时的方式传参。比如定义时有加入父组件的参数,则子组件触发时,无须子组件来定义参数,也会传入父组件参数。与在哪触发,是否传入参数,传入参数个数无关


最终测试代码

父组件

<template>
  <div>
    <div class="container" v-for="(item,index) of list" :key="index">
      我是{
   
   {index}}号{
   
   {item.name}}
      <button @click="say(index,item.name,$event)">父组件来触发</button>
      <test-component ref="component" @sayHi="say(index,item.name,$event)"></test-component>
    </div>
  </div> 
</template>

<script>
import testComponent from '@/components/testComponent.vue';
export default {
  components:{testComponent},
  data(){
    return{
      list:[
        {
        name:'爸爸'
        },
        {
        name:'爷爷'
        },
      ]
    }
  },
  methods:{
    say(){
      console.log(...arguments)
      if(arguments.length==0)console.log('哦噢,没有参数哦')
    }
  }
}
</script>

 子组件

<template>
    <div>
        <div>我是组件 {
   
   {data}}</div>
        <button @click="back">返回组件数据</button>
    </div>
</template>

<script>
export default {
    props:[],
    data(){
        return{
            data:'我是帅哥'
        }
    },
    methods:{
        //一顿对Data操作后
        back(){
            this.$emit("sayHi",this.data)
        }
    }
}
</script>

猜你喜欢

转载自blog.csdn.net/weixin_43818307/article/details/127803389
今日推荐