Vue学习记录之八(局部组件,全局组件,递归组件,动态组件)

一、局部组件

在src\components\Card.vue 建立一个文件,代码如下:

<template><div class="card"><header><div>标题</div><div>副标题</div></header><section>内容</section></div>
</template>
<script setup lang='ts'>
import { ref,reactive } from 'vue'</script>
<style scoped lang="scss">
$border: #ccc;
.card{border: 1px solid $border;width: 400px;header{display: flex;justify-content: space-between;padding: 5px;border-bottom: 1px solid $border;}section{padding: 5px;min-height: 300px;}}
</style>

然后在要使用的文件中引入并使用。

<template><div><!--2、使用--><Card></Card></div>
</template>
<script setup lang='ts'>
//1、引入
import Card from './components/Card.vue';
</script>

二、全局组件

上面局部变量是谁使用,谁应用。而全局变量在配置中一次引入,任何地方都可以随时使用。
在main.ts 文件引入

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
//1、引入组件
import Card from './components/Card.vue';const app = createApp(App)
//2,注册组件为全局变量
app.component('Card',Card)
app.use(createPinia())
app.use(router)app.mount('#app')

然后在任意需要的地方,使用 即可。如果有何多组件,可以使用批量注册组件的方法进行。例如我们在element UI 中导入Icons下:

import * as ElementPlusIconsVue from '@element-plus/icons-vue' 
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {app.component(key, component)
}

三、递归组件

1)、父传子数据

<template><div><!--给子组件传递一个名为datas的变量,该变量数据下面已定义--><Tree :datas="data"></Tree></div>
</template>
<script setup lang='ts'>
import { ref,reactive } from 'vue'
import Tree from './components/Tree.vue';
interface Tree{name:string,checked: boolean,children?: Tree[]
}
const data = reactive<Tree[]>([{name:"1",checked:false,children:[{name:"1-1",checked:false,}]},{name:"2",checked:true,children:[{name:"2-1",checked:false,}]},{name:"3",checked:false,children:[{name:"3-1",checked:false,children:[{name:"3-1-1",checked:false,},{name:"3-1-2",checked:false,},]}]},
])</script>

2)、开始递归

在子组件中(Tree.vue)开始编写递归代码

1、直接使用组件名称来当成循环体
<template><div v-for="item in data" class="tree"><input type="checkbox" v-model="item.checked"><span>{{ item.name }}</span><!--下面开始递归:可以直接使用文件名当组件名,也就是自己用自己的文件名称来递归。绑定的数据要和上面循环的数据名称一致,既用上面的 :data,而且使用v-if来判断数组的长度,为真时递归--><Tree v-if="item?.children?.length" :data="item.children"></Tree><!--可选链操作符的使用(?)的使用,如果后面的属性不到的话,就返回undefined,避免报错。undefined隐式转换以后就是false,停止了循环。一般配合双问(??)好表达式进行使用,如果左边返回一个undefined或者null值的时候(而且只有是undefined或者null才可以),则可以返回双问号后面(右边)的值,有点类似三目运算符。undefined??123  返回1230??123  返回0--></div>
</template>
<script setup lang='ts'>
import { ref,reactive } from 'vue'
interface Tree{name:string,checked: boolean,children?: Tree[]
}
defineProps<{data?:Tree[]
}>()
</script>
<style lang="scss" scoped>
.tree{margin-left: 10px;
}
</style>
2、自定义一个名称用来递归

上面我们直接使用了文件名,如果感觉突兀,也可以自定义,在子组件中,新建一组script代码。

<template><div v-for="item in datas" class="tree"><input type="checkbox" v-model="item.checked"><span>{{ item.name }}</span><!--递归体使用自定义的LvmanbaTree--><LvmanbaTree v-if="item.children?.length" :datas="item.children"></LvmanbaTree></div>
</template>
<script setup lang='ts'>
import { ref,reactive } from 'vue'
interface Tree{name:string,checked: boolean,children?: Tree[]
}
defineProps<{datas?:Tree[]
}>()
</script>
<script lang="ts">
export default{name="LvmanbaTree"
}
</script>
3、使用插件

第二种方法虽然可以自定了循环名称了,但是也要增加一组

第一步: 安装插件

pnpm add -D unplugin-vue-define-options @vue-macros/volar

第二步:在vite.config.ts中进行配置

//1、引入组件
import DefineOptions from 'unplugin-vue-define-options/vite'export default defineConfig({//2、在plugins中注册下,使用DefineOpetions()plugins: [DefineOptions()],
})

第三步:
在tsconfig.json 进行如下配置:就出现了代码提示了。

{"compilerOptions": {// ..."types": ["unplugin-vue-define-options/macros-global" /* ... */]}
}

第四步: 使用
它提供一个编译宏,必须使用这个插件,才能使用defineOptions. 这个是插件提供的,这样就不用再写一个

defineOptions({name:"LvmanbaTree"
})
4、接收tree的点击事件
<template><!--不加stop,出现冒泡事件--><div @click.stop="clickTap(item)" v-for="item in datas" class="tree"><input type="checkbox" v-model="item.checked"><span>{{ item.name }}</span><!--递归体使用自定义的LvmanbaTree--><LvmanbaTree v-if="item.children?.length" :datas="item.children"></LvmanbaTree></div>
</template>
<script setup lang='ts'>
import { ref,reactive } from 'vue'
interface Tree{name:string,checked: boolean,children?: Tree[]
}
defineProps<{datas?:Tree[]
}>()
const clickTap = (item: Tree) =>{console.log(item)
}
</script>
<script lang="ts">export default{name:"LvmanbaTree"}
</script>
<style lang="scss" scoped>
.tree{margin-left: 10px;
}
</style>

也可以传递事件

<template><div @click.stop="clickTap(item,$event)" v-for="item in datas" class="tree"><input type="checkbox" v-model="item.checked"><span>{{ item.name }}</span><Tree v-if="item.children?.length" :datas="item.children"></Tree></div>
</template>
<script setup lang='ts'>
import { ref,reactive } from 'vue'
interface Tree{name:string,checked: boolean,children?: Tree[]
}
defineProps<{datas?:Tree[]
}>()
const clickTap = (item: Tree,e) =>{//console.log(item)console.log(e.target)
}
</script><style lang="scss" scoped>
.tree{margin-left: 10px;
}
</style>

四、 动态组件

动态组件,就是多个组件使用同一个挂载点,也就是一个位置,可以动态切换的显示多个组件。 在挂载点使用 component标签,然后在使用v-bind:is = “组件”。 应用场景,典型的tab切换。当然也可以使用动态路由来实现。

实例: 效果如下。
在这里插入图片描述
第一步: 先创建三个组件
在这里插入图片描述
第二步:编写代码
一个标签内可以有两个想通的属性,但是必须一个静态,另外一个是动态。另外一个难理解的地方就是就把一个组件赋值给一个变量。

<template><div style="display: flex;"><div @click="switchCom(item,index)"v-for="(item,index) in data" class="tabs" :class="[active == index ? 'active':'']"><div>{{ item.name }}</div></div></div><component :is="comId"></component>
</template>
<script setup lang='ts'>
import { ref,reactive } from 'vue'
import AVue from './components/A.vue';
import BVue from './components/B.vue';
import CVue from './components/C.vue';
const comId = ref(AVue)
const active = ref(0)
const switchCom =(item,index:number) =>{active.value = index,comId.value = item.com
}
const data = reactive([{name:"A组件",com: AVue  //此时的变量是一个组件},{name:"B组件",com: BVue},{name:"C组件",com: CVue}])
</script>
<style scoped>
.active{background: skyblue;
}
.tabs{border: solid 1px #ccc;padding: 5px 10px;margin: 5px;cursor: pointer; /* 鼠标放上去变成小手 */
}
</style>

上面代码可以正常使用,但是在控制台有错误报错,原因就是组件变量导致的。
在这里插入图片描述
错误的引发:他包括了一些组件的信息,这里的属性没有必要去劫持,因此我们需要跳过它,他提供了2个API,第一个是shallowRef(它是代理最外面的一层), 另外一个是markRaw(它是在对象里面,它有一个skip属性,reactive如果碰到这个属性,也会跳过proxy代理)
在这里插入图片描述

错误修复如下:

<script setup lang='ts'>
import { ref,reactive,markRaw,shallowRef } from 'vue'
import AVue from './components/A.vue';
import BVue from './components/B.vue';
import CVue from './components/C.vue';
// 修改错误第一处,使用shallowRef
const comId = shallowRef(AVue)
const active = ref(0)
const switchCom =(item,index:number) =>{active.value = index,comId.value = item.comconsole.log(comId.value)
}
// 修改错误第二处,使用markRaw
const data = reactive([{name:"A组件",com: markRaw(AVue)},{name:"B组件",com: markRaw(BVue)},{name:"C组件",com: markRaw(CVue)}])
</script>

第二种方法:

<template><div style="display: flex;"><div @click="switchCom(item,index)"v-for="(item,index) in data" class="tabs" :class="[active == index ? 'active':'']"><div>{{ item.name }}</div></div></div><component :is="comId"></component>
</template>
<script setup lang='ts'>
import { ref,reactive,shallowRef } from 'vue'// 修改错误第一处,使用shallowRef
const comId = shallowRef('AVue')
const active = ref(0)
const switchCom =(item,index:number) =>{active.value = index,comId.value = item.comconsole.log(comId.value)
}
const data = reactive([{name:"A组件",com: "AVue"},{name:"B组件",com: "BVue"},{name:"C组件",com: "CVue"}])
</script>
<script lang="ts">
import AVue from './components/A.vue';
import BVue from './components/B.vue';
import CVue from './components/C.vue';
export default{components:{AVue,BVue,CVue}
}
</script>
<style scoped>
.active{background: skyblue;
}
.tabs{border: solid 1px #ccc;padding: 5px 10px;margin: 5px;cursor: pointer; /* 鼠标放上去变成小手 */
}
</style>

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

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

相关文章

2024软件测试面试八股文(有答案版),金九银十季,涨薪涨薪_八股文软件测试面试题

因为我们项目的用户活动和三方合作平台比较多&#xff0c;一般半个月或者1个月肯定会有一个迭代版本&#xff0c; 假如用户或者合作方突然有很紧急的需求&#xff0c;那一般老大他们会向上发邮件和OA呈批给(产品经理&#xff0c;项目经理)&#xff0c;如果通过了就会马上加急处…

【Go语言】深入解读Go语言中的指针,助你拨开迷雾见月明

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

《操作系统 - 清华大学》1 -1:操作系统概述 —— 内容概述

文章目录 1. 内容摘要2. 实验内容 1. 内容摘要 在这里对学习内容做一个整体上的介绍&#xff0c;那在这里包括我们要学习的内容&#xff0c;实验的内容。操作系统课涉及到计算机系统当中的资源管理&#xff0c;所以我们围绕着操作系统的实现来介绍相关内容&#xff0c;那主要分…

优化 Go 语言数据打包:性能基准测试与分析

场景&#xff1a;在局域网内&#xff0c;需要将多个机器网卡上抓到的数据包同步到一个机器上。 原有方案&#xff1a;tcpdump -w 写入文件&#xff0c;然后定时调用 rsync 进行同步。 改造方案&#xff1a;使用 Go 重写这个抓包逻辑及同步逻辑&#xff0c;直接将抓到的包通过网…

大势智慧亮相“第十届博博会”,展现数字文旅新质生产力!

2024年8月23日至26日&#xff0c;由国家文物局指导&#xff0c;中国博物馆协会主办的第十届“中国博物馆及相关产品与技术博览会”&#xff08;简称“博博会”&#xff09;在呼和浩特敕勒川国际会展中心成功举办。 呼和浩特敕勒川国际会展中心 大势智慧携数字文旅全栈解决方案以…

SpringBoot框架下的客户管理策略

1 绪论 1.1研究背景 随着网络不断的普及发展&#xff0c;企业客户管理系统依靠网络技术的支持得到了快速的发展&#xff0c;首先要从员工的实际需求出发&#xff0c;通过了解员工的需求开发出具有针对性的首页、个人中心、员工管理、客户信息管理、行业类型管理、项目信息管理、…

新能源汽车充电桩怎么选?

新能源汽车是我国七大战略性新兴产业之一&#xff0c;已成为汽车产业转型升级的重要推动力。毫无疑问。充电桩作为我国新能源汽车产业链下游的重要环节&#xff0c;在国家政策的大力支持和市场需求的带动下&#xff0c;有着非常广阔的前景。安科瑞叶西平187-06160015 新能源汽…

数据结构---顺序表之单链表

1.链表的概念 链表是一种逻辑上是线性的&#xff0c;但物理结构不一定是线性的数据结构&#xff0c;它通过链表中的指针链接次序实现的 链表的存储空间是我们通过动态内存开辟的内存空间&#xff0c;所以他们的地址可能是连续的也可能不是连续的 2.链表的分类 1.单向或者双向…

Footprint Analytics: 我们为何打造 Growthly 这款产品

在 Web3 的领域内&#xff0c;数据已成为新的“财富”。在 Footprint Analytics&#xff0c;我们始终站在区块链数据分析的最前沿&#xff0c;提供全方位的解决方案&#xff0c;为 Web3 生态中的企业和项目简化数据分析的复杂性。然而&#xff0c;随着我们对客户需求及行业趋势…

VLAN原理与接口

在学习之前&#xff0c;先抛出问题&#xff1a;什么是VLAN&#xff1f;VLAN工作原理是什么&#xff1f;VLAN如何配置&#xff1f; VLAN的定义 VLAN&#xff08;Virtual Local Area Network&#xff0c;虚拟局域网&#xff09;是一种在逻辑上将局域网设备从物理上划分的网络技…

一种单目标A*算法设计与实现

一种单目标A*算法设计与实现 作者&#xff1a;吴屏珊 最近在学习简单的单目标A*算法&#xff0c;其中在CSDN上阅读到的一篇博文给了我很大启发&#xff0c;于是在该博文的基础上&#xff0c;笔者记录了一点自己对于A*算法的体会和感悟。原文链接 目录 文章目录 一种单目标A*…

微信接口报错:Http头Authorization中的timestamp与 发起请求的时间不得超过5分钟

在发起请求的时候微信会自己封装一个系统时间 当服务器系统时间与实际实际相差5分钟或者5分钟以上就会出现这个错误 需要修改系统时间 问一下ChatGPT 用自动同步 sudo timedatectl set-ntp true 服务器执行 &#xff0c; 过个一分钟 再查看时间 发现正确 再支付就可以成功…

Spring6梳理11——依赖注入之注入List集合类型属性

以上笔记来源&#xff1a; 尚硅谷Spring零基础入门到进阶&#xff0c;一套搞定spring6全套视频教程&#xff08;源码级讲解&#xff09;https://www.bilibili.com/video/BV1kR4y1b7Qc 11 依赖注入之注入List集合类型属性 11.1 创建实体类Emp以及Dept Dept类中添加了遍历Emp…

Java语法-类和对象(上)

1. 面向对象的初步认识 1.1 什么是面向对象 概念: Java是一门纯面向对象的语言(Object Oriented Program&#xff0c;简称OOP)&#xff0c;在面向对象的世界里&#xff0c;一切皆为对象。 1.2 面向对象VS面向过程 如:洗衣服 面向过程: 注重的是洗衣服的过程,少了一个环节也不…

七层负载均衡和四层负载均衡的区别

文章目录 什么是七层负载均衡&#xff1f;一、定义与工作原理二、优点与缺点三、应用场景四、常见七层负载均衡器五、负载均衡算法 什么是四层负载均衡&#xff1f;一、定义与原理定义&#xff1a;原理&#xff1a; 二、特点与应用场景特点&#xff1a;应用场景&#xff1a; 三…

python类的call方法与init方法

1. call方法 在对象被调用了的时候就会调用call方法a(666) class A:def __call__(self, args):print(call 方法被调用了,args) aA() a(666) 2.init方法 创建对象的时候 init 方法被调用 class A:def __init__(self,args):print(创建对象的时候 init 方法被调用了,args) aA(…

三、LLM应用开发准备工作

LLM应用开发准备工作 开发基础开发工具大模型kx上网key的配置与使用网站结语 开发基础 最好具备一定的Python开发基础&#xff0c;不需要特别深 如果不具备&#xff0c;可以先学习一下基础知识&#xff08;概念&#xff09;&#xff0c;比如Python环境管理、包管理与使用、基本…

城市酷选:如何四年做到3000亿销售额 会员超500w

城市酷选&#xff0c;这一融合了线上线下消费的会员制社交电商平台&#xff0c;正以其独特的运营模式在市场中崭露头角。该平台不仅汇聚了超过600万的会员与60万商家&#xff0c;更实现了年交易额的百亿突破&#xff0c;彰显了其强大的市场影响力和消费者吸引力。 创新排队免单…

必应bing推广kai户流程教学,满足企业获客需求

微软Bing广告提供了三种主要广告类型&#xff0c;可以满足大多数出海企业的展示和客户获取需求。 搜索广告&#xff08;Search Ads&#xff09; 包括标准搜索广告和动态搜索广告。当用户的搜索词与投放的关键词匹配时&#xff0c;相应的搜索广告会被触发&#xff0c;向用户展示…

基于深度学习的数字识别系统的设计与实现(python、yolov、PyQt5)

&#x1f497;博主介绍&#x1f497;&#xff1a;✌在职Java研发工程师、专注于程序设计、源码分享、技术交流、专注于Java技术领域和毕业设计✌ 温馨提示&#xff1a;文末有 CSDN 平台官方提供的老师 Wechat / QQ 名片 :) Java精品实战案例《700套》 2025最新毕业设计选题推荐…