vue3中的组件通信

在开发中,发现了一些常用的vue中组件通信的方法,接下来我将为大家介绍下,如有错误请及时批评指正。

通信方法

  • 父组件给子组件传值
  1. 父组件用v-bind传递数据给子组件,子组件用defineProps接收数据。
  2. 父组件通过provide传递数据,子组件通过inject注入。
  • 子组件给父组件传值
  1. 子组件用defineEmitd定义事件发布,父组件用v-on订阅事件。
  2. 子组件通过defineExpose暴露数据,父组件通过ref引用组件中的数据
  3. 父组件通过v-model,子组件通过defineProps接受,然后定义'update:xxx'事件,并修改父组件给送过来数据,但一定是要发布'update:xxx'
  • 兄弟组件通信
  1. 在外部的js文件中定义响应式变量,同时引入到两个组件中,因为是响应式的,所以两个组件都可以修改这给变量,从而实现通信。

组件通信的写法

父传子

我们要写一个输入框和一个点击按钮,点击按钮后,会将输入框中的内容添加到数组,放入子组件中展示。

  1. 通过在父组件中通过属性绑定v-bind将数据传递给子组件,子组件通过defineProps声明Props来接受数据。
js 复制代码
<template>

  <div class="head">
    <input type="text" v-model="msg">
    <button @click="add">添加</button>
  </div>

  <Child :data="data" />

</template>

<script setup>
import Child from './child.vue'
import { ref } from 'vue'
const msg = ref('')
const data = ref('')//这里定义一个data,来保证传入的数据在点击添加才会改变,不被msg的值的改变影响
const add = () => {
  data.value = msg.value
}
</script>

<style lang="css" scoped></style>
js 复制代码
<template>
  <div class="body">
    <ul>
      <li v-for="(item, index) in list" :key="index">{{ item }}</li>
    </ul>
  </div>
</template>

<script setup>
import { ref, watch } from 'vue'

const props = defineProps({
  data: {
    type: String,
    default: ''
  }
})

const list = ref(['html', 'css', 'js'])

watch(() => props.data, (newVal) => { //监听如果传入的数据有改变,添加进入数组
  if (newVal) {
    list.value.push(newVal)
  }
})

</script>

<style lang="css" scoped></style>

这种写法并不是很好,将数据放在子组件中储存,会导致子组件的复用性降低,比如写一个展示数据的组件,放在主页能用,放到展示其他数据的页面就不行了。最好是将数据放在父组件中,子组件只发出更改的请求。可以根据项目需求使用,需要重复用的子组件最好别这样写。

  1. 父组件通过provide数据,子组件通过inject接收父组件传来的数据。provide有穿透的效果,在子组件的子组件中也能收到父组件传来的值。用readonly冻结数据,防止在子组件中修改。
js 复制代码
<template>

  <div class="head">
    <input type="text" v-model="msg">
    <button @click="add">添加</button>
  </div>

  <Child />

</template>

<script setup>
import Child from './child.vue'
import { ref, provide, readonly } from 'vue'

const msg = ref('')
const list = ref(['html', 'css', 'js'])
const add = () => {
  list.value.push(msg.value)
  console.log(list.value);
}

provide('list', readonly(list.value))  // 向下提供数据,用readonly防止子组件被修改

</script>

<style lang="css" scoped></style>
js 复制代码
<template>
  <div class="body">
    <ul>
      <li v-for="(item, index) in list" :key="index">{{ item }}</li>
    </ul>
  </div>
</template>

<script setup>
import { inject } from 'vue'

const list = inject('list')  // 注入数据

</script>

<style lang="css" scoped></style>

子传父

  1. 子组件用defineEmitd 定义事件并发布,父组件用v-on订阅事件。在子组件中发布事件,在父组件中接受数据。
js 复制代码
<template>
  <Child @add="handle" />//这里定义了函数,来接受子组件的add事件(子组件发布的事件)

  <div class="body">
    <ul>
      <li v-for="(item, index) in list" :key="index">{{ item }}</li>
    </ul>
  </div>
</template>

<script setup>
import Child from './child.vue'
import { ref } from 'vue'

const list = ref(['html', 'css', 'js'])
const handle = (val) => {
  list.value.push(val)
}
</script>

<style lang="css" scoped></style>
js 复制代码
<template>
  <div class="head">
    <input type="text" v-model="msg">
    <button @click="add">添加</button>
  </div>
</template>

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

const emit = defineEmits(['add'])  // 定义事件
const add = () => {
  emit('add', msg.value)
}
</script>

<style lang="css" scoped></style>
  1. 子组件通过defineExpose暴露数据,父组件通过ref引用组件中的数据.子组件将数据放到全局,让所有组件都可以拿到。
js 复制代码
<template>
  <Child ref="childRef" />

  <div class="body">
    <ul>
      <li v-for="(item, index) in childRef?.list" :key="index">{{ item }}</li>
    </ul>
  </div>
</template>

<script setup>
import Child from './child.vue'
import { ref } from 'vue'

const childRef = ref(null)

setTimeout(() => {
  console.log(childRef.value.list)
}, 1000)

</script>

<style lang="css" scoped></style>
js 复制代码
<template>
  <div class="head">
    <input type="text" v-model="msg">
    <button @click="add">添加</button>
  </div>
</template>

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

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

<style lang="css" scoped></style>
  1. 父组件通过v-model,子组件通过defineProps接受,然后定义'update:xxx'事件,并修改父组件给送过来数据,但一定是要发布'update:xxx'。其实是一个语法糖,defineProps在子组件接受父组件的数据,修改好了后,用defineEmits传回给父组件,完成通信。
js 复制代码
<Child v-model:list="list" />//等于下面的写法
<Child v-bind:list="list" @update:title="pageTitle = $event"/>//v-bind用于接受父组件传来的数据,@updata在数据改变这个事件后,把数据从子组件传回给父组件。
js 复制代码
<template>
  <div class="head">
    <input type="text" v-model="msg">
    <button @click="add">添加</button>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const msg = ref('')
const props = defineProps(['list'])

const emits = defineEmits(['update:list'])
const add = () => {
  const arr = props.list
  arr.push(msg.value)

  emits('update:list', arr)
}

</script>

<style lang="css" scoped></style>
js 复制代码
<template>
  <Child v-model:list="list" />

  <div class="body">
    <ul>
      <li v-for="(item, index) in list" :key="index">{{ item }}</li>
    </ul>
  </div>
</template>

<script setup>
import Child from './child.vue'
import { ref } from 'vue'

const list = ref(['html', 'css', 'js'])

</script>

<style lang="css" scoped></style>

兄弟通信

在外部的js文件中定义响应式变量,同时引入到两个组件中,因为是响应式的,所以两个组件都可以修改这个变量,从而实现通信。其实用Pinian这种工具也行。

js 复制代码
<template>
  <div class="body">
    <ul>
      <li v-for="(item, index) in list" :key="index">{{ item }}</li>
    </ul>
  </div>
</template>

<script setup>
import { list } from './bus.js'



</script>

<style lang="css" scoped></style>
js 复制代码
<template>
  <div class="head">
    <input type="text" v-model="msg">
    <button @click="add">添加</button>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { list } from './bus.js'

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

</script>

<style lang="css" scoped></style>
js 复制代码
<template>

  <Head />

  <Body />
</template>

<script setup>
import Head from './head.vue';
import Body from './body.vue';
</script>

<style lang="css" scoped></style>

js文件

js 复制代码
import { ref } from 'vue'

export const list = ref(['html', 'css', 'js'])
相关推荐
一 乐6 分钟前
校园二手交易|基于springboot + vue校园二手交易系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端
科技D人生17 分钟前
Vue.js 学习总结(20)—— Vue-Office 实战:word、pdf、excel、ppt 多种文档的在线预览
vue.js·word·vue-pdf·stylesheet·docx-preview·vue-office
vx1_Biye_Design18 分钟前
基于Spring Boot+Vue的学生管理系统设计与实现-计算机毕业设计源码46223
java·vue.js·spring boot·spring·eclipse·tomcat·maven
vx_Biye_Design19 分钟前
基于Spring Boot+vue的湖北旅游景点门票预约平台的设计--毕设附源码29593
java·vue.js·spring boot·spring cloud·servlet·eclipse·课程设计
hedley(●'◡'●)19 分钟前
基于cesium和vue的大疆司空模仿程序
前端·javascript·vue.js·python·typescript·无人机
qq5_81151751521 分钟前
web城乡居民基本医疗信息管理系统信息管理系统源码-SpringBoot后端+Vue前端+MySQL【可直接运行】
前端·vue.js·spring boot
百思可瑞教育22 分钟前
构建自己的Vue UI组件库:从设计到发布
前端·javascript·vue.js·ui·百思可瑞教育·北京百思教育
百锦再22 分钟前
Vue高阶知识:利用 defineModel 特性开发搜索组件组合
前端·vue.js·学习·flutter·typescript·前端框架
hdsoft_huge24 分钟前
1panel面板中部署SpringBoot和Vue前后端分离系统 【图文教程】
vue.js·spring boot·后端
这儿有一堆花1 小时前
Vue 是什么:一套为「真实业务」而生的前端框架
前端·vue.js·前端框架