总结 Vue3 的 13 种传参通信方式,非常齐全!!!

目录

一、父传子

二、子传父

三、兄弟组件传参(mitt)

 四、$attrs

五、refs传参

六、v-model

八、路由传参

九、vuex 传参 / pinia

十、浏览器缓存

十一、通过window对象全局挂载全局对象或者属性

十二、app.config.globalProperties


在前端项目离不开的传参通信方式,今天总结关于 Vue3 的传参方式如下:

  1. props 父传子
  2. defineEmits 子传父
  3. mitt 兄弟组件传参
  4. $attrs (爷孙)
  5. refs
  6. v-model (双向)
  7. provide/inject (多层)
  8. 路由传参
  9. vuex 传参 (全局)
  10. pinia 传参 (全局)
  11. 浏览器缓存 (全局)
  12. window (全局)
  13. app.config.globalProperties (全局)

一、父传子

 思路:父组件通过冒号:绑定变量,然后子组件用 const props = defineProps({}) 进行接收参数。

 父组件代码: 在第二行那里 :name="name"  把那么传给子组件

<template>
  <child :name="name"></child>
</template>

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

const name = ref('天天鸭')
</script>

子组件代码: const props = defineProps ({}) 接收后直接在标签使用

<template>
  <div>{
  
  { props.name }}</div>
</template>

<script setup>
import { defineProps } from 'vue'
const props = defineProps({
  name: {
    type: String,
    default: '',
  },
})
</script>

二、子传父

思路:子组件用 const emits = defineEmits( ['触发的方法'] )  注册某个在父组件的事件,然后通过 emits ( '触发的事件', 参数 ) 触发父组件事件并且带上参数。

 子组件代码: 注册 addEvent 事件后, 用 emits('addEvent', name.value) 触发父组件的 addEvent事件

<template>
  <div ></div>
</template>

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

const name = ref('天天鸭')
const emits = defineEmits(['addEvent'])
const handleSubmit = () => {
  emits('addEvent', name.value)
}
</script>

父组件代码: 触发 addEvent 事件后,在对应的方法里面直接能拿到传过来的参数

<template>
  <child @addEvent="handle"></child>
</template>

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

const handle = value => {
  console.log(value); // '天天鸭'
}
</script>

三、兄弟组件传参(mitt)

以前 vue2 是用 EventBus 事件总线跨组件实现兄弟组件通信的。但 vue3 中没有,所以 vue3 目前主流使用 mitt.js 插件来进行替代实现兄弟通信。

 1、npm 包引入

 npm install --save mitt

2、在 main.js 文件进行全局挂载, $bus 是自定义属性名

import mitt from "mitt"

const app = createApp(App)

app.config.globalProperties.$bus = new mitt()

3、传参出去的兄弟组件代码

<script setup>
    import mitt from 'mitt'
    const emitter = mitt()
    emitter.emit('自定义的事件名称','参数')
</script>

4、接收参数的兄弟组件代码

<script setup>
     import mitt from 'mitt'
     const emitter = mitt()
     emitter.on('自定义的事件名称', '参数' )
</script>

 四、$attrs

注意: 以前在在 vue2 里面中除了 $attrs,还有 $listeners ; 但 vue3 直接把 $listeners 合并到 $attrs 里面了。

 简要说明:$attrs 主要作用是接收没在 props 里面定义,但父组件又传了过来的属性。看下面代码例子就好懂多了

父组件代码: 传两个属性过去,一个在子组件 props 中,一个不在 

<template>
  <child :name="天天鸭" data="PC9527"/>
</template>

<script setup>
import child from './child.vue'
</script>

子组件代码$attrs 接收到 props 以外的内容,所以用 useAttrs() 打印出来没有 name 只有 data

<template>
  <div>
  {
  
  { props.name }}   // '天天鸭'
  </div>
</template>

<script setup>
import { defineProps, useAttrs } from 'vue'
const props = defineProps({
  name: {
    type: String
  }
})

const myattrs = useAttrs()
console.log(myattrs)   //  { "data": "PC9527" }
</script>

五、refs传参

简单说明:父组件通过在子组件上定义 ref='ref 名称',然后 const ref名称 = ref(null),就能通过 ref 名称操控子组件的属性和方法(子组件用 defineExpose 对外暴露才能被操控),具体看下面例子。

父组件代码: 

<template>
  <child ref="myref"></child>
  <button @click="myClick">点击</button>
</template>

<script setup>
  import child from "./child.vue"
  import { ref } from "vue"
  const myref = ref(null)
  const myClick = () => {
      console.log(myref.value.name) // 直接获取到子组件的属性
      myref.value.chileMethod()      // 直接调用子组件的方法
  }
</script>

子组件代码: defineExpose 对外暴露才能被操控

<template>
  <div></div>
</template>

<script setup>
    import { defineExpose } from "vue"

    const chileMethod = () =>{
      console.log("我是方法")
    }
    const name = ref('天天鸭')

    defineExpose({    // 对外暴露
        name,
        chileMethod
    })
</script>

六、v-model

简单讲解: v-model 其实语法糖,如下两行代码作用是一样, 上面是下面的简写。

<chile v-model:title="title" />

<chile :title="title" @update:title="title = $event" />

 父组件代码: 直接使用 v-model 传参

<template>
  <child v-model:name="name" v-model:num="num"></child>
</template>

<script setup>
    import child from "./child.vue"
    import { ref, reactive } from "vue"
    const name = ref("天天鸭")
    const num = ref("2222")
</script>

子组件代码: 通过 defineEmits 获取到然后用 emit ( "update: 修改的属性", 修改的内容 ) 进行修改父组件的内容,注意:update: 是固定写法。

<template>
  <button @click="myClick">点击</button>
</template>

<script setup>
  import { defineEmits } from "vue"
  const emit = defineEmits(["name","num"])
  
  // 子组件触发使用
  const myClick = () => {
      emit("update:name", "改个新名字")
      emit("update:num", "换个新号码")
  }
</script>

v-model扩展:defineModel():

defineModel() 宏的简单说明:父子组件的数据双向绑定,不用 emit 和 props 的繁重代码

版本要求:必须要 3.4+

 示例场景:父组件引入一个子组件弹窗,点击就父传子( props )弹出子组件弹窗,子组件里面有个按钮点击就子传父( emit )关闭

 父组件代码: v-model 在子组件身上绑定 showDevice 属性,该属性用于通知子组件是否打开弹窗。

<template>
  <child v-if="showDevice" v-model="showDevice"></child>
</template>

<script setup>
    import child from "./child.vue"
    import { ref } from "vue"
    
    const showDevice = ref(false) // 控制子组件的显示和隐藏
</script>

子组件代码: 如下的 handleClickCancel 方法,通过 defineModel 宏声明一个 model,点击按钮能直接通知父组件修改属性。

<template>
  <button @click="handleClickCancel">点击取消子组件弹窗</button>
</template>

<script setup>
  import { defineModel } from 'vue'
  const model = defineModel()                       // 写法一
  // const model = defineModel({ type: Boolean })   // 写法二 也可以用声明类型的方法

  const handleClickCancel = () => {
    model.value = false
  }
</script>

上面例子通过 defineModel 宏,直接不需要 props 和 emit 就实现了父子通信效果,非常简洁好用。

七、provide/inject

简单讲解:provideinject 叫依赖注入,是 vue 官方提供的 API,它们可以实现多层组件传递数据,无论层级有多深,都可以通过这 API 实现。

假设这是太老爷组件: provide ( '名称', 传递的参数 ) 向后代组件提供数据, 只要是后代都能接收

<template>
  <div></div>
</template>

<script setup>
import { ref, provide } from 'vue'
const name = ref('天天鸭')
// 向后代组件提供数据, 只要是后代都能接收
provide('name', name.value)
</script>

最深层的孙组件: 无论层级多深,用 inject ( 接收什么参数 ) 进行接收即可

<template>
  <div>{
  
  { name }}</div>
</template>

<script setup>
import { inject } from 'vue'
// 接收顶层组件的通信
const name = inject('name')
</script>

八、路由传参

简单讲解: 路由跳转事上参数也是传参的一种,而且传参方式还不止一种呢,下面细说。

1、query传参

// 传递方
const query = { id: 9527, name: '天天鸭' }
router.push({ path: '/user', query })

// 接收方
import { useRoute} from 'vue-router'
const route = useRoute()
console.log(route.query)

 2、params传参

注意:4.1.4 (2022-08-22) 删除了 param 这种方式

// 发送方
router.push({
   name: 'test', 
   params: {
       name: '天天鸭'
   }
})
 
// 接收方
import { useRoute} from 'vue-router'
const route = useRoute()
console.log(route.params) // { name: '天天鸭' }

 3、state 传参

// 发送方
const state= { name: '天天鸭' }
router.push({ path: '/user', state })
 
// 接收方直接使用
console.log(history?.state?.name)

九、vuex 传参 / pinia

写过对应的文章,可以直接细看:对比 vuex 和 pinia

https://juejin.cn/post/7355050145485914149

十、浏览器缓存

localStoragesessionStorage: 这算是用的不多,但也是必用的一种通信方式了,下面看看区别:

sessionStorage(临时存储):为每一个数据源维持一个存储区域,在浏览器打开期间存在,包括页面重新加载

localStorage(长期存储):与 sessionStorage 一样,但是浏览器关闭后,数据依然会一直存在

 下面直接上使用的语法。

// 存储数据
localStorage.setItem('key', 'value');
sessionStorage.setItem('key', 'value');

// 获取数据
const valueFromLocalStorage = localStorage.getItem('key');
const valueFromSessionStorage = sessionStorage.getItem('key');

// 删除数据
localStorage.removeItem('key');
sessionStorage.removeItem('key');

// 清空所有数据
localStorage.clear();
sessionStorage.clear();

十一、通过window对象全局挂载全局对象或者属性

简单说明:直接用语法 window.name = '天天鸭' 定义然后 全局 通用即可。存放在内存刷新会清空。

注意:在 Vue 3 应用程序中,虽然可以直接将属性挂载到 window 对象上实现全局访问,但这并不是推荐的做法,因为直接修改全局对象可能会导致命名冲突、难以进行模块化管理以及不利于应用的封装与维护。 

用法:直接定义,可以是属性也可以是对象

window.duname = '天天鸭'
window.duObj = { test: '看看对象' }

引用:

console.log( window.duname);   // 天天鸭 
console.log( window.duObj);   // {test: '看看对象'}

十二、app.config.globalProperties

简单讲解:app.config.globalProperties 是Vue官方的一个 api,这是对 Vue 2 中 Vue.prototype 使用方式的一种替代,Vue.prototype 法在 Vue3 已经不存在了。与任何全局的东西一样,应该谨慎使用

 用法示例:在 main.js 文件挂载一个全局的 msg 属性

import { createApp } from 'vue'

const app = createApp(App)

app.config.globalProperties.msg = 'hello'

在其它页面使用 getCurrentInstance() 获取

import { getCurrentInstance } from "vue";

const { proxy } = getCurrentInstance() // 使用proxy,类似于vue2的this

console.log(proxy.msg);    // hello

总结:

参考与:https://juejin.cn/post/7356817667574284340

如果有那里不对或者有补充欢迎大佬指导。有幸能让你看到这里,希望给个点赞哦。

### Vue3 父子组件传参方法及其示例 #### 1. 使用 Props 实现父组件向子组件传递数据 在 Vue 3 中,`props` 是一种常见的机制,用于从父组件向子组件传递数据。父组件通过 `v-bind` 将数据绑定到子组件的属性上,而子组件则通过声明 `props` 来接收这些数据。 **父组件代码示例:** ```html <template> <ChildComponent :message="parentMessage" /> </template> <script setup> import ChildComponent from &#39;./ChildComponent.vue&#39;; const parentMessage = "这是来自父组件的消息"; </script> ``` **子组件代码示例:** ```html <template> <div>{{ message }}</div> </template> <script setup> defineProps({ message: { type: String, required: true } }); </script> ``` 上述代码展示了如何使用 `props` 进行父子组件间的单向数据流[^1]。 --- #### 2. 使用 `$emit` 实现子组件向父组件发送事件 当子组件需要通知父组件某些状态变化时,可以使用 `$emit` 发送自定义事件。父组件监听该事件并执行相应逻辑。 **子组件代码示例:** ```html <template> <button @click="sendEvent">点击触发事件</button> </template> <script setup> const emit = defineEmits([&#39;child-event&#39;]); function sendEvent() { emit(&#39;child-event&#39;, &#39;这是子组件的数据&#39;); } </script> ``` **父组件代码示例:** ```html <template> <ChildComponent @child-event="handleChildEvent" /> <p>接收到的数据:{{ receivedData }}</p> </template> <script setup> import ChildComponent from &#39;./ChildComponent.vue&#39;; let receivedData = &#39;&#39;; function handleChildEvent(data) { receivedData = data; } </script> ``` 此部分说明了 `$emit` 如何帮助实现子组件与父组件之间的双向通信[^2]。 --- #### 3. 使用 `provide/inject` 跨级组件间通信 对于多层嵌套的组件结构,`provide/inject` 可以简化跨级通信的过程。祖父组件提供数据,后代组件可以直接注入而不需逐层传递。 **祖父组件代码示例:** ```html <template> <ParentComponent /> </template> <script setup> import ParentComponent from &#39;./ParentComponent.vue&#39;; // 提供共享数据 provide(&#39;sharedMessage&#39;, &#39;这是来自祖父组件的信息&#39;); </script> ``` **子孙组件代码示例:** ```html <template> <div>{{ sharedMessage }}</div> </template> <script setup> // 注入共享数据 const sharedMessage = inject(&#39;sharedMessage&#39;, &#39;&#39;); </script> ``` 这里描述了 `provide/inject` 的工作原理和适用场景[^3]。 --- #### 4. 使用 Vuex 或 Pinia 管理全局状态 如果项目规模较大或者涉及多个组件的状态同步问题,则推荐使用 Vuex(Vue 2/3)或 Pinia(Vue 3 推荐)。它们提供了集中式的存储解决方案。 **Vuex 示例:** ```javascript // store.js import { createStore } from &#39;vuex&#39;; export default createStore({ state: { count: 0 }, mutations: { increment(state) { state.count++; } } }); // 在任何组件中访问 this.$store.commit(&#39;increment&#39;); console.log(this.$store.state.count); ``` **Pinia 示例:** ```javascript // pinia-store.js import { defineStore } from &#39;pinia&#39;; export const useCounterStore = defineStore(&#39;counter&#39;, { state: () => ({ count: 0 }), actions: { increment() { this.count++; } } }); // 在任何组件中访问 const counterStore = useCounterStore(); counterStore.increment(); console.log(counterStore.count); ``` 这部分介绍了 Vuex 和 Pinia 的基本用法以及其优势[^5]。 --- #### 5. 使用 `$refs` 访问子组件实例 有时可能需要直接操作子组件的方法或内部变量,在这种情况下可以借助 `$refs` 完成。 **父组件代码示例:** ```html <template> <ChildComponent ref="childRef" /> <button @click="callChildMethod">调用子组件方法</button> </template> <script setup> import ChildComponent from &#39;./ChildComponent.vue&#39;; import { ref } from &#39;vue&#39;; const childRef = ref(null); function callChildMethod() { childRef.value.childFunction(); // 假设子组件有名为 childFunction 的方法 } </script> ``` **子组件代码示例:** ```html <template></template> <script setup> function childFunction() { console.log(&#39;子组件方法被调用了!&#39;); } </script> ``` 以上内容解释了 `$refs` 的作用及其实现细节。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值