【Vue3】全局组件,递归组件,动态组件,传送组件,缓存组件,异步组件等

news2024/11/18 23:29:31

组件使用

      • 父子组件传参
        • 父传子
          • 模板上直接使用
          • js里面使用
          • ts组件里面泛型接收
          • ts泛型里面设置默认值
        • 子传父
            • 方式一,采用defineEmits
            • 方式二,采用ts的泛型
          • 方式三,采用ref获取子组件内部暴露的数据和方法
            • 子组件先暴露
            • 父组件接收
      • 全局组件
          • 发现有报错,找不到模块“./App.vue”或其相应的类型声明
          • 批量导入组件
      • 可选链
      • 递归组件
          • 步骤一,建立子组件Tree.vue
          • 步骤二,建立父组件展示最终页面
          • 如何设置递归组件名name
          • 防止点击冒泡和传递event对象
      • 动态组件
          • 方式一
          • 方式二。Vue3写法
      • Teleport 传送组件
      • keep-alive缓存组件
          • include
          • enclude
          • max,缓存最多数
          • keep-alive生命周期onActivated和onDeactivated
      • 异步组件
          • Suspense

父子组件传参

  • 父组件通过v-bind绑定一个数据,然后子组件通过defineProps接受传过来的值
父传子
模板上直接使用
<template>
  <div class="main">
    <div class="vt-test">子组件</div>
    <div>{{ title }}</div>
  </div>
</template>

<script setup lang="ts">
//接受父组件传过来的值
defineProps({
  title: {
    type: String,
    default: '默认值',
  },
});
</script>
js里面使用
// 接受父组件传过来的值;
const props = defineProps({
  title: {
    type: String,
    default: '默认值',
  },
});
console.log('父组件传过来的值', props.title);
ts组件里面泛型接收
//ts模式下接收采取泛型更方便
const prop = defineProps<{
  title: string;
}>();
console.log('父组件传过来的值', prop.title);
ts泛型里面设置默认值
//ts模式下设置默认值
const prop = withDefaults(
  defineProps<{
    title: string;
    arr: number[];
  }>(),
  {
    arr: () => [1, 2, 3],
  }
);
console.log('父组件传过来的值', prop.title);
子传父
方式一,采用defineEmits
  • 子组件
<template>
  <div class="main">
    <div class="vt-test">子组件</div>
    <button @click="send">点击给父组件传值</button>
  </div>
</template>

<script setup lang="ts">
//给父组件传值采用defineEmits
const emit = defineEmits(['on-click','on-getname']);
const send = () => {
  emit('on-click', '花神');
  emit('on-getname', '花神');
};
</script>
  • 父组件
<template>
  <div class="vt-parents">父组件</div>
  <hr />
  <Helloworld :title="name" @on-click="getclick" @on-getname='getName'></Helloworld>
</template>

<script setup lang="ts">
import Helloworld from './components/HelloWorld.vue';
const name = '花神';
const getName = (value) => {
  console.log(value, '子组件传的值');
};
</script>
  • 子组件传多个事件
//给父组件传值采用defineEmits
const emit = defineEmits(['on-click', 'on-getname']);
const send = () => {
  emit('on-click', '花神');
  emit('on-getname', '花神2');
};
const getname = () => {
  emit('on-getname', '花神2');
};
方式二,采用ts的泛型
<script setup lang="ts">
//给父组件传值采用defineEmits
//有没有返回值,没有返回值定义void,不加也不报错
const emit = defineEmits<{
  (e: 'on-click', value: string): void;
  (e: 'on-getname', value: string): void;
}>();
const send = () => {
  emit('on-click', '花神');
};
const getname = () => {
  emit('on-getname', '花神2');
};
</script>
方式三,采用ref获取子组件内部暴露的数据和方法
子组件先暴露
  • defineExpose
    在这里插入图片描述
父组件接收
  • 类型检测<InstanceType>不写也行

全局组件

  • 在main.ts文件里导入组件并挂载在全局中

在这里插入图片描述

  • 页面上直接使用即可
    在这里插入图片描述
发现有报错,找不到模块“./App.vue”或其相应的类型声明

在这里插入图片描述

  • 解决思路:在项目根目录 env.d.ts 文件中,加入以下内容:
/// <reference types="vite/client" />
declare module "*.vue" {
  import type { DefineComponent } from "vue"
  const vueComponent: DefineComponent<{}, {}, any>
  export default vueComponent
}
批量导入组件
  • 想一次性全部导入模块的所有变量就可以使用 * as 代表全部
  • Object.entries() ,将一个对象中可枚举属性的键名和键值按照二维数组的方式返回
    在这里插入图片描述

可选链

  • 单问号,没有值返回undefined
  • 双问号,只判断undefined和null,0和false不处理
    在这里插入图片描述

递归组件

  • 简单来说就是在组件中内使用组件本身
  • 一般用来实现树形菜单,多级菜单
  • 注意的是:要防止无限递归,造成调用栈溢出
步骤一,建立子组件Tree.vue
<template>
  <div class="main" v-for="(item, index) in data" :key="index">
    <input type="checkbox" v-model="item.checked" /><span>{{ item.name }}</span>
    <Tree v-if="item?.children?.length" :data="item?.children"></Tree>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive } from 'vue';
//定义接收的数据类型
interface Tree {
  name: string;
  checked: boolean;
  children?: Tree[];
}
defineProps<{ data?: Tree[] }>();
</script>

<style scoped>
.main {
  margin-left: 30px;
}
</style>

步骤二,建立父组件展示最终页面
<template>
  <div class="main"></div>
  <TreeVal :data="data"></TreeVal>
</template>

<script setup lang="ts">
import { ref, reactive } from 'vue';
import TreeVal 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,
        children: [
          {
            name: '1-1-1',
            checked: false,
            children: [],
          },
        ],
      },
    ],
  },
  {
    name: '2',
    checked: false,
    children: [],
  },
]);
</script>

<style scoped></style>
  • 最终展示页面
    在这里插入图片描述
如何设置递归组件名name
  • 方式一:可以采用文件名本身
    在这里插入图片描述
  • 方式二:可以页面内再建script里自定义组件名
    在这里插入图片描述
  • 方式三:通过插件

在这里插入图片描述

防止点击冒泡和传递event对象

在这里插入图片描述

动态组件

  • 让多个组件使用同一个挂载点,并动态切换
  • 在挂载点使用component标签,然后使用v-bind :is=”组件“
方式一
<template>
  <div v-for="(item, index) in com" :key="index">
    <div>{{ item.name }}</div>
    <component :is="item.com"></component>
  </div>
</template>

<script lang="ts">
import A from './components/A.vue';
import B from './components/B.vue';
import C from './components/C.vue';

export default {
  components: {
    A,
    B,
    C,
  },
};
</script>
<script setup lang="ts">
import { ref, reactive } from 'vue';
//区别,此时使用的时候是字符串形式
const com = reactive([
  { name: 'A组件', com: "A" },
  { name: 'B组件', com: "B" },
  { name: 'C组件', com: "C" },
]);
</script>
方式二。Vue3写法
<template>
  <div v-for="(item, index) in com" :key="index">
    <div>{{ item.name }}</div>
    <component :is="item.com"></component>
  </div>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue';
import A from './components/A.vue';
import B from './components/B.vue';
import C from './components/C.vue';
//这边直接使用
const com = reactive([
  { name: 'A组件', com: A },
  { name: 'B组件', com: B },
  { name: 'C组件', com: C },
]);
</script>
  • 虽然展示,但有报错
    在这里插入图片描述
  • 使用markRaw,到时候会多一个skip属性,reactive碰到这个属性,会跳过proxy代理
<script setup lang="ts">
import { ref, reactive, markRaw } from 'vue';
import A from './components/A.vue';
import B from './components/B.vue';
import C from './components/C.vue';

const com = reactive([
  { name: 'A组件', com: markRaw(A) },
  { name: 'B组件', com: markRaw(B) },
  { name: 'C组件', com: markRaw(C) },
]);
</script>

Teleport 传送组件

  • Teleport是一种能够将我们的模板渲染至指定Dom节点,不受父级style,v-show等属性影响
  • 但data,prop数据依旧能够共用的技术
  • 主要为了解决,使Teleport节点挂载在其他指定的节点下,完全不受父级style样式的影响
  • 例如:想要将子组件的这个弹窗挂载到外层
    在这里插入图片描述
  • 使用Teleport ,to挂载到想要展示的层级
<template>
  <div class="main">
    <h3>子组件</h3>
    <!-- disabled设置为true,则to不生效,否则生效 -->
    <Teleport to="body" :disabled="true	">
      <div class="box">弹窗</div>
    </Teleport>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive } from 'vue';
</script>

<style scoped lang="less">
.main {
  position: relative;
  width: 500px;
  height: 30vh;
  margin-left: 30px;
  background: #888;
}
.box {
  background: yellow;
  width: 200px;
  height: 200px;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
</style>

在这里插入图片描述

keep-alive缓存组件

  • 注意,keep-alive里面只能有一个子节点,不能放多个,多个的话需要if条件判断只显示一个
  • 有时候不希望组件被重新渲染影响使用体验,或者处于性能考验,避免多次重复渲染
  • 目的,想要切换组件的时候,将我之前输入的值保留
    在这里插入图片描述
include
  • 缓存name匹配上的
  • 在vue3中,组件内部的组件name需要重新写,setup的语法糖不支持
  • 子组件
<template>
  <div class="main">
    <h3>子组件</h3>
    <Teleport to="body" :disabled="true">
      <div class="box">弹窗</div>
    </Teleport>
    <input type="text" />
  </div>
</template>

<script setup lang="ts">
import { ref, reactive } from 'vue';
</script>
//重写name,为了在父组件可以使用include缓存Avue
<script lang="ts">
export default {
  name: 'Avue',
};
</script>

  • 父组件
<template>
  <div class="main">
    <!-- include,只缓存名字匹配的,例如,这次只缓存Avue,Bvue不缓存-->
    <keep-alive :include="['Avue']">
      <Avue v-if="istrue"></Avue>
      <Bvue v-else></Bvue>
    </keep-alive>
    <button @click="change">切换</button>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive } from 'vue';
import Avue from './components/A.vue';
import Bvue from './components/B.vue';
let istrue = ref('true');
const change = () => {
  istrue.value = !istrue.value;
};
</script>

<style scoped></style>

enclude
  • 不缓存name匹配上的
max,缓存最多数
  • 超出max,会剔除旧的,不活跃的,保留新组件进行缓存
keep-alive生命周期onActivated和onDeactivated
  • 初始化只会走一次
  • 子组件
<template>
  <div class="main">
    <h3>子组件</h3>
    <Teleport to="body" :disabled="true">
      <div class="box">弹窗</div>
    </Teleport>
    <input type="text" />
  </div>
</template>

<script setup lang="ts">
import {
  ref,
  reactive,
  onMounted,
  onUnmounted,
  onActivated,
  onDeactivated,
} from 'vue';
onMounted(() => {
  console.log('初始化');
});
onActivated(() => {
  console.log('keeplive缓存生命周期初始化');
});
onDeactivated(() => {
  console.log('keeplive缓存生命周期卸载');
});
onUnmounted(() => {
  console.log('卸载');
});
</script>
<script lang="ts">
export default {
  name: 'Avue',
};
</script>
  • 刚进入

在这里插入图片描述

  • 切换后
    在这里插入图片描述
  • 切回来
    在这里插入图片描述

异步组件

  • defineAsyncComponent加载异步组件
  • 大型应用中,需要将应用分割成小一些的代码块,并且减少主包的体积
<template>
  <div class="main">
    <Suspense>
      <template #default>
          <Syncvue></Syncvue>
      </template>
      <template #fallback>
        <!-- 放置骨架屏等 -->
      </template>
    </Suspense>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive,defineAsyncComponent} from 'vue';
const Syncvue =defineAsyncComponent(()={import('@/components/sync.vue')})
</script>

<style scoped></style>

Suspense
  • 它帮助我们处理异步组件,但它的作用远不止于此
  • 我们可以将异步组件的加载状态和占位内容进行统一管理。当异步组件加载完成时,会自动替换占位内容,从而实现平滑的过渡效果
  • Suspense 允许我们协调整个应用程序的加载状态,而不是一个页面上到处都是 loading
  • Suspense,把异步组件放入 default 槽,把回退加载状态放入 fallback 槽。
  • Suspense 机制还提供了错误处理的能力。当异步组件加载出错时,可以显示自定义的错误信息,以便及时通知用户
<template>
  <Suspense>
    <template v-slot:default>
      <div>Loading...</div>
    </template>

    <template v-slot:error>
      <div>Failed to load component.</div>
    </template>

    <Syncvue />
  </Suspense>
</template>

<script>
import { defineAsyncComponent } from 'vue';

const Syncvue =defineAsyncComponent(()={import('@/components/sync.vue')})

export default {
  components: {
    Syncvue ,
  },
};
</script>

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

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

相关文章

云原生精品资料合集(附下载)

云计算是产业数字化转型的关键基础设施,以基础设施资源为中心的云搬迁时代接近尾声&#xff0c;以应用价值为中心的云原生时代已经到&#xff0c;所以IT人员学习云原生正当时&#xff01;最近跟各位大神征集了云原生的教程&#xff0c;行业报告和最佳实践&#xff0c;总有一款适…

【软考】UML中的图之通信图

目录 1. 说明2. 图示3. 特性4. 例题4.1 例题1 1. 说明 1.通信图强调收发消息的对象的结构组织2.早期版本叫做协作图3.通信图强调参加交互的对象和组织4.首先将参加交互的对象作为图的顶点&#xff0c;然后把连接这些对象的链表示为图的弧&#xff0c;最后用对象发送和接收的消…

『Linux从入门到精通』第 ㉑ 期 - 文件系统详解

文章目录 &#x1f490;专栏导读&#x1f490;文章导读&#x1f427;认识磁盘&#x1f427;逻辑抽象&#x1f427;文件系统&#x1f426;Block&#x1f426;Block Group&#x1f414;Block Group 的组成部分 &#x1f426;Superblock(超级区块)&#x1f426;Group Description(…

FRM模型十二:极值理论

目录 极值理论介绍GEVPOT 代码实现 极值理论介绍 在风险管理中&#xff0c;将事件分为高频高损、高频低损、低频高损、低频低损。其中低频高损是一种非常棘手的损失事件&#xff0c;常出现在市场大跌、金融体系崩溃、金融危机以及自然灾害等事件中。 由于很难给极端事件一个准…

如何解决局域网tcp延迟高来进行安全快速内外网传输呢?

在当今企业运营中&#xff0c;数据的快速流通变得至关重要&#xff0c;但局域网内的TCP延迟问题却成为了数据传输的障碍。本文旨在分析局域网TCP延迟的成因&#xff0c;并探讨几种企业数据传输的常见模式&#xff0c;以及如何为企业选择合适的传输策略&#xff0c;以确保数据在…

简单求和计算器

其实对于计算器的写法在C语言阶段就已经有了&#xff0c;但是&#xff0c;在目前阶段《前后端交互》&#xff0c;这算是一种全新的写法&#xff0c;毕竟将数据从前端返回给后端&#xff0c;然后再将数据返回给前端&#xff0c;都涉及到一些参数的交互&#xff0c;值得我们学习深…

[CISCN2019 华北赛区 Day2 Web1]Hack World 1 题目分析与详解

一、分析判断 进入靶机&#xff0c;主页面如图&#xff1a; 主页面提供给我们一条关键信息&#xff1a; flag值在 表flag 中的 flag列 中。 接着我们尝试输入不同的id&#xff0c;情况分别如图&#xff1a; 当id1时&#xff1a; 当id2时&#xff1a; 当id3时&#xff1a; 我…

博弈论---Nim游戏(公平组合游戏,概念,证明异或为0就是必败态,示例)

目录 概念&#xff1a; 公平组合游戏ICG 有向图游戏 Nim游戏 先手&#xff09;必胜状态 先手&#xff09;必败状态 如何确定先手是否必胜或者必败&#xff08;都采用最优策略&#xff09; 证明&#xff1a;全部异或为0则是必败状态 综上&#xff1a; 例子 概念&#…

OJ_二叉树已知先序遍历序列(有空叶子)求中序遍历序列

题干 C实现 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<vector> using namespace std;struct TreeNode {char data;TreeNode* left;TreeNode* right; };TreeNode* RecursiveBuildTree(int& i, char str[]) {char c str[i];i;if (c #) {re…

红队基础设施建设

文章目录 一、ATT&CK二、T1583 获取基础架构2.1 匿名网络2.2 专用设备2.3 渗透测试虚拟机 三、T1588.002 C23.1 开源/商用 C23.1.1 C2 调研SliverSliver 对比 CS 3.1.2 CS Beacon流量分析流量规避免杀上线 3.1.3 C2 魔改3.1.4 C2 隐匿3.1.5 C2 准入应用场景安装配置说明工具…

【开源】JAVA+Vue.js实现桃花峪滑雪场租赁系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 游客服务2.2 雪场管理 三、数据库设计3.1 教练表3.2 教练聘请表3.3 押金规则表3.4 器材表3.5 滑雪场表3.7 售票表3.8 器材损坏表 四、系统展示五、核心代码5.1 查询教练5.2 教练聘请5.3 查询滑雪场5.4 滑雪场预定5.5 新…

掌握Python操作Word:从基础到高级全覆盖

掌握Python操作Word&#xff1a;从基础到高级全覆盖 引言Python操作Word的基础文档的创建与打开文档的基本操作 创建和打开Word文档创建新的Word文档打开现有文档读取文档内容修改现有文档 编辑文档内容添加和编辑文本设置格式插入标题 处理文档结构操作段落列表的处理表格的操…

Linux Shell脚本练习(三)

1、测试用户名与密码是否正确。 2、输出1-1000内的素数。 3、对 100 以内的所有正整数相加求和(1234...100)。 4、输出9*9 乘法表。 5、编写脚本,显示进度条。 、 6、输入三个数并进行升序排序

Linux-nginx服务

一.Nginx概述 1.定义 一款高新能、轻量级Web服务软件 系统资源消耗低 对HTTP并发连接的处理能力高 单台物理服务器可支持30 000&#xff5e;50 000个并发请求。 2.Nginx模块作用 &#xff08;1&#xff09;main模块 全局配置模块&#xff0c;所有模块都要执行遵守&#xf…

Mac 制作可引导安装器

Mac 使用U盘或移动固态硬盘制作可引导安装器&#xff08;以 Monterey 为例&#xff09; 本教程参考 Apple 官网相关教程 创建可引导 Mac OS 安装器 重新安装 Mac OS 相关名词解释 磁盘分区会将其划分为多个单独的部分&#xff0c;称为分区。分区也称为容器&#xff0c;不同容器…

前端 JS 经典:Content-type 详解

1. 什么是 Content-Type Content-Type 是 HTTP 协议中的一个请求头或响应头字段&#xff0c;用于指示发送或接收的实体的媒体类型&#xff0c;告诉服务器或客户端如何解析和处理请求或响应的主体部分。 2. Content-Type 的构成 Content-Type 由两部分组成&#xff1a;媒体类型…

大数据可视化python01

import pandas as pd import matplotlib.pyplot as plt# 设置中文改写字体 plt.rcParams[font.sans-serif] [SimHei]# 读取数据 data pd.read_csv(C:/Users/wzf/Desktop/读取数据进行数据可视化练习/实训作业练习/瓜果类单位面积产量.csv ,encoding utf-8)#输出 print(data)…

高精度加法和动态规划综合运用

高精度加法的原理与手工相加类似&#xff0c;只是在计算时需要考虑到进位和处理较大的数字。下面是实现高精度加法的基本原理&#xff1a; 表示数字&#xff1a; 高精度加法通常通过字符串来表示数字&#xff0c;因为字符串没有固定长度限制&#xff0c;可以容纳任意大的数字。…

【tableau学习笔记】tableau无法连接数据源

【tableau学习笔记】tableau无法连接数据源 背景&#xff1a; 学校讲到Tableau&#xff0c;兴奋下载Kaggle Excel&#xff0c;一看后缀CSV&#xff0c;导入Tableau发现报错“tableau无法连接数据源”&#xff0c;自作聪明改为后缀XLSX&#xff0c;bug依旧。 省流&#xff1a…

Docker容器(3)单容器管理与

一、单容器 1.1概念简介 Docker三个重要概念: 仓库(Repository); 镜像(Image); 容器(Container). *Docker的三个重要概念是仓库(Repository)、镜像(Image)和容器(Container)**。具体如下&#xff1a; **镜像(Image)**&#xff1a;Docker镜像是创建容器的基础&#xff0c;它类似…