Vue3的11种组件间通信方式简单说明,前端必备5分钟完看学会

1024小神 2024-07-08 12:03:01 阅读 89

vue3出来很久了,也非常成熟了,平时项目只管用也没多想,直至今天想写一编关于vue3传参,然后我总结一下竟然总结出来11种方式那么多,11种我分别列了出来,由于vue3有两种setup写法,下面我将用最简洁的代码例子针对主流的<code><script setup>写法对每一种用法进行细说。

1.父传子

2.子传父

3.兄弟组件传参(mitt)

4.$attrs

5.refs

6.v-model

7.provide/inject

8.路由传参

9.vuex传参

10.pinia传参

11.浏览器缓存

一、父传子

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

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

<code><template>

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

</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>code>

</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"/>code>

</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对外暴露才能被操控),具体看下面例子。

父组件代码:

<code><template>

<child ref="myref"></child>code>

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

</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" />code>

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

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

<template>

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

</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>code>

</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>code>

</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>code>

</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

简单讲解:provide和inject叫依赖注入,是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传参

全局共享状态: 

import Vue from "vue"

import Vuex from "vuex"

Vue.use(Vuex);

export default new Vuex.Store({

state:{ // 用来定义一些变量

userName: "",

count: 1,

},

getters: { // 类似于计算属性

doneTodos (state) {

return state.count*2

}

},

mutations:{ // 是用来触发事件, 修改userName

saveName(state,userName){

state.userName = userName;

},

},

actions: { // 用于提交mutations,可以包含任意异步操作,, 在里面可以请求接口操作

increment (context) {

context.commit('saveName')

}

}

})

十、pinia

全局共享状态:

import {defineStore} from 'pinia'

const useUser = defineStore("user",{

state:() => ({ // 用来定义一些变量

mycount: 1,

}),

getters: { // 类似于计算属性

double: (state) => state.mycount * 2,

},

actions: { // 里面是一些方法,在里面可以请求接口操作

increment() {

this.mycount++

},

async registerUser(login, password) { // 异步操作

await api.post({ login, password })

}

}

})

export default useUser

十一、浏览器缓存

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

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();



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。