vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > vue父子组件通讯

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

作者:今天一定晴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,没有的时候就不会去读取 (这样安排是因为父组件在执行这行代码的时候,子组件可能还未加载完毕,这样以免报错)

总结

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

您可能感兴趣的文章:
阅读全文