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

devtools/2024/9/24 19:05:20/

一、局部组件

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

<template><div class="card"><header><div>标题</div><div>副标题</div></header><section>内容</section></div>
</template>
<script setup lang='ts'>javascript">
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'>javascript">
//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'>javascript">
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'>javascript">
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'>javascript">
import { ref,reactive } from 'vue'
interface Tree{name:string,checked: boolean,children?: Tree[]
}
defineProps<{datas?:Tree[]
}>()
</script>
<script lang="ts">javascript">
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'>javascript">
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'>javascript">
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'>javascript">
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'>javascript">
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">javascript">
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.ppmy.cn/devtools/116628.html

相关文章

sklearn特征选取之SelectFromModel

sklearn.feature_selection.SelectFromModel 是一种基于模型的重要性权重进行特征选择的工具&#xff0c;允许我们根据学习器的权重或特征重要性自动选择特征。它通过从模型中提取特征的重要性来选择特征&#xff0c;常用于与那些具有 coef_ 或 feature_importances_ 属性的模型…

LeetCode[中等]

给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 思路&#xff1a; 计算链表长度num&#xff0c;num - n就是需要删去结点的索引 其中若删去第一个结点&#xff0c;返回head.next; /*** Definition for singly-linked list.* public …

电商安全新挑战:筑起数字防御长城,守护业务与数据安全

在当今这个数字化时代&#xff0c;电商行业正以前所未有的速度发展&#xff0c;大数据、人工智能等技术的融入不仅重塑了消费模式&#xff0c;更激发了行业新的增长点。然而&#xff0c;这片繁荣景象之下&#xff0c;隐藏着一个不容忽视的暗流——网络安全威胁。从数据泄露到恶…

Spring Boot框架在高校心理辅导中的实践

2 相关技术简介 2.1Java技术 Java是一种非常常用的编程语言&#xff0c;在全球编程语言排行版上总是前三。在方兴未艾的计算机技术发展历程中&#xff0c;Java的身影无处不在&#xff0c;并且拥有旺盛的生命力。Java的跨平台能力十分强大&#xff0c;只需一次编译&#xff0c;任…

npm install --force or --legacy-peer-deps

这个命令中的 --force 和 --legacy-peer-deps 是用于控制包管理器&#xff08;如 npm 或 yarn&#xff09;在安装依赖时的行为的选项。 --force --force 选项通常用于强制包管理器执行某些操作&#xff0c;即使这可能会导致一些不期望的副作用。在安装依赖时&#xff0c;使用…

Spring MVC 基本配置步骤 总结

1.简介 本文记录Spring MVC基本项目拉起配置步骤。 2.步骤 在pom.xml中导入依赖&#xff1a; <dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>6.0.6</version><scope>…

基于Java+SpringBoot+vue+elementUI私人健身教练预约管理系统设计实现

基于JavaSpringBootvueelementUI私人健身教练预约管理系统设计实现 &#x1f345; 作者主页 网顺技术团队 &#x1f345; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; &#x1f345; 文末获取源码联系方式 &#x1f4dd; &#x1f345; 查看下方微信号获取联系方式 承接…

Unity从2018.1版本开始,可以采用内置JSON进行存档和读档

在Unity中&#xff0c;将数据转换为JSON格式并存储在Application.persistentDataPath路径下&#xff0c;是一个常见的需求&#xff0c;用于保存游戏设置、玩家进度等数据。以下是一个简单的步骤和示例代码&#xff0c;展示如何实现这一过程&#xff1a; 那么UnityEngine类下面…