学习vue3第十二节(组件的使用与类型)

1、组件的作用用途

目的:
提高代码的复用度,和便于维护,通过封装将复杂的功能代码拆分为更小的模块,方便管理,
当我们需要实现相同的功能时,我们只需要复用已经封装好的组件,而不需要重新编写相同的代码

好处:
代码复用:我们可以在多个地方复用封装好的组件,而不需要在每个地方都写相同的代码。
易于维护:当我们需要修改某个功能时,我们只需要在一个地方修改即可,而不需要在多个地方修改。
易于理解:通过将复杂的功能分解为更小的部分,我们可以更容易地理解和管理代码
单一职责:组件应该只做一件事情,而不是承担多个无关的职责,避免过度封装,导致功能复杂化

2、组件的分类

2.1. 全局组件

好处:只需要在main.ts 中挂载注册,不用在使用页面中一个一个的引入注册,减少了代码的冗杂;
坏处:会导致组件之间的依赖关系不明确,导致组件之间查找调试错误时候难以追踪具体位置;
同时,由于全局组件会被打包的打包后的文件中,导致初始化首屏加载时间长,编译和预处理时间长,从而影响用户的体验;谨慎使用全局组件

首先我们会先将一个vue组件定义在一个单独的.vue文件中,这就是单文件组件
如:定义一个全局的顶部搜索栏 headerForm.vue 文件

// headerForm.vue
<template><div class="header-form">全局顶部搜索栏name:{{ defineProps.name }}<el-row><el-col :span="6"><el-form :inline="true" :model="formInline" class="demo-form-inline"><el-form-item label="用户名"><el-input v-model="formInline.user" placeholder="请输入用户名"></el-input></el-form-item></el-form></el-col></el-row></div>
</template>
<script setup>
import { ref, watch, onMounted } from 'vue'
// defineProps 是vue3中新增的宏,用于处理接收 props 的属性,不需要引入,可以直接在setup 语法糖中使用;后续文章会专门介绍
const defineProps = defineProps({name: {type: String,default: ''}
})
// 此处使用了 ref() 函数 创建了 对象,为什么不用reactive() 函数呢?因为使用reactive() 函数,要使用嵌套函数保持响应式 需要使用 toRefs() 将其转换ObjectRefImpl 对象,详情请看 第五节
let formInline = ref({user: defineProps.name // 将user默认值设置为父组件传入的name 属性值
})
// watch 的相关内容请看第六节 watch
watch(() => defineProps.name, (n,o) => {// 监听name 的变化,用于同步更新user属性;formInline.value.user = defineProps.name
})
</script>
<style lang='scss' scoped>
.header-form{width: 100vw;height: 46px;
}
</style>
// main.ts
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import App from './App.vue'
<!-- 引入全局组件 -->
import HeaderFrom from './components/headerForm.vue'
import 'element-plus/dist/index.css'
import './style.css'
const app = createApp(App)
<!-- 挂载全局组件 -->
// app.component('注册的组件名称', 引入的单文件组件)
app.component('HeaderFrom', HeaderFrom) // 支持链式调用<!-- 如果全局组件比较多,可以这样使用,将element的所有图标注册到项目中,非必要勿用 -->
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {app.component(key, component)
}app.use(ElementPlus)
app.mount('#app')
<!-- App.vue -->
<template>
<div class="par">//  直接使用 HeaderFrom 即可,不需要再次引入<HeaderFrom :name="name"></HeaderFrom><Provide></Provide><button @click="handleChangeName">父组件change name</button></div>
</template>
<script setup>
import Provide from './components/provide1.vue'
import { ref, provide, inject } from 'vue'
let msg = ref('Andy start')
let name = ref('Andy')const handleChangeName = () => {name.value = 'Andy change'
}
const sChangeName = () => {msg.value = 'Andy sChangeName'
}
provide('pName', {msg, sChangeName})
</script><style lang="scss">
.img-box{display: inline-block;width: 100px;height: 100px;
}
</style>

注意:如果声明的组件不是项目中绝大多数页面共用的,请勿注册全局组件,应为即使在页面中没有使用该组件,也会导致引入的组件被打包到打包后的文件中,无法通过 tree-shaking 自动移除,因为组件被挂载到app实例上;

tree-shaking:消除无用的js代码;
1、在webpack中,通过配置 optimization.usedExports: true,开启tree-shaking功能
2、在vite中,通过配置 rollup-plugin-commonjs,开启tree-shaking功能;

2.2. 局部组件

好处
1、可以非常清晰父子组件之间的依赖关系,便于维护;
2、同时只有在页面加载时候才会使用组件,可以更好的支持tree-shaking减少打包体积;
坏处
需要每次使用时候导入一次,增加文件的导入语句;

<!-- 定义局部组件 dialogForm.vue -->
<template>
<div class="dialog-container"><div class="dialog-form"><div class="dialog-header"><div class="dialog-title">新增用户</div><el-icon class="dialog-close"><Close /></el-icon></div><el-form :model="formData" label-width="80px" ref="formDataRef"><el-form-item label="用户名:" prop="username"><el-input v-model="formData.username" placeholder="请输入用户名" /></el-form-item><el-form-item label="职位:" prop="post"><el-input v-model="formData.username" placeholder="请输入职位" /></el-form-item><el-button @click="submit" type="primary">提交</el-button></el-form></div>
</div>
</template>
<script setup>
import { reactive, ref } from 'vue'const formDataRef = ref()
let formData = ref({username: '',post: ''
})const submit = () => {console.log('==', formData.value)
}</script>
<!-- 在父组件myComponents.vue 中引入使用 -->
<template><div class="my-components">页面类型:{{pageNameType}}<DialogForm></DialogForm></div></template><script setup>import { ref, reactive } from 'vue'// 在setup 中直接引入组件即可,打包编译时会自动编译成组件,不需要再次使用componentsimport DialogForm from './dialogForm.vue'const pageNameType = ref('局部组件')</script>

2.3. 动态组件

动态组件,当一个页面中的内容需要通过不同的组件来进行展示时,可以通过动态组件的切换来实现;
需要注意的是:vue3中 需要使用markRaw() 或者 shallowReactive() 来创建组件,否则页面会发出警告,导致页面不更新
请添加图片描述

动态组件是通过 :is 属性来实现组件之间的切换的;

<component :is="组件名"></component>

如下实现:

<template><div class="my-components">页面类型:{{pageNameType}}<component :is="comName"></component><el-button type="primary" @click="handleChangeCom">切换组件</el-button></div>
</template>
<script setup>import { ref, markRaw } from 'vue'import Work from './work.vue' // 组件内容: The job is GeYou's live.import UserInfo from './userInfo.vue' // 组件内容:用户信息const pageNameType = ref('动态组件')const workRaw = markRaw(Work) // 使用markRaw进行标记,避免转换为响应式对象const userInfoRaw = markRaw(UserInfo)let comName = ref(workRaw) // 默认展示组件为 Workconst handleChangeCom = () => {console.log('===', comName)if (comName.value === workRaw) {comName.value = userInfoRaw} else {comName.value = workRaw}}
</script>

2.4. 递归组件

vue2 中是通过组件中的name属性来区分组件的,直接在自己组件中使用自己同名组件即可实现递归;
如:
递归组件注意需要有跳出循环的出口,不然会导致死循环,进而栈溢出; 跳出条件:v-if=“endNum < 4”
若不跳出循环将会报错:

请添加图片描述

<template><div class="recursion-com" v-if="endNum < 4"><span>{{name}}--{{ num }}--{{ endNum }}</span><div >// 此处调用直接与自己的组件名称保持一致即可<RecursionCom :num="endNum" ></RecursionCom> </div></div>
</template>
<script>
export default {name: 'RecursionCom', // 注意:需要声明组件名称components: {},props: {num: {type: Number,default: 0}},data() {return {name: 'vue2递归组件',list: [22, 33],endNum: 0}},created() {this.endNum = this.numthis.endNum++}
}
</script>

vue3 中

父组件中:
<template>
<div>vue3 父组件<RecursionComV3 :data="data"></RecursionComV3>
</div>
</template>
<script setup>
import { ref } from 'vue'
import RecursionComV3 from './recursionComV3.vue';
// 声明一个data 变量数据
const data = ref([{id: '1-1',name: '张家',children: [{id: '1-1-2',name: '张三',children: [{id: '1-1-3',name: '张三郎',}]}]},{id: '1-2',name: '李家',children: [{id: '1-2-2',name: '李四',children: [{id: '1-2-3',name: '李四郎',}]}]}
])
</script>
<!-- 子组件中 -->
使用js 书写时:
<template>
<div class="my-recursion"><div v-for="(item, index) in props.data" :key="item.id"><div class="item">{{ item.id }}:{{item.name}}</div><myTreeV3 v-if="item.children && item.children.length" :data="item.children"></myTreeV3></div>
</div>
</template>
<script>
// 如果使用js 需要在子组件中使用export default{} 给组件命名name;
export default {name: 'myTreeV3', 
}
</script>
<script setup>
import { ref, reactive, toRefs, onMounted, watch, computed } from 'vue'
const props = defineProps({data: {type: Array,default: () => ([]),},
})
</script>

最终运行结果如下图
请添加图片描述

若子组件使用ts 书写:
注意:ts 中需要使用到递归组件,需要使用到递归类型,需要将数据类型进行声明,
同时 调用的递归组件名称 需要与 自己的文件名保持一致,否则不生效:比如文件名为recursionComV3Ts.vue,则调用时需要使用:

如下:

<template>
<div class="my-recursion"><div v-for="(item) in data" :key="item.id"><div class="item">{{ item.id }}:{{item.name}}</div><!-- 使用ts 写递归组件时,调用的必须与自己的文件名保持一致 --><recursionComV3Ts v-if="item?.children && item?.children?.length" :data="item?.children"></recursionComV3Ts></div>
</div>
</template>
<script setup lang="ts">
// TreeData 声明接口类型
interface TreeData{id: stringname: stringchildren?:TreeData[] // children 是可以选项
}
defineProps<{data?:TreeData[]
}>()
</script>

3、组件的使用 注意事项

a、单文件组件结构、
b、命名规范,便于管理;
c、props属性传递声明类型,明确;
d、emit事件机制;
e、slot插槽,非常重要的部分,可以动态的将内容html插入到组件中;

下节 单独介绍 组件之间的传参,事件等

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

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

相关文章

(九)图像的高斯低通滤波

环境&#xff1a;Windows10专业版 IDEA2021.2.3 jdk11.0.1 OpenCV-460.jar 系列文章&#xff1a; &#xff08;一&#xff09;PythonGDAL实现BSQ&#xff0c;BIP&#xff0c;BIL格式的相互转换 &#xff08;二&#xff09;BSQ,BIL,BIP存储格式的相互转换算法 &#xff08;三…

Flask学习(六):蓝图(Blueprint)

蓝图&#xff08;Blueprint&#xff09;&#xff1a;将各个业务进行区分&#xff0c;然后每一个业务单元可以独立维护&#xff0c;Blueprint可以单独具有自己的模板、静态文件或者其它的通用操作方法&#xff0c;它并不是必须要实现应用的视图和函数的。 Demo目录结构&#xf…

linux离线安装jenkins及使用教程

本教程采用jenkins.war的方式离线安装部署&#xff0c;在线下载的方式会遇到诸多问题&#xff0c;不宜采用 一、下载地址 地址&#xff1a;Jenkins download and deployment 下载最新的长期支持版 由于jenkins使用java开发的&#xff0c;所以需要安装的linux服务器装有jdk环…

插入排序、归并排序、堆排序和快速排序的稳定性分析

插入排序、归并排序、堆排序和快速排序的稳定性分析 一、插入排序的稳定性二、归并排序的稳定性三、堆排序的稳定性四、快速排序的稳定性总结在计算机科学中,排序是将一组数据按照特定顺序进行排列的过程。排序算法的效率和稳定性是评价其优劣的两个重要指标。稳定性指的是在排…

新版Idea2023.3.5与lombok冲突、@Data失效

新版idea和lombok冲突&#xff0c;加上Data&#xff0c;其他地方get set也不报错&#xff0c;但是一运行就找不到get set方法。 但是直接使用Getter和Setter可以访问、应该是Data失效了。 解决方法&#xff1a; 看推上介绍是 lombok 与 idea 采集 get 、set 方法的时候所用的技…

Jupyter开启远程服务器(最新版)

Jupyter Notebook 在本地进行访问时比较简单&#xff0c;直接在cmd命令行下输入 jupyter notebook 即可&#xff0c;然而notebook的作用不止于此&#xff0c;还可以用于远程连接服务器&#xff0c;这样如果你有一台服务器内存很大&#xff0c;但是呢你又不喜欢在linux上进行操作…

【C语言】编译和链接----预处理详解【图文详解】

欢迎来CILMY23的博客喔&#xff0c;本篇为【C语言】文件操作揭秘&#xff1a;C语言中文件的顺序读写、随机读写、判断文件结束和文件缓冲区详细解析【图文详解】&#xff0c;感谢观看&#xff0c;支持的可以给个一键三连&#xff0c;点赞关注收藏。 前言 欢迎来到本篇博客&…

如何备考2025年AMC8竞赛?吃透2000-2024年600道真题(免费送题)

最近有家长朋友问我&#xff0c;现在有哪些类似于奥数的比赛可以参加&#xff1f;我的建议可以关注下AMC8的竞赛&#xff0c;类似于国内的奥数&#xff0c;但是其难度要比国内的奥数低一些&#xff0c;而且比赛门槛更低&#xff0c;考试也更方便。比赛的题目尤其是应用题比较有…

Redis开源协议变更!Garnet:微软开源代替方案?

Garnet&#xff1a;微软开源的高性能替代方案&#xff0c;秉承兼容 RESP 协议的同时&#xff0c;以卓越性能和无缝迁移能力重新定义分布式缓存存储&#xff01; - 精选真开源&#xff0c;释放新价值。 概览 最近&#xff0c;Redis修改了开源协议&#xff0c;从BSD变成了 SSPLv…

第二十一章 Jquery ajax

文章目录 1. jquery下载2. jquery的使用3. jquery页面加载完毕执行4. jquery属性控制6. 遍历器 2. ajax1. 准备后台服务器2. ajax发送get请求3. ajax发送post请求 1. jquery下载 点击下载 稳定版本1.9 2. jquery的使用 存放到html文件的同级目录 3. jquery页面加载完毕执行…

Unity | 射线检测及EventSystem总结

目录 一、知识概述 1.Input.mousePosition 2.Camera.ScreenToWorldPoint 3.Camera.ScreenPointToRay 4.Physics2D.Raycast 二、射线相关 1.3D&#xff08;包括UI&#xff09;、射线与ScreenPointToRay 2.3D&#xff08;包括UI&#xff09;、射线与ScreenToWorldPoint …

Linux安装redis(基于CentOS系统,Ubuntu也可参考)

前言&#xff1a;本文内容为实操记录&#xff0c;仅供参考&#xff01; 一、下载并解压Redis 1、执行下面的命令下载redis&#xff1a;wget https://download.redis.io/releases/redis-6.2.6.tar.gz 2、解压redis&#xff1a;tar xzf redis-6.2.6.tar.gz 3、移动redis目录&a…

“直播曝光“有哪些媒体直播分流资源?

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 我们线下举办活动时&#xff0c;往往希望活动进行更大的曝光&#xff0c;随着视频直播越来越被大众认可&#xff0c;甚至成了活动的标配&#xff0c;那么做活动视频直播的时候&#xff0…

admin端

一、创建项目 1.1 技术栈 1.2 vite 项目初始化 npm init vitelatest vue3-element-admin --template vue-ts 1.3 src 路径别名配置 Vite 配置 配置 vite.config.ts // https://vitejs.dev/config/import { UserConfig, ConfigEnv, loadEnv, defineConfig } from vite im…

|行业洞察·趋势报告|《2024旅游度假市场简析报告-17页》

报告的主要内容解读&#xff1a; 居民收入提高推动旅游业发展&#xff1a;报告指出&#xff0c;随着人均GDP的提升&#xff0c;居民的消费能力增强&#xff0c;旅游需求从传统的观光游向休闲、度假游转变&#xff0c;国内人均旅游消费持续增加。 政府政策促进旅游市场复苏&…

公众号的AI聊天机器人已修复!谷歌Gemini Pro 10大使用场景解析

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;所以创建了“AI信息Gap”这个公众号&#xff0c;专注于分享AI全维度知识…

WorkPlus Meet构建局域网视频会议解决方案,助力企业协同与沟通

在当今数字化时代&#xff0c;局域网视频会议扮演着企业协同与沟通的重要角色。而选择适合的局域网视频会议平台能够提升企业的协作效率与沟通效果。WorkPlus Meet以其卓越的性能和强大的功能&#xff0c;成为企业局域网视频会议的首选。 局域网视频会议的优势与作用不言而喻。…

蓝桥杯-卡片换位

solution 有一个测试点没有空格&#xff0c;要特别处理&#xff0c;否则会有一个测试点运行错误&#xff01; 还有输入数据的规模在变&#xff0c;小心顺手敲错了边界条件 #include<iostream> #include<string> #include<queue> #include<map> #incl…

进程与文件

目录 Linux的 > 和 >> 文件的本质 &#xff1a; 操作系统的系统调用函数 open&#xff1a; close&#xff1a;关闭文件 write&#xff1a; open的返回值&#xff1a; 操作系统视角中的“文件与进程之间的关系”&#xff1a; 从上图可以得知以下论点&#xff1a…

LabVIEW电动汽车直流充电桩监控系统

LabVIEW电动汽车直流充电桩监控系统 随着电动汽车的普及&#xff0c;充电桩的安全运行成为重要议题。通过集成传感器监测、单片机技术与LabVIEW开发平台&#xff0c;设计了一套电动汽车直流充电桩监控系统&#xff0c;能实时监测充电桩的温度、电压和电流&#xff0c;并进行数…