vue父子组件通讯的所有方法小结

 更新时间:2024年07月26日 08:30:47   作者:今天一定晴q  
本文将介绍父组件与子组件之间传递数据的四种方法,以一个简单的小demo为例,通过实例全方位解析和代码演示,便于大家理解,需要的朋友可以参考下

父子组件通讯

父组件展示输入框用于新增数据,子组件展示数组信息

场景一:直接传递一整个数组

父组件在子组件标签中使用v-bind绑定一个属性名为list,属性值为要传递的数组list

子组件调用函数defineProps,接收父组件传过来的数据。defineProps函数是vue默认帮我们引入好了的,它默认接收一个对象作为参数,该对象包含一个字段,字段名为父组件绑定的属性名list,字段值又为一个对象,对象中包含子组件期望接收到的数据类型type和默认值default,此处期望接收到一个数组,默认值为一个空数组。list可以直接拿到template模块中使用

父组件代码:

<template>
  <div class="inputGroup">
    <input type="text" v-model="value">
    <button @click="add">添加</button>
  </div>

  <Child :list="list"> </Child>  // 父组件将值v-bind绑定传给子组件
</template>

<script setup>
  import Child from '@/components/child.vue' // 引入子组件
  import { ref } from 'vue'
  const value = ref('')
  const list = ref(['html', 'css', 'js'])

  const add = () => {
    list.value.push(value.value)
    value.value = ''
  }
</script>

子组件代码:

<template>
    <div class="child">
        <ul>
          <li v-for="item in list">{{ item }}</li>
        </ul>
    </div>
</template>

<script setup>
    defineProps({       // 子组件使用defineProps接收         
        list: {                   
            type: Array,          
            required: true,
            default: () => []     
        }
    })
</script>

这个通讯过程本身就是一个响应式的过程,所以父组件向子组件传递过去的属性值 list 发生改变后,子组件会重新接收一遍最新的值,由于 list 被定义成了响应式,浏览器最终就会将新添加的值成功渲染出来

场景二:只传递新增加的那个值

父组件在子组件标签中使用v-bind绑定一个属性名为msg,属性值为要传递的新增数据toChild

子组件定义一个变量props接收defineProps函数执行的结果,再将接收到的新增数据 props.msg添加进子组件已经定义好的list数组中

父组件代码:

<template>
  <div class="inputGroup">
    <input type="text" v-model="value">
    <button @click="add">添加</button>
  </div>

  <Child :msg="toChild"> </Child>
</template>

<script setup>
  import Child from '@/components/child.vue' // 引入子组件
  import { ref } from 'vue'
  const value = ref('')
  const toChild = ref('')

  const add = () => {
    toChild.value = value.value
  }
</script>

子组件代码:

<template>
    <div class="child">
        <ul>
          <li v-for="item in list">{{ item }}</li>
        </ul>
    </div>
</template>

<script setup>
    import { ref, watch } from 'vue'
    const list = ref(['html', 'css', 'js'])
    const props = defineProps({
        msg: ''     // 直接简写,不再把msg对应的值写成一个对象
    })              
  
    watch(          // 监视props.msg的值的变化,一旦变化执行回调函数
        () => props.msg,
        (newVal, oldVal) => {
            list.value.push(newVal)
        }
    )
</script>

defineProps函数中的字段可以直接被拿到template中使用,但如果要在js脚本中使用,需要一个变量来接收这个函数的执行结果

注意:这里不直接list.value.push(props.msg),而是需要watchprops.msg的值进行监听是因为:list的更新需要list.value.push()这句js代码反复去执行,而js代码在浏览器第一遍渲染页面完成后,不会再执行第二遍,所以需要watch函数在监视到值变化后,主动去执行list的更新

子父组件通讯一

父组件展示数组信息,子组件展示输入框用于新增数据

借助发布订阅机制,子组件调用defineEmits函数接受一个数组作为参数,数组 [ 'new' ] 表示组件可以触发一个名为 'new' 的自定义事件,返回给emits对象,可以用它来触发 new 事件。点击按钮后,调用emits函数发布事件,传递的参数分别为要传输给父组件的事件名new和事件值value.value

父组件订阅该事件,通过事件参数获取子组件提供的值

父组件代码:

<template>
    <!-- 订阅new事件-->
    <Child @new="handle"></Child>
    
    <div class="child">
        <ul>
          <li v-for="item in list">{{ item }}</li>
        </ul>
    </div>

</template>

<script setup>
    import Child from '@/components/child2.vue'
    import { ref } from 'vue'
    const list = ref(['html', 'css', 'js'])

    const handle = (event) => {   // event事件参数,其实就是子组件发布事件时传输过来的值
        list.value.push(event)
    }
</script>

子组件代码:

<template>
    <div class="inputGroup">
        <input type="text" v-model="value">
        <button @click="add">添加</button>
    </div>
</template>

<script setup>
    import { ref } from 'vue'
    const value = ref('')

    const emits = defineEmits(['new'])  // 创建一个new事件
    const add = () => {
        emits('new', value.value)  // 发布事件 
    }
</script>

子父组件通讯二

仍然是父组件展示数组信息,子组件展示输入框用于新增数据

能用但不建议版

如果将list数组看做成篮子,新增数据看做成苹果,那么子父组件通讯一就是儿子把苹果丢给父亲,父亲再将苹果装入篮中;子父组件通讯二就是父亲把篮子共享给了儿子,儿子将苹果装入篮中

父组件定义了list数组,通过v-model:list指令将父组件的 list 属性与子组件中的 list prop 进行了双向绑定,意味着当在子组件内部修改 list 时,这些更改也会反映回父组件的 list 属性中

子组件接收list的方式就是使用defineProps接收

父组件代码:

<template>
    <Child v-model:list="list"></Child>
    
    <div class="child">
        <ul>
          <li v-for="item in list">{{ item }}</li>
        </ul>
    </div>
</template>

<script setup>
    import Child from '@/components/child3.vue'
    import { ref } from 'vue'
    
    const list = ref(['html', 'css', 'js'])
</script>

子组件代码:

<template>
    <div class="inputGroup">
        <input type="text" v-model="value">
        <button @click="add">添加</button>
    </div>
</template>

<script setup>
    import { ref, defineProps } from 'vue'
    const value = ref('')

    const props = defineProps({
        list: {
            type: Array,
            default: () => []
        }
    })

    const add = () => {
        props.list.push(value.value)
    }
</script>

但是vue官方不建议我们让子组件直接操作父组件给过来的数据,因为这样会导致数据流很混乱。正常来讲我自己的数组想要被修改,就应该由我自己来改,而不是交到别人手上去改

优化版

所以子组件的js代码应当优化成下面的样子

使用 defineEmits 函数来声明组件可以触发的事件update:list,在 Vue 中,以 update: 开头的事件通常用于通知父组件 子组件内部数据的变更。arr接收list prop 的引用,再把更新过后的arr抛出出去,v-model:list就会自动get到最新的值

<script setup>
    import { ref, defineProps } from 'vue'
    const value = ref('')

    const props = defineProps({
        list: {
            type: Array,
            default: () => []
        }
    })

    const emits = defineEmits(['update:list'])
    const add = () => {
        const arr = props.list
        arr.push(value.value)
        emits('update:list', arr)
    }
</script>

子父组件通讯三

仍然是父组件展示数组信息,子组件展示输入框用于新增数据

父组件直接读取到子组件更新后的list:父组件中定义了一个响应式变量childRefchildRef作为一个标记打到子组件标签上,就可以通过childRef获取到子组件的任何数据

子组件自己完成对list的更新,调用defineExpose函数,指定list的数据可以被外部访问

父组件代码:

<template>
    <Child ref="childRef"></Child>
    <div class="child">
        <ul>
          <li v-for="item in childRef?.list">{{ item }}</li> 
        </ul>
    </div>
</template>

<script setup>
    import Child from '@/components/child4.vue'
    import { ref, onMounted } from 'vue'
    const childRef = ref(null)  
</script>

子组件代码:

<template>
    <div class="inputGroup">
        <input type="text" v-model="value">
        <button @click="add">添加</button>
    </div>
</template>

<script setup>
    import { ref, defineProps } from 'vue'
    const value = ref('')
    const list = ref(['html', 'css', 'js'])

    const add = () => {
        list.value.push(value.value)
    }

    defineExpose({ list }) // 自愿暴露数据
</script>

ref 是 Vue 中的一个特殊属性,它允许我们在父组件中引用子组件或 DOM 元素

item in childRef?.list中,是ES6的新语法,当childRef有值的时候才会读取后面的.list,没有的时候就不会去读取 (这样安排是因为父组件在执行这行代码的时候,子组件可能还未加载完毕,这样以免报错)

总结

  • 父子组件通讯:父组件将值v-bind绑定传给子组件,子组件使用defineProps接收
  • 子组件向父组件通讯:借助发布订阅机制,子组件负责发布事件并携带参数,父组件订阅该事件,通过事件参数获取子组件提供的值
  • 子组件向父组件通讯:父组件借助v-model将数据绑定给子组件,子组件创建'update:xxxx'事件,并将接收到的数据修改后emits出来
  • 子组件向父组件通讯:父组件通过ref获取子组件中defineExpose()暴露出来的数据

以上就是vue父子组件通讯的所有方法小结的详细内容,更多关于vue父子组件通讯的资料请关注脚本之家其它相关文章!

相关文章

  • vue实现右上角时间显示实时刷新

    vue实现右上角时间显示实时刷新

    这篇文章主要为大家详细介绍了vue实现右上角时间显示实时刷新,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-10-10
  • vue3循环展示图片实现过程

    vue3循环展示图片实现过程

    这篇文章主要介绍了vue3循环展示图片实现过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-05-05
  • vue 集成 vis-network 实现网络拓扑图的方法

    vue 集成 vis-network 实现网络拓扑图的方法

    这篇文章主要介绍了vue 集成 vis-network 实现网络拓扑图的方法,本文通过实例代码给大家介绍的非常详细 ,需要的朋友可以参考下
    2019-08-08
  • Vue3监听reactive对象中属性变化的方法

    Vue3监听reactive对象中属性变化的方法

    在 Vue 3 中,如果你想监听 reactive 对象中的某个属性发生的变化,你可以使用 watch 函数进行监听,watch 函数允许你观察 reactive 对象的某个属性或者整个对象,所以本文给大家介绍了Vue3监听reactive对象中属性变化的方法,需要的朋友可以参考下
    2024-08-08
  • vue项目中使用Svg的方法

    vue项目中使用Svg的方法

    本文主要以 vue-cli3 搭建的项目为例,来聊一下如何在项目中更优雅的使用 svg 。感兴趣的朋友跟随小编一起看看吧
    2018-10-10
  • Vue3基于 rem 比例缩放方案示例详解

    Vue3基于 rem 比例缩放方案示例详解

    这篇文章主要介绍了Vue3基于rem比例缩放方案,本缩放方案置于hooks中即可,文中通过示例代码介绍了vue-cli3 中使用rem布局的方法,需要的朋友可以参考下
    2023-05-05
  • vue实现集成腾讯TIM即时通讯

    vue实现集成腾讯TIM即时通讯

    最近在做商城类的项目,需要使用到客服系统,用户选择的腾讯IM即时通信,所以本文主要介绍了vue实现集成腾讯TIM即时通讯,感兴趣的可以了解一下
    2021-06-06
  • vue中将网页打印成pdf实例代码

    vue中将网页打印成pdf实例代码

    本篇文章主要介绍了vue中将网页打印成pdf实例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-06-06
  • Vue-router不允许导航到当前位置(/path)错误原因以及修复方式

    Vue-router不允许导航到当前位置(/path)错误原因以及修复方式

    本文主要介绍了Vue-router不允许导航到当前位置(/path)错误原因以及修复方式,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09
  • Vue路由跳转方式区别汇总(push,replace,go)

    Vue路由跳转方式区别汇总(push,replace,go)

    vue项目中点击router-link标签链接都属于声明式导航。vue项目中编程式导航有this.$router.push(),this.$router.replace(),this.$router.go()​​​​​​​。这篇文章主要介绍了Vue路由跳转方式区别汇总(push,replace,go)
    2022-12-12

最新评论