vue的组件通讯

185 阅读4分钟

前言

我们知道vue框架构造的是一个单页面,它不同于传统方法有很多html文件,只有一个html文件,vue文件被挂载到唯一的html中。vue通讯可以在不同vue组件中传递数据,今天就让我们聊一聊vue的组件通讯。

父子通讯

1.父子组件通讯 --- 父组件将值v-bind绑定传给子组件,子组件使用defineProps接受

父组件:

<template>
  <div class="input-group">
    <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>

<style lang="css" scoped>

</style>

输入框中v-model="value"将value值双向绑定(根据表单输入元素或组件输出的值而变化)

添加按钮上添加了add点击事件.

第7行将子组件引入,并将msg通过v-bind传给子组件,toChild是一个变量

子组件

<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: ''
  })
  
  watch(
    () => props.msg,
    (newVal, oldVal) => {
      list.value.push(newVal)
    }
  )
  
  </script>
  
  <style lang="css" scoped></style>

子组件从vue引入ref和watch,分别用于响应和监听。 定义响应式list数组.

defineProps函数定义了一个叫msg的属性接收父组件的传值,可为任何类型

watch()函数里有两个回调函数,第一个是要监听的目标,第二个表示当目标的值发生变化,将newval放到list数组中

v-for可以遍历数组长度,只要数组中还有值就会生成一个list并将item放入li

效果:

image.png

当输入框输入值并点击添加时

image.png

子父通讯

方法一:借助发布订阅机制,子组件负责发布事件并携带参数,父组件订阅该事件通过事件参数获取子组价提供的值

父组件:

<template>
    <!-- 订阅add1事件 -->
    <Child @add1="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) => {
    list.value.push(event)
  }
  </script>
  
  <style lang="css" scoped>
  
  </style>

父组件引入子组件并绑定一个事件add1,add1发生就会执行handle函数

定义一个响应式数组list

handle函数将从子组件传来的值放入数组

子组件:

<template>
    <div class="input-group">
      <input type="text" v-model="value">
      <button @click="add">添加</button>
    </div>
  </template>
  
  <script setup>
  import { ref } from 'vue'
  const value = ref('')
   
  const emits = defineEmits(['add1'])  // 创建一个add1事件
  const add = () => {
    // 将value给到父组件
    emits('add1', value.value)  // 发布事件
  }
  </script>
  
  <style lang="css" scoped>
  
  </style>

输入框中v-model="value"将value值双向绑定(根据表单输入元素或组件输出的值而变化)

添加按钮上添加了add点击事件,add可以发布事件

第12行我们创建了一个add1事件,当添加按钮被点击时触发add函数,将add1事件发布,并将value值给到父组件

方法二:父组件借助v-model将数据绑定给子组件,子组件创建'update:xxx'事件,并接收到的数据修改后emits出来

父组件:

<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>
  
  <style lang="css" scoped>
  
  </style>

父组件引入子组件,定义了一个数组list,v-model:list将数据绑定给子组件

子组件:

<template>
    <div class="input-group">
      <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 emits = defineEmits(['update:list'])
  const add = () => {
    // props.list.push(value.value) // 不建议直接操作父组件给过来的数据,会污染数据
  
    const arr = props.list
    arr.push(value.value)
    emits('update:list', arr)
  }
  </script>
  
  <style lang="css" scoped></style>

defineProps定义了接收数据的类型及默认是空数组

defineEmits定义了一个事件update:list,当点击按钮触发add,会将update:list事件发布出去

23到25行不直接修改父组件的数据而是新new了一个数组arr,将数组arr给父组件。

方法三:父组件通过ref获取子组件中defineExpose() 暴露出来的数据

父组件:

<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>
  
  <style lang="css" scoped>
  
  </style>

父组件引入子组件,ref="childRef"可以让父组件访问到子组件。

v-for="item in childRef?.list"当childRef有不为空时访问list数组,以防还没拿到数据就编译这行代码导致错误。

子组件:

<template>
    <div class="input-group">
      <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:list }) // 心甘情愿暴露出来list
  </script>
  
  <style lang="css" scoped></style>

这种方法只需将子组件input框的值放入数组中,任何将list数组暴露出来就行了

defineExpose({ list:list })可以将list暴露给父组件

总结

今天我们聊了不同组件之间的通讯,希望对你们有帮助,可以的画帮忙点个赞。好好学习,天天向上!