饮冰十年-人工智能-Vue3-67-组件间数据交互

news/2024/11/13 14:07:26/文章来源:https://www.cnblogs.com/YK2012/p/18333300

上一篇:饮冰三年-人工智能-Vue-66 Vue组件化

  很久以前我对Vue2的组件间数据交互做过学习,兜兜转转再用Vue已经是Vue3版本。

Vue3组件间数据交互

1、准备工作

  环境准备

    使用 Vite 创建一个新的 Vue 3 项目

  功能介绍

    该功能由APPVue+4个组件组成  
  •     头部组件(MyHeader)

        主要是一个input框,用于收集用户输入内容,

        当用户输入完成,并按下enter键后,将数据添加到 MyList 列表组件中

  •     列表组件(MyList)
        主要用于展示待办项
  •     任务组件(MyItem)
        包括 左边勾选框、中间任务内容、右边删除按钮
        点击勾选框,标记任务是否完成;点击删除按钮,删除任务项
  •     底部组件(MyFooter)
        用于显示待办事项列表的统计信息,并提供全选和清除已完成任务的功能。

2、props emit 版本

<template><div class="todo-header"><input type="text" placeholder="请输入你的任务名称,按回车键确认" @keyup.enter="add" /></div>
</template><script setup>
// 引入nanoid
import { nanoid } from "nanoid";
// 定义 emits
const emit = defineEmits(['addTodo'])
const add = (e) => {// 判断用户是否输入了内容if (e.target.value.trim().length === 0) {alert("输入的内容不能为空");return;}// 将用户的输入,包装成为一个todo对象const todoObj = {id: nanoid(),title: e.target.value,done: false,};// 将todo对象传递给App组件emit('addTodo', todoObj)// 清空用户的输入e.target.value = "";
}</script><style scoped>
/*header*/
.todo-header input {width: 560px;height: 28px;font-size: 14px;border: 1px solid #ccc;border-radius: 4px;padding: 4px 7px;
}.todo-header input:focus {outline: none;border-color: rgba(82, 168, 236, 0.8);box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);
}
</style>
MyHeader

源码解析

  emit 是一个用于触发事件的方法,允许子组件向父组件发送消息。这是 Vue 的一种组件通信机制,通常用于子组件向父组件传递数据或通知父组件发生了某个事件。

作用和用法

  • 事件传递: 当子组件需要通知父组件某个事件发生时,可以使用 emit 方法。例如,当用户在输入框中输入任务并按下回车键时,你想要将这个任务传递给父组件。

  • 自定义事件: emit 允许你创建自定义事件,父组件可以通过监听这些事件来响应子组件的行为。例如,在示例中,子组件使用 emit('addTodo', todoObj) 来触发名为 addTodo 的事件,并将 todoObj 作为参数传递给父组件。

如何在父组件中监听事件

  • 在父组件中,你可以通过 @ 符号来监听子组件发出的事件

  • <MyHeader @addTodo="addTodo"></MyHeader>

<template><ul class="todo-main"><!-- v-for 指令用于遍历 todos 数组,生成多个 MyItem 组件。:todo="todoObj": 将当前的 todoObj 传递给 MyItem 组件的 todo prop。:checkTodo="checkTodo" 和 :deleteTodo="deleteTodo": 将父组件的方法 checkTodo 和 deleteTodo 作为 prop 传递给 MyItem 组件,允许子组件在适当的时候调用这些方法 --><MyItem v-for="todoObj in todos" :key="todoObj.id" :todo="todoObj" :checkTodo="checkTodo" :deleteTodo="deleteTodo"></MyItem></ul>
</template><script setup>import MyItem from './MyItem.vue';
// defineProps 是一个 Vue 3 的编译宏,用于在 <script setup> 中定义组件接收的 props。
const props = defineProps({todos: Array, // todos: 一个数组,用于存储待办事项列表。checkTodo: Function, // checkTodo: 一个函数,用于处理勾选或取消勾选待办事项的操作。deleteTodo: Function // deleteTodo: 一个函数,用于处理删除待办事项的操作。
});
</script><style scoped>
/*main*/
.todo-main {margin-left: 0px;border: 1px solid #ddd;border-radius: 2px;padding: 0px;
}.todo-empty {height: 40px;line-height: 40px;border: 1px solid #ddd;border-radius: 2px;padding-left: 5px;margin-top: 10px;
}
</style>
MyList.Vue

源码解析

  • 父组件通过 props 向子组件传递数据和方法。

作用和用法

  • 父组件传:父组件 APPVue 通过 : 符号绑定 todos、checkTodo 和 deleteTodo到子组件 MyList 组件。 Vue 会将这些数据和方法作为 props 传递给 MyList 组件。
<MyList :todos="todos" :checkTodo="checkTodo" :deleteTodo="deleteTodo"></MyList>
  • 子组件接:在 MyList.vue 组件中,使用 defineProps 来定义和接收这些 props:

<template><li><label><input type="checkbox" :checked="todo.done" @change="handleCheck(todo.id)" /><span>{{ todo.title }}</span></label><button class="btn btn-danger" @click="handleTodo(todo.id)">删除</button></li>
</template><script setup>// 接收 props
const props = defineProps({todo: Object,checkTodo: Function,deleteTodo: Function
})
// 处理勾选事件
const handleCheck = (id) => {// 通知App组件,修改todo的done状态
  props.checkTodo(id)
}// 处理删除事件
const handleTodo = (id) => {if (window.confirm('确定删除吗?')) {props.deleteTodo(id)}
}     
</script><style scoped>
/*item*/
li {list-style: none;height: 36px;line-height: 36px;padding: 0 5px;border-bottom: 1px solid #ddd;
}li label {float: left;cursor: pointer;
}li label li input {vertical-align: middle;margin-right: 6px;position: relative;top: -1px;
}li button {float: right;display: none;margin-top: 3px;
}li:before {content: initial;
}li:last-child {border-bottom: none;
}li:hover {background-color: #ddd;
}li:hover button {display: block;
}
</style>
MyItem.vue

源码解析

  有了上面的基础,这个比较好理解,父组件通过 props 向子组件传递数据和方法。不过不同的是,子组件在这里调用了props传的方法。

// 处理勾选事件
const handleCheck = (id) => {// 通知App组件,修改todo的done状态
  props.checkTodo(id)
}// 处理删除事件
const handleTodo = (id) => {if (window.confirm('确定删除吗?')) {props.deleteTodo(id)}
}  
<template><div class="todo-footer" v-show="total"><label><input type="checkbox" :checked="isAll" @change="checkAll" /></label><span> <span>已完成{{ doneTotal }}</span> / 全部{{ todos.length }} </span><button class="btn btn-danger" @click="clearAll">清除已完成任务</button></div>
</template><script setup>
import { computed} from 'vue'// 接收 props
const props = defineProps({todos: {type: Array,required: true}
});
// 定义 emits
const emit = defineEmits(['checkAllTodo', 'clearAllTodo']);// 计算属性
const total = computed(() => props.todos.length)const doneTotal = computed(() => {return props.todos.reduce((pre, todo) => pre + (todo.done ? 1 : 0), 0);
})const isAll = computed(() => doneTotal.value === total.value && total.value > 0)const checkAll = (e) => {emit('checkAllTodo', e.target.checked);
}const clearAll = () => {emit('clearAllTodo')
}</script><style scoped>
/*footer*/
.todo-footer {height: 40px;line-height: 40px;padding-left: 6px;margin-top: 5px;
}.todo-footer label {display: inline-block;margin-right: 20px;cursor: pointer;
}.todo-footer label input {position: relative;top: -1px;vertical-align: middle;margin-right: 5px;
}.todo-footer button {float: right;margin-top: 5px;
}
</style>
MyFooter.vue

源码解析

  • 定义 props:

    • props 接收一个 todos 数组,表示所有的待办事项。

    • defineProps的时候可以为属性设置必填项

  • 定义 emits:
    • emit 用于向父组件发送事件。定义了两个事件:checkAllTodo 和 clearAllTodo。

    • checkAll: 当复选框状态改变时,触发 checkAllTodo 事件,并传递复选框的勾选状态。

    • clearAll: 当点击清除按钮时,触发 clearAllTodo 事件。

<script setup>
import { ref,  watch } from 'vue'
import MyHeader from './components/MyHeader.vue'
import MyList from './components/MyList .vue'
import MyFooter from './components/MyFooter.vue'
// 初始化 todos
const todos = ref(JSON.parse(localStorage.getItem('todos')) || [])
// 添加todo
const addTodo = (todo) => {todos.value.unshift(todo);
};// 勾选或者取消勾选一个todo
const checkTodo = (id) => {todos.value.forEach((todo) => {if (todo.id === id) {todo.done = !todo.done;}});
};
// 删除一个todo
const deleteTodo = (id) => {todos.value = todos.value.filter((todo) => todo.id !== id);
};// 全选或者全不选
const checkAllTodo = (done) => {todos.value.forEach(todo => todo.done = done)
};// 清除所有已经完成的todo
const clearAllTodo = () => {todos.value = todos.value.filter((todo) => !todo.done)
}
// 监听 todos 的变化并同步到 localStorage
watch(todos,(newValue) => {localStorage.setItem('todos', JSON.stringify(newValue));},{ deep: true }
);
</script><template><div id="root"><div class="todo-container"><div class="todo-wrap"><!-- 在父组件中,你可以通过 @ 符号来监听子组件发出的事件 --><MyHeader @addTodo="addTodo"></MyHeader><MyList :todos="todos" :checkTodo="checkTodo" :deleteTodo="deleteTodo"></MyList><MyFooter :todos="todos" @checkAllTodo="checkAllTodo" @clearAllTodo="clearAllTodo"></MyFooter></div></div></div>
</template><style scoped>
.logo {height: 6em;padding: 1.5em;will-change: filter;transition: filter 300ms;
}.logo:hover {filter: drop-shadow(0 0 2em #646cffaa);
}.logo.vue:hover {filter: drop-shadow(0 0 2em #42b883aa);
}
</style>
APP.vue
这段源码大家可自行理解下。

总结

数据流: Vue 中的 props 实现了单向数据流,父组件通过 props 将数据和方法传递给子组件,子组件通过 emit 发送事件回父组件
理解子组件中使用 emit 和直接通过 props 调用父组件方法的差异,可以通过一个简单的生活类比来解释。
类比:点餐和送餐
假设你在餐厅工作,负责点餐和送餐。餐厅有两个主要角色:服务员(父组件)和厨房(子组件)。
1. 使用 emit(服务员通知厨房)
    服务员(父组件):
        服务员记录顾客的点单(父组件的方法)。
        服务员将点单传递给厨房(通过 emit 将事件传递给父组件)。
    厨房(子组件):
        厨房收到点单后,准备菜肴(子组件执行操作)。
        厨房准备好菜肴后,通过铃声(emit 事件)通知服务员。
场景:
    顾客点了一道菜,服务员记录并传递给厨房。
    厨房准备好菜肴后,通过铃声通知服务员。
    服务员听到铃声后,将菜肴送到顾客桌上。
解释:
    服务员通过监听厨房的铃声(emit 事件)来知道菜肴已准备好,并将菜送到顾客桌上。
    服务员没有直接去厨房检查菜肴是否准备好(不直接调用父组件的方法)。
2. 直接通过 props 调用(服务员自己做菜)
    服务员(父组件):
        服务员记录顾客的点单(父组件的方法)。
        服务员直接自己准备菜肴(通过 props 直接调用父组件的方法)。
    厨房(子组件):
        厨房只是一个摆设(子组件只是传递数据),所有操作都由服务员完成。
场景:
    顾客点了一道菜,服务员记录并自己准备菜肴。
    服务员准备好菜肴后,直接将菜肴送到顾客桌上。
解释:
    服务员没有依赖厨房的通知(emit 事件),而是自己完成所有步骤。
    服务员直接根据点单准备菜肴(直接调用父组件的方法)。
对比
    emit:像厨房通过铃声(事件)通知服务员菜肴已准备好。厨房不直接送菜,通知服务员由服务员完成最终的送菜动作。适用于子组件只需通知父组件某个事件发生,而不需要知道具体如何处理。
    直接调用 props 方法:像服务员自己准备菜肴,不依赖厨房的通知。服务员直接完成点单记录和菜肴准备的所有步骤。适用于子组件需要直接调用父组件的方法来完成某些操作。
 

2、全局事件总线版本

 
    全局事件总线(Global Event Bus)全局事件总线是一个可以在应用的任何部分触发和监听事件的机制。
    适用场景
        它可以简化父子组件之间的通信,特别是当组件层级很深或者组件之间没有直接的父子关系时。
    使用方法
        在 Vue 3 中,不再推荐使用类似 Vue 2 中的 $bus 方式来创建全局事件总线
        在 Vue 3 中,我们可以使用 mitt 这个库来创建一个简单的全局事件总线。mitt 是一个轻量级的事件总线库
安装
npm install mitt

  

npm install mitt

  


    添加时间总线eventBus.js

2、发布订阅模式


    在 Vue 3 中,全局事件总线和发布-订阅模式是相似的概念,实际上事件总线就是一种实现发布-订阅模式的方式。
    发布-订阅模式:
        这是一种设计模式,允许对象之间的解耦。发布者(发布事件的组件)和订阅者(监听事件的组件)之间不直接交互,而是通过一个中介(事件总线)来通信。
        发布者发布消息,订阅者通过监听特定的事件来响应这些消息。
    事件总线:
        事件总线是实现发布-订阅模式的一种具体方式。在 Vue 中,事件总线通常是一个独立的对象,它提供了 on(订阅事件)、emit(发布事件)和 off(取消订阅)等方法。
        使用事件总线,组件可以轻松地发布和订阅事件,而无需了解彼此的存在。
    总结
        在 Vue 3 中,通过创建一个事件总线(如使用 mitt 库)实现组件之间的消息传递,实际上就是在应用发布-订阅模式。这使得组件之间的通信更加灵活和解耦,便于维护和扩展。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/775750.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[米联客-安路飞龙DR1-FPSOC] FPGA基础篇连载-26 RS485串口程序收发环路设计

软件版本:Anlogic -TD5.9.1-DR1_ES1.1 操作系统:WIN10 64bit 硬件平台:适用安路(Anlogic)FPGA 实验平台:米联客-MLK-L1-CZ06-DR1M90G开发板 板卡获取平台:https://milianke.tmall.com/ 登录"米联客"FPGA社区 http://www.uisrc.com 视频课程、答疑解惑! 1概述在…

[米联客-安路飞龙DR1-FPSOC] FPGA基础篇连载-25 ADC模块FEP-DAQ9248采集显示波形方案

软件版本:Anlogic -TD5.9.1-DR1_ES1.1 操作系统:WIN10 64bit 硬件平台:适用安路(Anlogic)FPGA 实验平台:米联客-MLK-L1-CZ06-DR1M90G开发板 板卡获取平台:https://milianke.tmall.com/ 登录"米联客"FPGA社区 http://www.uisrc.com 视频课程、答疑解惑! 1 概述本…

UE4 C++ 多人游戏中的简单聊天窗口

本质 不管是客户端还是服务器在输入文字后,按下回车发送,将触发RPC调用。然后通过RPC将发送者,输入文本等信息,传入到服务器,然后通过多播RPC传播到所有客户端的聊天框。 UI UI利用三个组件 ScrollBox 用于在服务器以及每个客户端上显示消息的载体 TextBlock 本地将信息通…

[米联客-安路飞龙DR1-FPSOC] FPGA基础篇连载-24 基于FPGA简易示波器显示驱动设计

软件版本:Anlogic -TD5.9.1-DR1_ES1.1 操作系统:WIN10 64bit 硬件平台:适用安路(Anlogic)FPGA 实验平台:米联客-MLK-L1-CZ06-DR1M90G开发板 板卡获取平台:https://milianke.tmall.com/ 登录"米联客"FPGA社区 http://www.uisrc.com 视频课程、答疑解惑! 1 概述F…

[米联客-安路飞龙DR1-FPSOC] FPGA基础篇连载-23 RGB转HDMI显示方案

软件版本:Anlogic -TD5.9.1-DR1_ES1.1 操作系统:WIN10 64bit 硬件平台:适用安路(Anlogic)FPGA 实验平台:米联客-MLK-L1-CZ06-DR1M90G开发板 板卡获取平台:https://milianke.tmall.com/ 登录"米联客"FPGA社区 http://www.uisrc.com 视频课程、答疑解惑! 1概述本…

VU13载板,2个FMC和3个FMC+接口,一个QSFP28(100G)光纤口,一个千兆网接口

VU13载板,2个FMC和3个FMC+接口,一个QSFP28(100G)光纤口,一个千兆网接口,8GB内存。基于XILINX Virtex UltraScale+系列,芯片型号为XCVU13P-2FHGB2104I的一款高性能FMC+载板。该板卡集成了3个FMC+(Vita 57.4)和2个FMC(Vita 57.1)连接器。可以与各种FMC子卡进行完美匹配,为用…

无影云电脑设置开机启动项

在msconfig及任务管理器的选项卡中,不可设置启动项。可通过以下步骤设置。Windows设置 应用 启动 打开或关闭相应启动项版权木有,侵权不究,欢迎转载

企业数字化转型的必备钥匙:数据思维|专题报告集

原文链接:https://tecdat.cn/?p=37165 本质上来讲,企业数字化转型,不仅是技术方面的升级,更是企业文化、思维方式的转变。那么,企业数字化转型究竟需要什么样的思维方式? 企业数字化转型,需要什么样的思维方式? 不知道你有没有过这样的感觉:不知道从什么时候开始,和…

【PHP系列】内存马(一)不死马

实验环境工具 phpstudy一、内存马概念 内存马是无文件攻击的一种常用手段,利用中间件的进程执行某些恶意代码。首先要讲的是PHP不死马,实质上就是直接用代码弄一个死循环,强占一个 PHP 进程,并不间断的写一个PHP shell,或者执行一段代码 二、不死马剖析 test.php: <?p…

[米联客-安路飞龙DR1-FPSOC] FPGA基础篇连载-21 VTC视频时序控制器设计

软件版本:Anlogic -TD5.9.1-DR1_ES1.1 操作系统:WIN10 64bit 硬件平台:适用安路(Anlogic)FPGA 实验平台:米联客-MLK-L1-CZ06-DR1M90G开发板 板卡获取平台:https://milianke.tmall.com/ 登录"米联客"FPGA社区 http://www.uisrc.com 视频课程、答疑解惑! 1概述Vi…

【视频讲解】Python用LSTM、Wavenet神经网络、LightGBM预测股价

原文链接:https://tecdat.cn/?p=37184 原文出处:拓端数据部落公众号 分析师:Yuyan Ye 在金融科技的浪潮中,量化投资方法以其数据驱动和模型导向的特性,日益成为资本市场分析的重要工具。特别是,长短期记忆网络(LSTM)、Wavenet以及LightGBM等先进的机器学习算法,因其…

easyFrida指南

easyFrida使用python运行 python easyFrida.py -h usage: easyFrida.py [-h] [-R] [-S S] [-f F | -p P] [--className CLASSNAME] [--plugin PLUGIN] [-l]_____ _ ____ __ _ ___ _ _| ___| __(_) __| | __ _/ _ \/ _` / __| | | | |_ | __| |/ _` |/ _` || __/ (…