【C语言】实现通讯录管理系统

大家好,我是苏貝,本篇博客带大家实现通讯录,如果你觉得我写的还不错的话,可以给我一个赞👍吗,感谢❤️
在这里插入图片描述


目录

  • 一. 前言
  • 二. 通讯录的实现
    • 2.1 写出基本框架
    • 2.2 制作menu菜单
    • 2.3 创建联系人和通讯录结构体
    • 2.4 定义通讯录并初始化
    • 2.5 使用枚举常量优化代码
    • 2.6 增加联系人信息
    • 2.7 删除联系人信息
    • 2.8 查找联系人信息
    • 2.9 修改联系人信息
    • 2.10 打印所有联系人信息
    • 2.11 以名字排序所有联系人
  • 三. 模块化代码实现
    • 3.1 test.c
    • 3.2 contact.h
    • 3.3 contact.c
    • 3.4 结果演示
  • 四. 存在的问题

一. 前言

本文将使用C语言来实现通讯录管理系统,该通讯录包括若干联系人,和每个联系人的姓名、年龄、性别、电话、地址。此通讯录的功能包括:增加联系人信息,删除联系人信息,查找联系人信息,修改联系人信息,显示所有联系人信息,根据名字顺序给所有联系人信息排序

二. 通讯录的实现

首先,我们建立1个contact.h文件,即一个头文件,用来声明。建立1个test.c文件,用来测试代码。再建立1个contact.c文件,用来写实现上述6个功能的代码

2.1 写出基本框架

下面的代码就是通讯录的基本框架,很多程序的基本框架和下面代码相似,用do-while循环来决定实现什么功能。变量input作为循环的判断条件,如果选择0,则退出循环,选择1~6之间的数则执行对应的功能,选择其它数则提示输入错误,再进入循环

int main()
{int input = 0;do{menu();printf("请选择:");scanf("%d", input);switch (input){case 1:break;case 2:break;case 3:break;case 4:break;case 5:break;case 6:break;case 0:printf("退出程序\n");break;default:printf("选择错误,请重新输入\n");break;}} while (input);return 0;
}

2.2 制作menu菜单

基本框架中有menu菜单,那让我们来了解一下如何写menu菜单,即一个名为menu的函数。菜单界面就像餐厅里服务员递给你的菜单,根据菜单里的内容进行选择。选择1~6,实现特定功能;选择0,退出程序

void menu()
{printf("-----------------------------------\n");printf("***********************************\n");printf("******  1.Add       2.Del    ******\n");printf("******  3.Select    4.Modify ******\n");printf("******  5.Show      6.Sort   ******\n");printf("******  0.exit               ******\n");printf("***********************************\n");printf("-----------------------------------\n");
}

2.3 创建联系人和通讯录结构体

因为联系人信息包括姓名、年龄、性别、电话、地址,而且它们的类型和所占大小不同,所以我们想到构建一个联系人结构体,为了书写分别,我们将struct PeoInfo重命名为PeoInfo。

typedef struct PeoInfo
{char name[20];int age;char gender[5];char tele[12];char addr[30];
}PeoInfo;

现在我们将上面字符数组都确定了最大元素个数,那如果有一天我们发现有一个人的地址不止30个字节怎么办呢?我们接下来的代码里面也可能有addr[30],所以以后修改起来不太方便。因此,不妨我们用define定义一些标识符常量,之后敲代码时需要用到字符大小就写标识符常量而非一个数字,这样可以方便以后修改数组的大小

#define NAME_MAX 20
#define GENDER_MAX 5
#define TELE_MAX 30
#define ADDR_MAX 30typedef struct PeoInfo
{char name[NAME_MAX];int age;char gender[GENDER_MAX];char tele[TELE_MAX];char addr[ADDR_MAX];
}PeoInfo;

如果我们想存储若干个联系人的信息,那我们就要定义一个数组,数组有若干个元素,元素的类型是PeoInfo,很自然的,我们用define定义的标识符常量来表示数组的最大元素个数。通讯录除了要有所有联系人信息外,也应该可以告诉我们有多少个联系人,所以通讯录里要有2个东西,一个是若干联系人信息,一个是联系人的个数,它们的类型不同,所以用结构体表示通讯录

#define MAX 1000
typedef struct Contact
{PeoInfo data[MAX];int sz;
}Contact;

2.3 的都是声明语句,所以都放在contact.h文件中


2.4 定义通讯录并初始化

通讯录的定义简简单单,不用多说

	Contact con;

我们来想想如何将它初始化。(如果不初始化,那么con里面的内容都是随机值)
在test.c文件中调用初始化函数,在contact.h中声明初始化函数,在contact.c文件中定义函数。结构体传参时最好是传址而非传值,且初始化需要改变结构体的内容,所以只能传址

	InitContact(&con);

初始化就是将变量con的元素sz的值赋值为0,并且data数组里面的元素也都是0。sz不用多说,将data数组里面的元素全变为0,只需应用我们之前介绍过的memset函数了解memset函数

void InitContact(Contact* pc)
{assert(pc);//断言pc->sz = 0;memset(pc->data, 0, sizeof(pc->data));
}

2.5 使用枚举常量优化代码

如果不让你看菜单,你能知道上面基本框架的switch语句中的case 1~6分别是什么意思吗?如果你和我一样不太记得的话,那我们可以使用枚举常量来帮助我们识别。枚举常量如果我们自己不去主动赋值的话,它们的值会从0开始,依次+1,所以EXIT的值为0,ADD的值为1……

enum Option
{EXIT,//0ADD,DEL,SELECT,MODIFY,SHOW,SORT
};

所以switch语句中的case语句后面的值可以用带提示的枚举常量代替

switch (input){case ADD:break;case DEL:break;case SELECT:break;case MODIFY:break;case SHOW:break;case SORT:break;case EXIT:printf("退出程序\n");break;default:printf("选择错误,请重新选择\n");break;}

2.6 增加联系人信息

在test.c文件中调用函数

case ADD:AddContact(&con);break;

在contact.c文件中定义函数。先判断通讯录是否满了,若没满则输入联系人信息,最好一定要记得sz++。注意:输入年龄的scanf语句中,记得要&

void AddContact(Contact* pc)
{assert(pc);if (pc->sz == MAX){printf("通讯录已满,增加失败\n");return;}printf("请输入名字:");scanf("%s",pc->data[pc->sz].name );printf("请输入年龄:");scanf("%d", &(pc->data[pc->sz].age));printf("请输入性别:");scanf("%s", pc->data[pc->sz].gender);printf("请输入电话:");scanf("%s", pc->data[pc->sz].tele);printf("请输入地址:");scanf("%s", pc->data[pc->sz].addr);pc->sz++;printf("增加成功\n");
}

2.7 删除联系人信息

在test.c文件中调用函数

case DEL:DelContact(&con);break;

在contact.c文件中定义函数。先判断通讯录是否为空,不为空时,输入要删除的人的姓名,在通过for循环搜索是否有该姓名的联系人,因为除了删除联系人信息功能需要搜索以外,查找和修改联系人信息也需要通过for循环搜索是否有该姓名的联系人,所以不妨将其封装成一个函数。若没有找到这个姓名的联系人,返回-1,否则返回该姓名的下标。
找到该姓名的联系人以后做删除操作,删除操作只需要让下标后面的元素依次向前进一位,覆盖掉下标的位置即可。所以循环的结束条件是i < pc->sz - 1,不要搞错。覆盖时只需要pc->data[i] = pc->data[i + 1];因为如果结构体的类型完全相同,那就可以整体赋值。最后sz–。可能有人注意到了,这个删除操作不能删除最后一个元素,是的,但没有关系,因为我们的sz–了,所以之后的遍历中不会再遍历原本的最后一个元素

int FindOfName(char* name, Contact* pc)
{assert(name && pc);int i = 0;for (i = 0; i < pc->sz; i++){if (0 == strcmp(name, (pc->data[i].name)))return i;}return -1;
}void DelContact(Contact* pc)
{assert(pc);char name[NAME_MAX] = { 0 };if (pc->sz == 0){printf("通讯录为空,删除失败\n");return;}printf("请输入要删除的人的名字:");scanf("%s", name);int ret = FindOfName(name, pc);if (ret == -1){printf("找不到要删除的人\n");return;}int i = 0;for (i = ret; i < pc->sz - 1; i++){pc->data[i] = pc->data[i + 1];}pc->sz--;printf("删除成功\n");
}

2.8 查找联系人信息

查找联系人信息同样需要搜索函数FindOfName(name, pc);,如果要查找的人存在,那么会返回它的下标,再通过下标对这个人信息进行打印。为了直观的看出各个信息是属于哪一类的,我们可以在打印前打印提示信息,注意:年龄是%-5s,后面打印信息时是%-5d

void SelectContact(Contact* pc)
{char name[NAME_MAX] = { 0 };printf("请输入要查找的人的名字:");scanf("%s", name);int ret = FindOfName(name, pc);if (ret == -1){printf("找不到要查找的人\n");return;}printf("%-20s%-5s%-5s%-30s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");printf("%-20s%-5d%-5s%-30s%-30s\n", pc->data[ret].name, pc->data[ret].age,pc->data[ret].gender, pc->data[ret].tele, pc->data[ret].addr);
}

2.9 修改联系人信息

修改联系人信息同样需要搜索函数FindOfName(name, pc);,如果要想修改的人存在,那么会返回它的下标,再通过下标对这个人的全部信息重新输入

void ModifyContact(Contact* pc)
{assert(pc);char name[NAME_MAX] = { 0 };printf("请输入要修改的人的名字:");scanf("%s", name);int ret = FindOfName(name, pc);if (ret == -1){printf("找不到要修改的人\n");return;}printf("请输入名字:");scanf("%s", pc->data[ret].name);printf("请输入年龄:");scanf("%d", &(pc->data[ret].age));printf("请输入性别:");scanf("%s", pc->data[ret].gender);printf("请输入电话:");scanf("%s", pc->data[ret].tele);printf("请输入地址:");scanf("%s", pc->data[ret].addr);
}

2.10 打印所有联系人信息

打印所有联系人信息,无非就是遍历并打印所有元素,同样加上提示信息

void ShowContact(Contact* pc)
{assert(pc);if (pc->sz == 0){printf("通讯录为空,打印无意义\n");return;}int i = 0;printf("%-20s%-5s%-5s%-30s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");for (i = 0; i < pc->sz; i++){printf("%-20s%-5d%-5s%-30s%-30s\n", pc->data[i].name, pc->data[i].age,pc->data[i].gender, pc->data[i].tele, pc->data[i].addr);}
}

2.11 以名字排序所有联系人

使用qsort函数可快速排序,了解qsort函数

int cmp(const void* a, const void* b)
{return strcmp((char*)a, (char*)b);
}void SortContact(Contact* pc)
{assert(pc);qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp);printf("排序成功\n");
}

三. 模块化代码实现

3.1 test.c

#include"contact.h"void menu()
{printf("-----------------------------------\n");printf("***********************************\n");printf("******  1.Add       2.Del    ******\n");printf("******  3.Select    4.Modify ******\n");printf("******  5.Show      6.Init   ******\n");printf("******  7.sort      0.exit   ******\n");printf("***********************************\n");printf("-----------------------------------\n");
}enum Option
{EXIT,ADD,DEL,SELECT,MODIFY,SHOW,INIT,SORT
};int main()
{Contact con;//初始化通讯录InitContact(&con);int input = 0;do{ menu();printf("请选择:");scanf("%d", &input);switch (input){case ADD:AddContact(&con);break;case DEL:DelContact(&con);break;case SELECT:SelectContact(&con);break;case MODIFY:ModifyContact(&con);break;case SHOW:ShowContact(&con);break;case INIT:InitContact(&con);break;case SORT:SortContact(&con);break;case EXIT:printf("退出程序\n");break;default:printf("选择错误,请重新选择\n");break;}} while (input);return 0;
}

3.2 contact.h

#pragma once#include<stdio.h>
#include<assert.h>
#include<string.h>#define NAME_MAX 20
#define GENDER_MAX 5
#define TELE_MAX 30
#define ADDR_MAX 30
#define MAX 1000typedef struct PeoInfo
{char name[NAME_MAX];int age;char gender[GENDER_MAX];char tele[TELE_MAX];char addr[ADDR_MAX];
}PeoInfo;typedef struct Contact
{PeoInfo data[MAX];int sz;
}Contact;//初始化通讯录
void InitContact(Contact* pc);//增加联系人
void AddContact(Contact* pc);//删除联系人
void DelContact(Contact* pc);//打印通讯录
void ShowContact(Contact* pc);//查找联系人
void SelectContact(Contact* pc);//修改联系人信息
void ModifyContact(Contact* pc);//以名字排序所有联系人
void SortContact(Contact* pc);

3.3 contact.c

#include"contact.h"//初始化通讯录
void InitContact(Contact* pc)
{assert(pc);pc->sz = 0;memset(pc->data, 0, sizeof(pc->data));
}//增加联系人
void AddContact(Contact* pc)
{assert(pc);if (pc->sz == MAX){printf("通讯录已满,增加失败\n");return;}printf("请输入名字:");scanf("%s",pc->data[pc->sz].name );printf("请输入年龄:");scanf("%d", &(pc->data[pc->sz].age));printf("请输入性别:");scanf("%s", pc->data[pc->sz].gender);printf("请输入电话:");scanf("%s", pc->data[pc->sz].tele);printf("请输入地址:");scanf("%s", pc->data[pc->sz].addr);pc->sz++;printf("增加成功\n");
}int FindOfName(char* name, Contact* pc)
{assert(name && pc);int i = 0;for (i = 0; i < pc->sz; i++){if (0 == strcmp(name, (pc->data[i].name)))return i;}return -1;
}//删除联系人
void DelContact(Contact* pc)
{assert(pc);char name[NAME_MAX] = { 0 };if (pc->sz == 0){printf("通讯录为空,删除失败\n");return;}printf("请输入要删除的人的名字:");scanf("%s", name);int ret = FindOfName(name, pc);if (ret == -1){printf("找不到要删除的人\n");return;}int i = 0;for (i = ret; i < pc->sz - 1; i++){pc->data[i] = pc->data[i + 1];}pc->sz--;printf("删除成功\n");
}//打印通讯录
void ShowContact(Contact* pc)
{assert(pc);if (pc->sz == 0){printf("通讯录为空,打印无意义\n");return;}int i = 0;printf("%-20s%-5s%-5s%-30s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");for (i = 0; i < pc->sz; i++){printf("%-20s%-5d%-5s%-30s%-30s\n", pc->data[i].name, pc->data[i].age,pc->data[i].gender, pc->data[i].tele, pc->data[i].addr);}
}//查找联系人
void SelectContact(Contact* pc)
{char name[NAME_MAX] = { 0 };printf("请输入要查找的人的名字:");scanf("%s", name);int ret = FindOfName(name, pc);if (ret == -1){printf("找不到要查找的人\n");return;}printf("%-20s%-5s%-5s%-30s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");printf("%-20s%-5d%-5s%-30s%-30s\n", pc->data[ret].name, pc->data[ret].age,pc->data[ret].gender, pc->data[ret].tele, pc->data[ret].addr);
}//修改联系人信息
void ModifyContact(Contact* pc)
{assert(pc);char name[NAME_MAX] = { 0 };printf("请输入要修改的人的名字:");scanf("%s", name);int ret = FindOfName(name, pc);if (ret == -1){printf("找不到要修改的人\n");return;}printf("请输入名字:");scanf("%s", pc->data[ret].name);printf("请输入年龄:");scanf("%d", &(pc->data[ret].age));printf("请输入性别:");scanf("%s", pc->data[ret].gender);printf("请输入电话:");scanf("%s", pc->data[ret].tele);printf("请输入地址:");scanf("%s", pc->data[ret].addr);
}int cmp(const void* a, const void* b)
{return strcmp((char*)a, (char*)b);
}//以名字排序所有联系人
void SortContact(Contact* pc)
{assert(pc);qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp);printf("排序成功\n");
}

3.4 结果演示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


四. 存在的问题

前面实现的通讯录有什么问题呢?
1.录入的信息,等程序结束后,还存在吗?不存在了,因为数据是存放内存中的,只要程序退出,掉电,都会
丢失怎么解决呢?用文件存储,数据库…
2.通讯录的大小是固定的100个元素,存放100个人的信息如果信息太多,空间小了;如果信息太少,空间大了。怎么解决?用动态内存管理!
所以期待博主的下一篇优化的通讯录管理系统吧


好了,那么本篇博客就到此结束了,如果你觉得本篇博客对你有些帮助,可以给个大大的赞👍吗,感谢看到这里,我们下篇博客见❤️

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

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

相关文章

LSM Tree 深度解析

我们将深入探讨日志结构合并树&#xff0c;也称为LSM Tree&#xff1a;这是许多高度可扩展的NoSQL分布式键值型数据库的基础数据结构&#xff0c;例如Amazon的DynamoDB、Cassandra和ScyllaDB。这些数据库的设计被认为支持比传统关系数据库更高的写入速率。我们将看到LSM Tree如…

驱动开发4 使用字符设备驱动的分步实现编写LED驱动(LED亮灯)

一、思维导图 二、通过字符设备驱动的分步实现编写LED驱动&#xff0c;另外实现特备文件和设备的绑定 应用程序 test.c #include<stdlib.h> #include<stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/ioctl.h> #include…

Jenkins部署失败:JDK ‘jdk1.8.0_381‘ not supported to run Maven projects

Jenkins部署报错&#xff1a;JDK ‘jdk1.8.0_381’ not supported to run Maven projects提示使用的jdk有问题&#xff0c;启动的jdk版本不能满足项目启动。 登录Jenkins管理页面&#xff0c;系统管理——全局工具配置——JDK安装配置满足条件的JDK版本&#xff0c;保存配置&…

Parallels Client for Mac:改变您远程控制体验的革命性软件

在当今数字化的世界中&#xff0c;远程控制软件已经成为我们日常生活和工作中不可或缺的一部分。在众多远程控制软件中&#xff0c;Parallels Client for Mac以其独特的功能和出色的性能脱颖而出&#xff0c;让远程控制变得更加简单、高效和灵活。 Parallels Client for Mac是…

08数据结构——排序

8.2 插入排序 8.2.1 直接插入排序 直接插入排序&#xff08;用哨兵&#xff09;代码如下&#xff1a; void InsertSort(ElemType A[],int n){int i,j;for(i2;i<n;i) //依次将A[2]~A[n]插入前面已排序序列if(A[i]<A[i-1]){ //若A[i]关键码小于其前驱…

成都瀚网科技有限公司抖音小店:创新营销引领电商潮流

在当今数字化时代&#xff0c;抖音作为一款备受欢迎的短视频平台&#xff0c;不仅吸引了大量用户的关注&#xff0c;还为众多电商企业提供了新的销售渠道。成都瀚网科技有限公司抖音小店便是其中之一&#xff0c;凭借其独特的营销策略和优质的产品&#xff0c;成为了抖音电商领…

PyCharm改变代码背景图片的使用教程

一个好的集成环境是学习和使用一门编程语言的重中之重&#xff0c;这次我给大家分享如何改变PyCharm软件的代码背景图片。 说明&#xff1a;本教程使用的是汉化版PyCharm软件。 打开PyCharm软件。 点击软件最上方导航栏的文件&#xff0c;然后找到设置。 打开设置然后点击外观…

总结使用React做过的一些优化

一、修改css模拟v-show {!flag && <MyComponent style{{display: none}} />} {flag && <MyComponent />}<MyComponent style{{ display: flag ? block : none }} />二、循环使用key const todosList todos.map(item > {<li key{it…

Web APIs——焦点事件以及小米搜索框

一、事件类型 二、焦点事件 <body><input type"text"><script>const input document.querySelector(input)input.addEventListener(focus,function(){console.log(有焦点触发)})input.addEventListener(blur,function(){console.log(失去焦点触…

如何使用 JMeter 进行 HTTPS 请求测试?

本文将介绍如何使用 JMeter 测试 HTTPS 请求&#xff0c;并提供相关的技巧和注意事项。 在进行性能测试时&#xff0c;很多网站都采用了 HTTPS 协议。当我们测试 HTTPS 请求&#xff0c;如果服务端开启了双向认证&#xff0c;则需要客户端发送请求时带上证书。本文介绍如何在 …

【Axure视频教程】曲线图

今天教大家在Axure制作可视化曲线图的原型模板&#xff0c;鼠标移入曲线图后&#xff0c;会显示弹窗并回显对应折点的具体数据&#xff0c;该模板是用Axure原生元件制作的&#xff0c;所以使用方便&#xff0c;可以任意修改对应样式或者交互效果。该原型模板的具体效果可以参考…

Pytorch--3.使用CNN和LSTM对数据进行预测

这个系列前面的文章我们学会了使用全连接层来做简单的回归任务&#xff0c;但是在现实情况里&#xff0c;我们不仅需要做回归&#xff0c;可能还需要做预测工作。同时&#xff0c;我们的数据可能在时空上有着联系&#xff0c;但是简单的全连接层并不能满足我们的需求&#xff0…

【Docker】Docker学习之一:离线安装Docker步骤

前言&#xff1a;基于Ubuntu Jammy 22.04 (LTS)版本安装和测试 1、Docker安装 1.1、离线安装 步骤一&#xff1a;官网下载 docker 安装包 wget https://download.docker.com/linux/static/stable/x86_64/docker-24.0.6.tgz步骤二&#xff1a;解压安装包; tar -zxvf docker…

谈谈Net-SNMP软件

Net-SNMP是一个开源的SNMP软件套件&#xff0c;它提供了SNMP代理&#xff08;snmpd&#xff09;和SNMP工具&#xff08;如snmpget、snmpwalk等&#xff09;&#xff0c;可以用于监控和管理网络设备。 Net-SNMP最初是从UC Davis的SNMP软件衍生而来&#xff0c;现在已经成为广泛…

小程序设计基本微信小程序的校园生活助手系统

项目介绍 通篇文章的撰写基础是实际的应用需要&#xff0c;然后在架构系统之前全面复习大学所修习的相关知识以及网络提供的技术应用教程&#xff0c;以校园生活助手系统的实际应用需要出发&#xff0c;架构系统来改善现校园生活助手系统工作流程繁琐等问题。不仅如此以操作者…

纺织工厂数字孪生3D可视化管理平台,推动纺织产业数字化转型

近年来&#xff0c;我国加快数字化发展战略部署&#xff0c;全面推进制造业数字化转型&#xff0c;促进数字经济与实体经济深度融合。以数字孪生、物联网、云计算、人工智能为代表的数字技术发挥重要作用。聚焦数字孪生智能工厂可视化平台&#xff0c;推动纺织制造业数字化转型…

【Java集合类面试十八】、ConcurrentHashMap是怎么分段分组的?

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a;ConcurrentHashMap是怎么…

手把手教你在项目中引入Excel报表组件

摘要&#xff1a;本文由葡萄城技术团队原创并首发。转载请注明出处&#xff1a;葡萄城官网&#xff0c;葡萄城为开发者提供专业的开发工具、解决方案和服务&#xff0c;赋能开发者。 前言 GrapeCity Documents for Excel&#xff08;以下简称GcExcel&#xff09;是葡萄城公司的…

【TES641】基于VU13P FPGA的4路FMC接口基带信号处理平台

板卡概述 TES641是一款基于Virtex UltraScale系列FPGA的高性能4路FMC接口基带信号处理平台&#xff0c;该平台采用1片Xilinx的Virtex UltraScale系列FPGA XCVU13P作为信号实时处理单元&#xff0c;该板卡具有4个FMC子卡接口&#xff08;其中有2个为FMC接口&#xff09;&#x…

Vue3.3指北(二)

Vue3.3指北 Vue31、组件基础1.1、全局组件1.2、局部组件1.3、组件的命名1.4、组件的数据存放1.5、组件标签化 2、父组件向子组件传递数据2.1、props2.2、动态props2.3、props传数组2.4、props传对象2.4.1、默认值和必传值 3、子组件向父组件传递数据4、父子组件互相访问4.1、父…