vue3-setup语法糖之组件传参(defineProps、defineEmits、defineExpose、provide、inject)

本文介绍了Vue3中使用defineProps和defineEmits进行父传子和子传父通信的方式。在<scriptsetup>语法下,这两个宏用于声明组件的props和emits,简化了数据传递的过程。同时,文章提到了defineExpose宏用于在组件中暴露特定的属性和方法,以便于父组件访问。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

vue3官方文档 

  • defineProps 和 defineEmits 都是只能在 <script setup> 中使用的编译器宏。他们不需要导入,且会随着 <script setup> 的处理过程一同被编译掉。

  • defineProps 接收与 props 选项相同的值,defineEmits 接收与 emits 选项相同的值。

父传子  - defineProps

 父组件

<template>
    <div class="Father">
        <p>我是父组件</p>
        <!--  -->
        <son :ftext="ftext"></son>
    </div>
</template>
    
<script setup>
import {ref} from 'vue'
import Son from './son.vue'
const ftext = ref('我是父组件-text')

    
</script>

子组件

<template>
    <div class="Son">
        <p>我是子组件</p>
       <!-- 展示来自父组件的值 -->
       <p>接收到的值:{
  {ftext}}</p>
    </div>
</template>
    
<script setup>
import {ref} from 'vue'
// setup 语法糖写法

//defineProps 来接收组件的传值
const props = defineProps({
    ftext: {
        type:String
    },
})

    
</script>

组件名格式

都使用 PascalCase 作为组件名的注册格式(每个字母开头大写)

<ComponentA></ComponentA>

import ComponentA from './ComponentA.js'

export default {
  components: {
    ComponentA
  },
  setup() {
    // ...
  }
}

 传递 prop 的细节

Prop 名字格式:如果一个 prop 的名字很长,应使用 camelCase 形式(即驼峰命名法)

在子组件里的defineProps使用  camelCase 形式(即驼峰命名法)

//子组件里使用
defineProps({
  greetingMessage: String
})

<span>{
  { greetingMessage }}</span>

虽然理论上你也可以在向子组件传递 props 时使用 camelCase 形式 (使用 DOM 内模板时例外),但实际上为了和 HTML attribute 对齐,我们通常会将其写为 kebab-case 形式(即单词连接命名法 greeting-message): 

在父组件里引用子组件且传递参数时 使用 kebab-case 形式

//父组件
<MyComponent greeting-message="hello" />

子传父 - defineEmits

子组件: 

<template>
    <div class="Son">
        <p>我是子组件</p>
        <button @click="toValue">点击给父组件传值</button>
    </div>
</template>
    
<script setup>
import {ref} from 'vue'
// setup 语法糖写法
//用defineEmits()来定义子组件要抛出的方法,语法defineEmits(['要抛出的方法'])
const emit = defineEmits(['exposeData'])

const stext = ref('我是子组件的值-ftext')
const toValue = ()=>{
    emit('exposeData',stext)
}
    
</script>

 父组件:

<template>
    <div class="Father">
        <p>我是父组件</p>
        <!--  -->
        <son @exposeData="getData" :ftext="ftext"></son>
    </div>
</template>
    
<script setup>
import {ref} from 'vue'
import Son from './son.vue'
const ftext = ref('我是父组件-text')
const getData = (val)=>{
    console.log("接收子组件的值",val)
}
</script>

参考文档:<script setup> | Vue.js 

Props | Vue.js 组件事件 | Vue.js


defineExpose 

 官方解释:

使用 <script setup> 的组件是默认关闭的(即通过模板引用或者 $parent 链获取到的组件的公开实例,不会暴露任何在 <script setup> 中声明的绑定)。

可以通过 defineExpose 编译器宏来显式指定在 <script setup> 组件中要暴露出去的属性

子组件:

<template>
    <div>
        <p>我是子组件</p>
    </div>
</template>
    
<script setup>
import { ref } from 'vue';

    const stext = ref('我是子组件的值')
    const sfunction = ()=>{
        console.log("我是子组件的方法")
    }
    defineExpose({
        stext,
        sfunction
    })
</script>

父组件:

<template>
	<div class="todo-container">
		<p>我是父组件</p>
		<son ref="sonDom"></son>
		<button @click="getSonDom">点击</button>
	</div>
</template>

<script setup>
import { ref ,nextTick} from 'vue';
	import son from './components/son.vue'
	const sonDom = ref(null) //注意这里的命名要和ref上面的命名一致
	const getSonDom = ()=>{
		console.log("sonDom",sonDom.value)
	}

	//直接打印sonDom的值是拿不到的,子组件节点还没生成
	nextTick(()=>{
		console.log("sonDom",sonDom.value)
	})
	
	
</script>

参考文档: <script setup> | Vue.js


上面所说的都是常规的父子组件(一级嵌套),如果出现多层的嵌套,那么使用props传参很麻烦。

provide 和 inject 可以帮助我们解决这一问题 [1]。一个父组件相对于其所有的后代组件,会作为依赖提供者。任何后代的组件树,无论层级有多深,都可以注入由父组件提供给整条链路的依赖。

参考文档:依赖注入 | Vue.js

<think>好的,我需要帮助用户解决在Vue3中使用WebSocket并通过setup语法糖实现功能的问题。首先,我得回忆一下Vue3setup语法糖和WebSocket的基本用法。用户提到使用setup语法糖,也就是<scriptsetup>的形式,这样可以让代码更简洁。同时,他们需要集成WebSocket,可能需要全局管理连接,或者在组件内直接使用。根据提供的引用,用户可能希望使用Pinia进行状态管理,或者全局注入WebSocket的处理函数。 引用[1]和[2]提到了使用Pinia存储WebSocket的数据,以及在main.ts中全局初始化WebSocket。这可能是一个好的方向。用户可能需要在多个组件中接收WebSocket消息,所以全局管理比较合适。同时,setup语法糖中如何访问实例或使用生命周期钩子也是需要考虑的。接下来,我需要考虑如何组织代码。首先,在Pinia中创建存储WebSocket数据和状态的store,这样可以在不同组件中共享数据。然后在main.ts中初始化WebSocket连接,并设置回调函数,将接收到的消息分发到各个组件的处理函数中。这样,组件只需要注册自己的消息处理函数即可,而不需要直接管理WebSocket连接。在组件内部,使用setup语法糖时,如何引入Pinia的store,以及如何注册消息处理函数。例如,使用inject获取全局的onMessageList,并将处理函数push进去。同时,可能需要使用onMounted和onUnmounted生命周期钩子来注册和移除处理函数,避免内存泄漏。 另外,引用[3]提到在setup中使用getCurrentInstance来获取实例,但通常不推荐这样做。更好的做法是使用ref和reactive来管理响应式数据,以及使用provide/inject进行跨组件通信。现在,需要将这些步骤整理成一个清晰的示例教程。首先创建WebSocket的Pinia store,然后在main.ts中初始化WebSocket,并设置全局的消息处理。接着,在组件中使用setup语法糖,引入store,并注册自己的消息处理逻辑。同时,处理连接状态和错误情况,确保健壮性。 可能还需要考虑WebSocket的重连机制,但用户的问题可能暂时不需要这么复杂。先完成基本功能,再提及优化点。最后,生成相关问题,帮助用户深入理解,比如如何优化WebSocket连接、处理多页面消息分发等。</think>### 在Vue3中使用WebSocket并通过Setup语法糖实现功能 以下是基于Vue3 Composition API和Setup语法糖的WebSocket实现方案,整合了全局状态管理和组件级响应式交互: #### 一、创建Pinia WebSocket Store ```typescript // src/store/webSocket.ts import { defineStore } from "pinia"; import { ref, reactive } from "vue"; export const useWebSocketStore = defineStore("webSocket", () => { // 响应式状态 const messages = ref<any[]>([]); const connectionStatus = ref<"closed" | "connecting" | "open">("closed"); const error = ref<string>(""); // WebSocket实例 let socket: WebSocket | null = null; // 操作方法 const connect = (url: string) => { connectionStatus.value = "connecting"; socket = new WebSocket(url); socket.onopen = () => { connectionStatus.value = "open"; }; socket.onmessage = (event) => { messages.value.push(JSON.parse(event.data)); }; socket.onerror = (e) => { error.value = "WebSocket连接异常"; }; socket.onclose = () => { connectionStatus.value = "closed"; }; }; const sendMessage = (data: any) => { if (socket?.readyState === WebSocket.OPEN) { socket.send(JSON.stringify(data)); } }; const disconnect = () => { socket?.close(); }; return { messages, connectionStatus, error, connect, sendMessage, disconnect }; }); ``` #### 二、全局WebSocket初始化 ```typescript // main.ts import { createApp } from &#39;vue&#39; import App from &#39;./App.vue&#39; import { useWebSocketStore } from &#39;./store/webSocket&#39; const app = createApp(App) // 初始化WebSocket连接 const wsStore = useWebSocketStore() wsStore.connect(&#39;wss://your-websocket-url&#39;) app.mount(&#39;#app&#39;) ``` #### 三、组件级实现(Setup语法糖) ```vue <!-- src/components/WebSocketDemo.vue --> <script setup lang="ts"> import { useWebSocketStore } from &#39;@/store/webSocket&#39; import { onMounted, onUnmounted, watch } from &#39;vue&#39; const wsStore = useWebSocketStore() // 实时显示连接状态 watch( () => wsStore.connectionStatus, (newStatus) => { console.log(`连接状态变更: ${newStatus}`) } ) // 组件挂载时自动订阅消息 onMounted(() => { console.log(&#39;WebSocket组件已挂载&#39;) }) // 组件卸载时清理资源 onUnmounted(() => { wsStore.disconnect() }) // 发送测试消息 const sendTestMessage = () => { wsStore.sendMessage({ type: &#39;test&#39;, content: &#39;Hello WebSocket&#39; }) } </script> <template> <div> <p>连接状态:{{ wsStore.connectionStatus }}</p> <button @click="sendTestMessage">发送测试消息</button> <div v-for="(msg, index) in wsStore.messages" :key="index"> {{ msg }} </div> </div> </template> ``` #### 四、关键特性说明 1. **响应式状态管理** 使用Pinia的响应式系统(`ref`/`reactive`)自动同步连接状态和消息数据,支持跨组件共享状态[^1] 2. **生命周期集成** 通过`onMounted`/`onUnmounted`生命周期钩子管理连接资源,避免内存泄漏[^3] 3. **类型安全** 使用TypeScript定义消息类型和状态枚举,增强代码可靠性 4. **错误处理** 通过WebSocket原生事件监听实现错误捕获和状态同步 5. **全局访问** 在任何组件中通过`useWebSocketStore()`访问同一Store实例[^1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值