Vite+Vue3项目实战:组件化开发与通信指南

一、典型的Vite+Vue3项目结构

续上文成功创建Vue3项目的脚手架,通过visual Studio Code软件打开刚刚创建的文件夹,将会看到这样一个项目结构。

使用Vite构建Vue3项目时,项目结构通常遵循一定的组织规则,以保持代码的清晰和可维护性。以下是一个典型的Vite+Vue3项目结构分析: (部分省略)

补充说明:
①'index.html': 项目的入口HTML文件,其中包含一些基本的HTML结构和用于挂载Vue应用的‘’<div  id="app"></div>‘’元素
②router': 路由配置目录,通常包含一个`index.ts`文件,用于设置路由规则
③' store': 状态管理目录,通常包含一个`index.ts`文件,用于配置Vuex或Pinia等状态管理库
 

二、单组件开发

1、概述:

单组件开发是指在前端框架Vue.js中,将一个Vue组件的模板、逻辑和样式封装在一个单独的文件中进行开发的方式。这种文件通常以'.vue'为后缀,因此也常被称为单文件组件(Single File Component,简称SFC)。

2、在单组件开发中,一个组件通常包含以下三个部分:

(1) <template>:

这部分定义了的HTML结构,也就是组件的外观。

(2) '<script>':

这部分包含了组件的JavaScript逻辑,定义了组件的行为和数据

(3)'<style>':

这部分写明了组件的样式。通过添加`scoped`属性,可以确保这些样式仅应用于当前组件,避免样式冲突。

3、代码示例:

<script setup>import { reactive } from "vue";import Header from "./components/Header.vue";import Footer from "./components/Footer.vue";import Nav from "./components/Nav.vue";const propStudent = {name: "李雷",age: 19,   }const propTeacher = reactive( {name: "韩梅梅",age: 25,   })const addTeacherAge = () => {propTeacher.age ++ console.log(`教师年龄为${propTeacher.age}`);      }
</script><template><!-- 实验一: 在父组件里,设置子组件的“字符串型”属性(进而用于父组件向子组件传递数据) --><Header propName="王五" propAge="21"  /><!-- 实验二: 在父组件里,设置子组件的“对象型”属性(进而用于父组件向子组件传递数据)--><Nav v-bind="propStudent"  /><!-- 实验二: 在父组件里,设置子组件的“响应型”属性(进而用于父组件向子组件传递数据) --><Footer v-bind="propTeacher"  /><button v-on:click="addTeacherAge">在父组件中增加教师年龄</button>
</template><style scoped></style>

三、父组件向子组件传递数据

1、概述:

父组件向子组件传递数据是组件化编程中的一种常见操作,它允许父组件将与子组件有关的信息或数据通过特定的属性(称为props)传递给子组件。这种方式保证了组件之间的数据传递是清晰定义和可维护的,同时也遵循了单向数据流的设计原则,即数据总是从父组件流向子组件,子组件不允许直接修改这些props的值,而是通过事件向上反馈信息,由父组件来决定是否及如何更新数据。

2、父组件向子组件传递数据的过程通常涉及以下步骤:

(1)定义Props: 父组件在其子组件标签上定义一些属性,并将数据作为这些属性的值传递。

(2)接收Props: 子组件在其定义中声明接收这些属性,并在其内部通过'props'对象访问这些数据。

3、示例1:

(1)父组件(App.vue)

<!-- 父组件的模板 -->
<template><div><child-component :message="helloMessage" /></div>
</template><script>
import ChildComponent from './components/Header.vue';export default {components: {ChildComponent},data() {return {helloMessage: 'Hello from Parent!'};}
}
</script>

在上述代码中,':message="helloMessage"'是一个prop绑定,它将父组件中的'helloMessage'数据传递给'ChildComponent'。

(2)子组件(Header)

<!-- 子的模板 -->
<template><div><p>{{ message }}</p></div>
</template><script>
export default {props: ['message']
}
</script>

在子组件中,'props: ['message']'声明了子组件期望从父组件接收一个名为'message'的prop,然后可以在模板中使用这个prop显示数据。 

运行结果:

4、示例2

(1)父组件(App.vue)

<!-- 父组件的模板 -->
<template><div><Header :propName="userName" :propAge="userAge" /></div>
</template>
<script setup>
import Header from './components/Header.vue';
const userName = '王晓';
const userAge = 19;
</script>

注释:

①'<template>' 标签:这是Vue组件的模板部分,它定义了组件的结构和HTML标记。 

② '<Header :propName="userName" :propAge="userAge" />':这行代码是在父组件中使用了子组件'Header'。'Header'组件通过props(属性)接收数据。这里有两个属性绑定:
  ':propName="userName"':这是一个prop绑定,'propName'是子组件'Header'中定义的一个prop名称,它被绑定到父组件中的'userName'变量。这里的`userName`的值是字符串`'王晓'`。
  ':propuserAge"':这是另一个prop绑定,'propAge'是子组件'Header'中的另一个prop名称,它被绑定到父组件中的'userAge'变量。这里的'userAge'的值是数字'19'。

 ③'import Header from'./components/Header.vue';':这行代码导入了名为'Header'的子组件,它位于当前目录下的'components'文件夹中,并且文件名为'Header.vue'。

④ 'const userName = '王晓';'和'const userAge = 19;':这两行代码定义了一个名为'userName'和'userAge'的常量,并赋值为字符串“王晓”和数字'19'。

 (2)子组件(Header.vue)

<!-- 子的模板 -->
<template><div><h3>示例2</h3>
<p>{{propName}}</p >
<p>{{propAge}}</p ></div>
</template>
<script setup>const props = defineProps(["propName", "propAge"])console.log(props);
</script>
<style scoped>div {width:25%;}
</style>

注释:

①<p>{{propName}}</p>和<p>{{propAge}}</p>是段落元素,其中的{{propName}}和{{propAge}}是一个绑定表达式,用于显示传递给组件的propName属性的值和用于显示传递给组件的propAge属性的值

②const props = defineProps(["propName", "propAge"]) : 使用defineProps定义了组件的两个属性:propName和propAge。 console.log(props): 在控制台打印出传递给组件的props对象,这将包含propName和propAge属性及其值

③这个组件在接收了propName和propAge后,会将这些值显示在页面上,并在控制台输出这些属性的当前值。 

运行结果:

控制台: 

四、子组件向父组件传递数据

1、概述:

在Vue中,子组件向父组件传递数据通常是通过自定义事件来实现的。这种机制允许子组件在其内部状态发生变化时通知父组件父组件可以监听这些事件并响应

2、实现步骤:

(1) 父组件在引用子组件的时候,绑定一个自定义事件监听器
(2)子组件通过'$emit'方法触发这个自定义事件,并将需要传递的数据作为参数传递给父组件
(3)父组件在自定义事件的监听器中接收这些数据,并可以根据这些数据更新自身的状态

3、子组件(Header.vue)

<template><div><button @click="sendMessageToParent">发送数据到父组件</button></div>
</template><script setup>
import { defineEmits } from 'vue';// 定义一个自定义事件及其可以接收的参数类型
const emit = defineEmits(['messageFromHeader']);// 方法用于在点击按钮时触发自定义事件,并传递数据
function sendMessageToParent() {const message = 'Hello from Header!';emit('messageFromHeader', message);
}
</script>

注释:

(1)'<template>'部分定义了子组件的HTML结构。包含了一个按钮'<button>',用户点击这个按钮将会发送数据到父组件。

(2)'<script setup>' 部分定义了子组件的逻辑。
  ① 引入了'defineEmits'函数,用于定义组件可以触发的事件以及这些事件可以接收的参数类型。
  ②使用'defineEmits'定义了一个名为'messageFromHeader'的自定义事件。
  ③ 定义了一个名为'sendMessageToParent'的函数,当按钮被点击时触发。函数内部创建了一个字符串'message',并通过'emit'函数触发'messageFromHeader'事件,将字符串作为参数传递给父组件。

4.父组件(App.vue) 

<template><div><Header @messageFromHeader="handleMessageFromHeader" /><p>从子组件接收到的消息:{{ message }}</p></div>
</template><script setup>
import { ref } from 'vue';
import Header from './components/Header.vue';// 用于接收子组件传递的数据
const message = ref('');// 事件处理器,用于处理子组件发来的消息
function handleMessageFromHeader(msg) {message.value = msg;
}
</script>

注释:

(1)'<template>' 部分定义了组件的HTML结构。
   - 包含了一个'<Header>'组件的标签,用于引入子组件。
   - 有一个段落'<p>'用于显示从子组件接收到的消息。
   - 使用了'{{ message }}'来绑定父组件中的'message'数据,以便动态显示。

2. '<script setup>'部分,用于定义组件的逻辑。
   - 引入了'ref'函数,它用于创建响应式数据。
   - 引入了'Header'组件,它位于'./components/Header.vue'路径下。
   - 定义了一个名为'message'的响应式数据,初始值为空字符串。
   - 定义了一个名为'handleMessageFromHeader'的事件处理器函数,它用于接收子组件传递的数据。函数将接收到的消息'msg'赋值给'message',从而更新显示的内容。

运行结果:

小结实现步骤:

1. 父组件通过('<Header>')标签引入子组件,并监听子组件发出的('messageFromHeader')事件。
2. 父组件定义了一个事件处理器('handleMessageFromHeader')来接收从子组件传递的数据,并将其存储在响应式数据('message')中。
3. 子组件定义了一个按钮,当用户点击按钮时,执行('sendMessageToParent')函数。
4. ('sendMessageToParent')函数通过('emit')函数触发('messageFromHeader')事件,并将要发送的消息作为参数传递。
5. 当父组件监听到('messageFromHeader')事件时,执行('handleMessageFromHeader')函数,更新显示从子组件接收到的消息。

 五、跨组件通信

1、概述:

在Vue框架中,跨组件通信指的是组件之间进行数据和方法传递的过程,特别是当这些组件不是简单的父子关系时。Vue中的跨组件通信是为了在组件之间共享数据和状态实现复杂的交互逻辑,从而构建更加灵活和可维护的前端应用程序。

2、常见的跨组件通信方式

(1) Props 和 Events

这是 Vue 中最常用的父子组件通信方式 。 父组件通过 props 向子组件传递数据 , 子组件则可以通过自定义事件 ( $ emit ) 向父组件发送消息 。代码示例:

①App.vue部分
<template><div><h1>父组件</h1><Headercomponents :some-prop="message" @some-event="handleEvent" /></div>
</template><script>
import Headercomponents from './components/Header.vue';export default {components: {Headercomponents},data() {return {message: 'Hello from Parent Component!'};},methods: {handleEvent(data) {console.log('Event received from Header:', data);}}
}
</script>
 ②Header.vue
<template><div><h2>子组件</h2><p>{{ someProp }}</p><button @click="sendMessageToParent">Send Message to Parent</button></div>
</template><script>
export default {props: {someProp: String},methods: {sendMessageToParent() {this.$emit('some-event', 'Hello from Header Component!');}}
}
</script>

注释:

在这个示例中:

- 父组件通过`<Headercomponents :some-prop="message" ...>`向子组件传递了一个名为`someProp`的prop,其值为`message`。
- 子组件在其`props`定义`中接收了`someProp`,并在模板中显示它。
- 子组件有一个按钮,当点击按钮时,会通过`this.$emit('some-event', 'Hello from Header Component!')`向父组件发送名为`some-event`的事件,并传递了一条消息。
- 父通过`@some-event="handleEvent"`监听这个事件,并在`handleEvent`方法中处理它,打印从子组件接收到的消息。

运行结果:

 (2) Provide / Inject  :

Vue 提供了一个 provide/inject 机制 , 允许祖先组件通过 provide 选项提供数据或方法 , 而任何后代组件都可以通过 inject 选项来接收这些数据或方法 , 无论组件层次结构有多深 。代码示例:

①App.vue部分
<script setup>import { provide, ref } from 'vue'import Header from "./components/Header.vue"/*provide用于某个上层组件将数据广播给所有下层组件。若使用了provide和inject来进行数据传递,则一般不需要再使用defineProps*///【实验1】某个上层组件向所有下层组件广播普通数据const web =  {name:"百度一下", url:"www.baidu.com"}provide("provideWeb", web)//【实验2】某个上层组件向所有下层组件广播响应式数据const user = ref(0)provide("provideUser",user)//【实验3】某个上层组件向所有下层组件广播函数const userAdd = () => {user.value++} provide("provideFuncUserAdd",userAdd)
</script><template><h3>我是上层的App组件, 用户数为: {{ user }}</h3><Header/>
</template><style scoped></style>
②Nav.vue部分
<script setup>import { inject } from 'vue'//【实验1】下层组件通过inject注入上层App组件广播的普通数据const web = inject("provideWeb")console.log("provideWeb:", web)//【实验2】下层组件通过inject注入上层App组件广播的函数const funcUserAdd = inject("provideFuncUserAdd")console.log("provideFuncUserAdd:", funcUserAdd)//【实验3】下层组件通过inject注入上层Header组件广播的普通数据const url = inject("provideUrl")console.log("provideUrl:", url)
</script><template><h3>我是底层的Nav组件</h3><button @click="funcUserAdd">添加用户</button>
</template><style scoped></style>
③ Header.vue部分
<script setup>import { provide, inject } from 'vue'import Nav from "./Nav.vue"//【实验1】下层组件通过inject注入上层App组件广播的响应式数据const user = inject("provideUser")console.log("provideUser:", user.value)//【实验2】某个上层组件向所有下层组件广播函数const str = "www.xiaomi.com"provide("provideUrl", str)
</script><template><h3>我是中间的Header组件</h3><Nav/>
</template><style scoped></style>

 六、插槽

1、概述:

在Vue中,插槽(Slots)是一种用于组合组件的机制,它允许父组件向子组件内部传递内容,而无需担心子组件的内部实现细节。简单来说,插槽就是子组件中用来嵌入父组件内容的占位符。 

2、主要有以下几种类型:

(1)匿名插槽(默认插槽):

 匿名插槽是插槽的基本形式,没有特定的名字。当父组件在子组件标签内部插入内容时,这些内容会被填充到子组件内部的匿名插槽中

(2)具名插槽:

 具名插槽具有特定的名字,父组件可以根据这个名字将内容插入到指定的位置。在一个子组件内部,可以通过`<slot>`标签定义具名插槽,并为其指定一个名字。

(3)作用域插槽:

作用域插槽允许父组件接收子组件传递的数据,并在父组件中可以使用这些数据。通常用于列表渲染等场景,使得父组件可以访问子组件的数据。

3、代码示例:

(1)匿名插槽(默认插槽):

①App.vue部分
<template><div><Card><p>这是自定义的内容(会被默认插入默认插槽)</p><!-- 【实验1】把代码片段插入默认插槽,可以不使用<template>标签封装 --><h3>插入默认插槽的三级标题</h3></Card></div>
</template><script setup>import Card from './components/Card.vue';
</script>
② Card.vue 部分
<template><div><!-- 定义一个默认插槽(不需要命名) --><div class="default-slot"><slot></slot></div></div>
</template><script setup></script><style>.default-slot{background-color: antiquewhite;}
</style>

运行结果:

(2)具名插槽:

①App.vue部分
<template><div><Card><!-- 【实验】把代码片段插入具名插槽,必须使用<template>标签封装,并且用v-slot:指定插槽的名字,v-slot:简写形式为# --><template v-slot:footer><button @click="handleClick">我是插入具名插槽的按钮</button></template></Card></div>
</template><script setup>import Card from './components/Card.vue';const handleClick = () => {alert('插入具名插槽的按钮被点击了!');};
</script>
② Card.vue 部分
<template><div><!-- 定义一个具名插槽(需要通过name命名,最常用) --> <div class="named-slot"><slot name="footer"></slot></div> </div>
</template><script setup></script><style>.named-slot{background-color: gainsboro;}
</style>

运行结果:

(3)作用域插槽:

①App.vue部分
<template><div><Card><!-- 【实验】作用域插槽:子组件将url和title数据配置到 name="user" 的插槽中,当父组件将某个片段插入该插槽时,便可通过 v-slot:user="data" (data是随便取的名字) 来接收这些数据--><template v-slot:user="data">  子组件通过作用域插槽传来的数据: {{ data.url }} , {{ data.title }}</template>  </Card></div>
</template><script setup>import Card from './components/Card.vue';const handleClick = () => {alert('插入具名插槽的按钮被点击了!');};
</script>
② Card.vue 部分
<template><div><!-- 定义一个作用域插槽(需要通过name命名,所以它也是具名插槽的一种,但要求在插槽里配置一些数据) --><div class="scoped-slot"><slot name="user" url="www.baidu.com" title="百度一下"></slot></div></div>
</template><script setup></script><style>.scoped-slot{background-color: pink;}
</style>

运行结果;

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

汽车免拆案例 | 2007款宝马650i车发动机偶尔无法起动

故障现象 一辆2007款宝马650i车&#xff0c;搭载N62B48B发动机&#xff0c;累计行驶里程约为26万km。车主反映&#xff0c;发动机偶尔无法起动&#xff0c;故障频率较低&#xff0c;十几天出现1 次&#xff0c;且故障出现时起动机不工作。 故障诊断  接车后试车&#xff0c;…

团队管理中如何做好目标管理

团队管理中的目标管理是确保团队高效运行的核心要素之一。 在目标管理中&#xff0c;清晰的目标设定、合理的资源分配、实时的跟踪与反馈机制是成功的关键。首先&#xff0c;设定SMART目标&#xff08;具体、可衡量、可达成、相关性强、时间限定&#xff09;能够有效聚焦团队的…

【力扣热题100】—— Day4.反转链表

你不会永远顺遂&#xff0c;更不会一直年轻&#xff0c;你太安静了&#xff0c;是时候出发了 —— 24.12.2 206. 反转链表 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&…

【AWS re:Invent 2024】一文了解EKS新功能:Amazon EKS Auto Mode

文章目录 一、为什么要使用 Amazon EKS Auto Mode&#xff1f;二、Amazon EKS自动模式特性2.1 持续优化计算成本2.2 迁移集群操作2.3 EKS 自动模式的高级功能 三、EKS Auto 集群快速创建集群配置四、查看来自 API 服务器的指标五、EKS 相关角色权限设置六、参考链接 一、为什么…

记事本建java及java命名规范

1.桌面开发&#xff1a;c# 2. 记事本建java&#xff1a; 以class的名称(类名)为名&#xff0c;名称.java 编译jdk&#xff1a;javac 名称.java 调动运行jre : java 名称 查看名称.java里面的内容&#xff1a;cat 名称.java java 的命名规范 大驼峰&#xff08;每个单词首…

过程管理系统(源码+文档+部署+讲解)

本文将深入解析“过程管理系统”的项目&#xff0c;探究其架构、功能以及技术栈&#xff0c;并分享获取完整源码的途径。 系统概述 过程管理系统是一款专为工业设计的综合管理平台&#xff0c;旨在通过集成各种管理流程和功能模块来提高管理效率和安全性。系统提供了从登录系…

期权懂|个股期权交割操作流程是什么样的?

期权小懂每日分享期权知识&#xff0c;帮助期权新手及时有效地掌握即市趋势与新资讯&#xff01; 个股期权交割操作流程是什么样的&#xff1f; 一、行权申报&#xff1a; 期权买方在行权日通过其经纪商提交行权指令&#xff0c;表明其决定行使期权权利。 二、行权匹配&#xf…

智能仓储:入库业务流程介绍

01 入库流程 入库业务流程&#xff0c;常见过程是这样的&#xff1a; 创建PO单 > 创建到货清单 > 核对货物 > 入库质检 > 货物贴标签 > 上架 > 库存同步 1、创建PO单 po单指的是的采购订单&#xff0c;比如采购了一车货品&#xff0c;这车的货品可以理解…

MySQL并发控制(一):幻读

假设有如下表结构&#xff1a; CREATE TABLE t(id int(11) NOT NULL,c int(11) DEFAULT NULL,d int(11) DEFAULT NULL,PRIMARY KEY (id),KEY c (c) ) ENGINEInnoDB;insert into t values(0,0,0),(5,5,5),(10,10,10),(15,15,15),(20,20,20),(25,25,25); 问&#xff1a;如果执行…

Ubuntu22.04中mysql8 rpm安装

1、安装依赖 sudo apt update sudo apt -y dist-upgrade sudo apt -y install vim net-tools wget gcc make cmake lrzsz sudo apt -y install libmecab2 libjson-perl 2、下载rpm文件 https://dev.mysql.com/downloads/mysql/ https://cdn.mysql.com//Downloads/MySQL-8.0/m…

Intel 性能分析“全家桶” For HPC(一)

本系列是对于HPC应用性能分析涉及的主要方法论及Intel主流工具分享。理解这些方法论将有助于对性能分析结果的理解。同时方法论也可以推广到其他的硬件平台的分析上。除此之外后面也将介绍如何用Vtune, Advisor以及ITAC进行性能分析&#xff0c;以及在性能分析过程中这三种性能…

Qwen1.8B大模型微调流程

提示&#xff1a;本篇笔记是在微调大模型为法律相关模型的教程下记录的&#xff0c;参考的讲解视频在B站上&#xff0c;一搜微调大模型为法律大模型就有很多视频。 文章目录 1. 数据集1.1 数据下载1.2 数据格式转换 2. 模型训练2.1 安装依赖2.2 模型训练 3. 模型推理3.1 LoRA模…

第十六章 使用 iSCSI 服务部署网络存储

1. iSCSI 技术介绍 硬盘是计算机硬件设备中重要的组成部分之一&#xff0c;硬盘存储设备读写速度的快慢也会对服务器的整体性能造成影响。硬盘存储结构、RAID 磁盘阵列技术以及LVM 技术等都是用于存储设备的技术&#xff0c;尽管这些技术有软件层面和硬件层面之分&#xff0c…

【js面试题】JavaScript 中箭头函数与普通函数的深度剖析

在 JavaScript 编程的世界里&#xff0c;函数是极为重要的组成部分。而随着 ES6 的出现&#xff0c;箭头函数成为了 JavaScript 函数家族中的新成员。它与传统的普通函数有着诸多的不同之处&#xff0c;这些差异深刻地影响着我们编写代码的方式以及代码的执行逻辑。本文将对 Ja…

【漫话机器学习系列】Adaboost算法

Adaboost&#xff08;Adaptive Boosting&#xff09;是一种经典的集成学习方法&#xff0c;主要思想是通过将多个弱学习器&#xff08;通常是简单模型&#xff0c;如决策树桩&#xff09;加权组合&#xff0c;来提升整体模型的预测能力。Adaboost 是一种自适应的学习方法&#…

SQL靶场第四关

sql靶场第四关攻略 输入?id1页面正常 输入?id1发现页面也正常 输入?id1"&#xff0c;页面异常&#xff0c;说明存在sql报错注入 在输入?id1" --页面还是报错 1.判断闭合点 我们需要找到闭合点&#xff0c;尝试在双引号后面加个) 输入?id1") --我们发现…

Trunk链路操作题

Trunk链路操作题 论证&#xff1a;

Alogrithm:三色棋

1. 说明 三色旗的问题最早由 E.W.Diikstra 所提出&#xff0c;他所使用的用语为 Dutch Nation Flag&#xff08;Dijkstra 为荷兰人&#xff09;&#xff0c;而多数的作者则使用 Three-Color Flag 来称之。 假设有一条绳子&#xff0c;上面有红、白、蓝三种颜色的旗子&#xff0…

需要排序的子数组

题目描述 给定一个无序数组arr&#xff0c;求出需要排序的最短子数组长度 要求&#xff1a;O(N) 如输入&#xff1a;arr{2,3,7,5,4,6}&#xff0c;返回4&#xff0c;因为只有{7,5,4,6}需要排序。 分析 以{2,3,7,5,4,6,8,9}为例&#xff1a; 前端小于最小波谷&#xff08;3…

Python酷库之旅-第三方库Pandas(154)

目录 一、用法精讲 701、pandas.Timestamp.utcnow方法 701-1、语法 701-2、参数 701-3、功能 701-4、返回值 701-5、说明 701-6、用法 701-6-1、数据准备 701-6-2、代码示例 701-6-3、结果输出 702、pandas.Timestamp.utcoffset方法 702-1、语法 702-2、参数 70…