🔥🔥🔥Vue3中的常用组件通信大总结 包括Vue3.4defineModel()实现组件双向绑定

前言

Vue中官网是这么介绍组件的:组件允许我们将UI划分为独立的、可重用的部分,并且对每个部分进行单独的思考

如果一个文件包含四五个组件,那么他们之间的数据通信如何解决呢,所以组件中数据通信是Vue中非常重要的知识

父传子(子组件使用父组件的 state&& function)

props

xml 复制代码
//父组件
<template>
<div>
这是父组件
</div>
<child :state=state :ParentFn=ParentFn></child>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import child from "./components/index.vue"
const state = ref<string>('这是父组件的state')
const ParentFn =() => {
console.log('这是父组件的方法')
}
</script>
//子组件
<template>
<div>这是子组件</div>
<div>这是父组件传过来的值{{ props.state}}</div>
<button @click="props.ParentFn">触发父组件方法</button>
</template>
<script lang="ts" setup>
const props = defineProps({
	state: String,
	ParentFn:Function,

})
</script>

attrs:包含父作用域里除 class 和 style 除外的非 props 属性集合

xml 复制代码
//父组件
<template>
<child :msg1="msg1" :msg2="msg2" title="good"></child>
</template>
<script setup>
import child from "./components/index.vue"
import { ref, reactive } from "vue"
const msg1 = ref(1)
const msg2 = ref(2)
</script>
//子组件
<template>
<div>{{attrs}}</div>
</template>
<script lang="ts" setup>
import {useAttrs} from "vue"
defineProps({
msg1: Number
})
const attrs = useAttrs()
console.log(attrs) //{ "msg2": 2, "title": "good" }
</script>
//子组件第二种使用方式
//将父组件传递的所有非 prop 属性绑定到子组件的元素上
<template>
<div v-bind="$attrs"></div>
</template>

子传父(父组件使用子组件的state &&function)

emit这个方法我用的比较少 代码比较繁琐且难用

vue 复制代码
//父组件
<template>
<child @myClick="onMyClick"/>
</template>
<script setup lang="ts">
import child from "./components/index.vue"
const onMyClick = (msg:any) => {
console.log(msg) // 这是父组件收到的信息
}
</script>
//子组件
<template>
<div>这是子组件</div>
<button @click="handleClick">按钮</button>
</template>
<script lang="ts" setup>
const emit = defineEmits(["myClick"])
const handleClick = ()=>{
emit("myClick", "这是发送给父组件的信息")
}
</script>

defineExpose + ref

ref绑定在子组件上可以在父组件中来访问子组件的实例

在子组件使用defineExpose暴露方法或变量

xml 复制代码
//父组件
<template>

<div> 这是父组件</div>

<div> 这是子组件的数据{{childRef?.state }}</div>

<button @click="childRef!.fnFromChild">触发子组件</button>

<child ref="childRef"></child>

</template>
<script setup lang="ts">

import { ref } from 'vue';

import child from "./components/index.vue"

const childRef = ref<null | {state:string,fnFromChild:Function}>(null)

</script>

//这是子组件
<template>

<div>这是子组件</div>

</template>
<script lang="ts" setup>
import { ref } from 'vue';
const state = ref<string>("hello")
const fnFromChild = () => {
console.log('这是子组件的方法')
}
defineExpose(
{
state,
fnFromChild
}
)
</script>

v-model: 在子组件直接修改父组件数据

xml 复制代码
//这是父组件

<template>
<div> 这是父组件{{ params }}</div>
<child v-model="params"></child>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import child from "./components/index.vue"
const params = ref<string>('1')
</script>
//这是子组件
<template>
<div>这是子组件{{ modelValue }}</div>
</template>
<script lang="ts" setup>
defineProps({
modelValue: String
})
//实现了父传子

</script>
// 实现子组件修改父组件数据
<template>
<div>这是子组件{{ modelValue }}</div>
<button @click="updateValue">子组件的方法 改变父组件数据</button>
</template>

<script lang="ts" setup>
defineProps({
modelValue: String
})
const emit = defineEmits(["update:modelValue"])
const updateValue = () => {
emit("update:modelValue","我是父组件的值 我被子组件改变的")
}
</script>

v-model在组件上使用双向绑定

从 Vue 3.4 开始,推荐的实现方式是使用 defineModel()其实就是上述例子的语法糖

defineModel() 返回的值是一个 ref, 它的 .value 和父组件的 v-model 的值同步

⚠️ 注意 如果为 defineModel prop 设置了一个 default 值且父组件没有为该 prop 提供任何值,会导致父组件与子组件之间不同步

xml 复制代码
//父组件
<template>
<div> 这是父组件{{ count}}</div>
<child v-model="count"></child>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import child from "./components/index.vue"
const count= ref<number>(1)
</script>

//子组件
<template>
<div>这是子组件{{ model}}</div>
<button @click="update">子组件的方法 改变父组件数据</button>
</template>
<script lang="ts" setup>
const model = defineModel({default : 1})
function update() {
model.value++
}
</script>

组件上的 v-model 也可以接受一个参数

xml 复制代码
//父组件
<child v-model:title="bookTitle" />
//子组件
<script setup>
const title = defineModel('title')
</script>

<template>
  <input type="text" v-model="title" />
</template>

多个v-model绑定

xml 复制代码
//父组件
<child v-model:first-name="first" v-model:last-name="last" />
//子组件
<script setup>
const firstName = defineModel('firstName')
const lastName = defineModel('lastName')
</script>

<template>
  <input type="text" v-model="firstName" />
  <input type="text" v-model="lastName" />
</template>

祖孙通信 provide && inject

用于提供可以被后代组件注入的值

这个组件库用的多些,因为组件库不知道你会在哪使用它提供的值

xml 复制代码
//先代组件
<script setup>
import { ref, provide } from 'vue'
import { countSymbol } from './injectionSymbols'
// 提供静态值
provide('path', 'good')
// 提供响应式的值
const count = ref(0)
provide('count', count)
// 提供时将 Symbol 作为 key
provide(countSymbol, count)
</script>
//后代组件
<script setup>
import { inject } from 'vue'
import { countSymbol } from './injectionSymbols'
// 注入不含默认值的静态值
const path = inject('path')
// 注入响应式的值
const count = inject('count')
// 通过 Symbol 类型的 key 注入
const count2 = inject(countSymbol)
// 注入一个值,若为空则使用提供的默认值
const bar = inject('path', '/default-path')
</script>

全局通信 Pinia

接下来贴一波日常使用的代码 创建文件夹stroe 创建文件index.ts

ts 复制代码
//这样引入方便pinia使用插件比如
// 比如持久化 pinia.use(piniaPluginPersistedstate)
import { createPinia } from 'pinia'
const pinia = createPinia()
export default pinia
//在main.ts中
import pinia from '@/stores'
app.use(pinia)

创建文件user.ts

ts 复制代码
import { defineStore } from 'pinia'
import { UserState } from '@/stores/interface'
export const useUserStore = defineStore('Oner-user', {
state: (): UserState => ({
token: '',
userInfo: { name: 'Oner' },
userVerify: '',
currentPage: 0,
}),
getters: {},
actions: {
// Set Token
setToken(token: string) {
this.token = token
},
// Set setUserInfo
setUserInfo(userInfo: UserState['userInfo']) {
this.userInfo = userInfo
},
setUserVerify(verify: string) {
this.userVerify = verify
},
setCurrentPage(value: number) {
this.currentPage = value
},
},
})

在任意组件中使用

ts 复制代码
const userStore = useUserStore()
console.log(userStore.token) // ''
console.log(userStore.setToken("zhaimoudetoken"))
console.log(userStore.token) // zhaimoudetoken

文章到这里就结束了,希望对你有所帮助。

相关推荐
Pedantic42 分钟前
SwiftUI 手势层级(Gesture Hierarchy)详解
前端
飘尘1 小时前
前端转型全栈(Java后端)的快速上手指引
前端·后端·全栈
一颗烂土豆1 小时前
Meshopt 压缩深度解析,为什么它比 Draco 更快
前端·javascript·webgl
浏览器工程师2 小时前
AI Agent 接浏览器任务,先别让它一路点到底
前端·后端
雨季mo浅忆2 小时前
VSCode自动格式化三要素
前端
爱勇宝3 小时前
深扒 Anthropic 1680 位工程师简历:应届生几乎没机会,AI 公司最缺的不是博士
前端·后端·程序员
kyriewen3 小时前
同事每天催我 Code Review,我写了个脚本让 AI 替我 review PR——现在他反过来催 AI 了
前端·javascript·ai编程
user20585561518136 小时前
Windows 项目安装时报 `node-sass` 错误,如何快速处理
前端
LiaCode6 小时前
Redis 在生产项目的使用
前端·后端