Vue3+TS项目 - ref和useTemplateRef获取组件实例

news2024/11/29 20:34:52

        在Vue2中,子组件使用的是选项式 API ,被引用的组件实例和该子组件的 this 完全一致,这意味着父组件对子组件的每一个属性和方法都有完全的访问权。这使得在父组件和子组件之间创建紧密耦合的实现细节变得很容易,当然也因此,应该只在绝对需要时才使用组件引用。大多数情况下,你应该首先使用标准的 props 和 emit 接口来实现父子组件交互。

        而在Vue3中,子组件使用<script setup>的组件是默认私有的:一个父组件无法访问到一个使用了 <script setup> 的子组件中的任何东西,除非子组件在其中通过 defineExpose 宏显式暴露。

一、创建子组件(表格)

        在项目目录src/components目录中创建TableNormal.vue组件,并且通过defineExpose对外暴露父组件可以调用的函数。代码如下:

<template>
  <div class="table-wrap">
    <!-- table-wrap -->
    <div class="table-wrap">
      <el-table ref="table" border :data="tableData">
        <el-table-column type="selection" width="55" fixed></el-table-column>
        <el-table-column type="index" label="序号" width="50px" :resizable="false"></el-table-column>
        <template v-for="(item, index) in tableColumns">
            <el-table-column :prop="item.prop" :label="item.label" :key="'' + index"></el-table-column>
        </template.
      </el-table>
    </div>
    <!-- /table-wrap -->
  </div>
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue';
defineOptions({
  name: "Table-Normal"
})
type TableColumnsType = {
    label: string,
    prop: string
}
const tableColumns = ref<Array<TableColumnsType>>([])       // 列数据
const tableData = ref<Array<any>>([])                       // 行数据
const page = ref(1)
const pageSize = ref(5)
const pageTotal = ref(0)

const onLoadTableColumns = () => {
  // 通过Axios API接口获取tableColumns 表格列数据
}

const onLoadTableData = () => {
  // 通过Axios API接口获取tableData 表格行数据
}

onMounted(() => {
  onLoadTableColumns()
  onLoadTableData()
})

// 对外暴露onLoadTableData函数
defineExpose({onLoadTableData})
</script>

二、创建父组件(Department)

        在项目src/views目录中,创建Department.vue文件。示例代码如下:

<template>
  <div>
    <table-normal></table-normal>
    <button @click="() => valueChange()">重新加载</button>
  </div>
</template>
<script lang="ts" setup>
// 重新加载
const valueChange = () => {

}
</script>

2.1 ref获取组件实例

        通过ref获取组件实例后,则可以通过实例对象的变量,去调用子组件中对外暴露的变量或函数了。

<template>
  <div>
    <table-normal ref="tableNormalRef"></table-normal>
    <button @click="() => valueChange()">重新加载</button>
  </div>
</template>
<script lang="ts" setup>
import { ref} from "vue";
const tableNormalRef = ref(null) 

// 重新加载
const valueChange = () => {
  if(tableNormalRef.value && tableNormalRef.value.onLoadTableData) 
    tableNormalRef.value.onLoadTableData()
}
</script>

三、解决问题 - 类型断言

        当父组件Department.vue中,通过ref获取自定义表格组件实例,并且在子组件中已通过defineExpose对外暴露了onLoadTableData函数,所以我们可以通过实例变量直接调用onLoadTableData()函数。

if(tableNormalRef.value && tableNormalRef.value.onLoadTableData) 
    tableNormalRef.value.onLoadTableData()

3.1 "never"断言

        但是调用后,会提示如下截图上的断言提示【错误提示:类型“never”上不存在属性“onLoadTableData”。】。

        在TypeScript中,当一个变量被推断为never类型时,这意味着变量从逻辑上不应该存在任何值。所以需要在获取实例时,告诉ref该实例的类型。

        由于ref获取自定义组件为DOM元素,所以将其类型指定为HTMLElement,代码如下:

<template>
  <div>
    <table-normal ref="tableNormalRef"></table-normal>
    <button @click="() => valueChange()">重新加载</button>
  </div>
</template>
<script lang="ts" setup>
import { ref} from "vue";
const tableNormalRef = ref<HTMLElement | null>(null)

// 重新加载
const valueChange = () => {
  if(tableNormalRef.value && tableNormalRef.value.onLoadTableData) 
    tableNormalRef.value.onLoadTableData()
}
</script>

3.2 onLoadTableData不存在

        添加HTMLElement后,never类型断言问题是消失了,但随之而来又有新问题【错误:属性“onLoadTableData”在类型“HTMLElement”上不存在。你是否指的是“onloadeddata”?

        这是由于onLoadTableData为自定义函数,在HTMLElement类型中并不存上在,所以我们需要重新定义一个新接口类型,并继承HTMLElement类型即可。代码如下:

<template>
  <div>
    <table-normal ref="tableNormalRef"></table-normal>
    <button @click="() => valueChange()">重新加载</button>
  </div>
</template>
<script lang="ts" setup>
import { ref} from "vue";
// 定义新接口类型
interface LoadTableDataElement extends HTMLElement {
  onLoadTableData: () => void
}
const tableNormalRef = ref<LoadTableDataElement | null>(null)

// 重新加载
const valueChange = () => {
  if(tableNormalRef.value && tableNormalRef.value.onLoadTableData) 
    tableNormalRef.value.onLoadTableData()
}
</script>

        此时VSCode中波浪线不存在了。

3.3 null类型

        在通过ref获取组件实例中,有可能出现组件实例未获取到的情况(即为null类型),所以在valueChange函数中调用前,需判断其是否存在,再调用。否则会报错【错误提示:“tableNormalRef.value”可能为 “null”。

四、useTemplateRef

        模板引用也可以被用在一个子组件上,这种情况下引用中获得的值是组件实例。

4.1 新特性获取组件实例

        在前面讲了,使用ref方式获取组件实例,但在3.5版本后,可以通过新特性useTemplateRef来获取模板中的组件实例。我们将上面示例代码稍作修改,代码如下:

<template>
  <div>
    <table-normal ref="tableNormalRef"></table-normal>
    <button @click="() => valueChange()">重新加载</button>
  </div>
</template>
<script lang="ts" setup>
import { ref} from "vue";
// 定义新接口类型
interface LoadTableDataElement extends HTMLElement {
  onLoadTableData: () => void
}
const tableNormalRef = useTemplateRef('tableNormalRef')

// 重新加载
const valueChange = () => {
  if(tableNormalRef.value && tableNormalRef.value.onLoadTableData) 
    tableNormalRef.value.onLoadTableData()
}
</script>

4.2 类型断言处理

        使用useTemplateRef时,也会出现类型断言问题,此时上述代码会提示如下错误【类型“{}”上不存在属性“onLoadTableData”。】。

        此时,我们3.2中定义的新接口类型,指定给useTemplateRef即可,代码如下:

<template>
  <div>
    <table-normal ref="tableNormalRef"></table-normal>
    <button @click="() => valueChange()">重新加载</button>
  </div>
</template>
<script lang="ts" setup>
import { ref} from "vue";
// 定义新接口类型
interface LoadTableDataElement extends HTMLElement {
  onLoadTableData: () => void
}
const tableNormalRef = useTemplateRef<LoadTableDataElement>('tableNormalRef')

// 重新加载
const valueChange = () => {
  if(tableNormalRef.value && tableNormalRef.value.onLoadTableData) 
    tableNormalRef.value.onLoadTableData()
}
</script>

        在开发中,当遇到各种问题时,认真阅读错误提示,并根据问题逐一排查,相信大多情况能很快定位到问题,并得到解决的。

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

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

相关文章

java相关新技术

Java作为一种广泛应用的编程语言&#xff0c;其新技术层出不穷&#xff0c;为开发者提供了更多的工具和框架来构建高效、可扩展的应用程序。以下是一些当前比较热门的Java新技术 Java 17及更高版本&#xff1a; Java平台持续更新&#xff0c;每个新版本都带来了性能改进和新特…

C++学习笔记之类对象(一)

C学习笔记之类&对象&#xff08;一&#xff09; https://www.runoob.com/cplusplus/cpp-classes-objects.html 类是C的核心特性&#xff0c;为用户自定义的数据类型&#xff0c;可以在其中放入数据和函数作为成员&#xff0c;并且以此为模板&#xff0c;创建多个对象个体进…

三维世界的魅力:探索开源的Three.js案例

三维世界的魅力&#xff1a;探索开源的Three.js案例 原生Three.js 和 Cesium.js 案例 - 不断 - 只做开源 。 引言 在这个数字化时代&#xff0c;三维技术已经成为我们生活中不可或缺的一部分。无论是在游戏、电影制作、建筑设计还是虚拟现实中&#xff0c;三维技术都发挥…

ARM Assembly: 第8课 branching

branch causes a branch to a target address. The "B" mnemonic signifies an unconditional branch. 单个的B表示进入一个无条件的分支&#xff0c;而含条件的分支通常可以基于APSR 条件flag进行指令的执行。比如&#xff0c;基于condition flag z是否为1, 我们可…

深度学习基础—目标定位与特征点检测

1.目标定位 &#xff08;1&#xff09;定义 目标定位就是在图片中&#xff0c;定位对象的位置&#xff0c;对于对象的位置可以用框圈住显示。如下图所示&#xff1a; 假设正在进行图片分类工作&#xff0c;那么这个汽车图片很有可能被分类为汽车类别。对于目标定位&#xff0c;…

[图形学]smallpt代码详解(1)

一、简介 本文介绍了著名的99行代码实现全局光照的光线跟踪代码smallpt。 包括对smallpt的功能介绍、编译运行介绍&#xff0c;和对代码的详细解释。希望能够帮助读者更进一步的理解光线跟踪。 二、smallpt介绍 1.smallpt是什么 smallpt(small Path Tracing) 是一个全局光照…

C# List遍历元素重新赋值问题

需求&#xff1a;修改List<string>类型的链表的每一个string对象。 第一反应是List.ForEach&#xff0c;但是使用完后&#xff0c;原链表还是原链表&#xff1b; 后来又学习了一下&#xff0c;了解到C#用foreach语句对数组进行遍历,只能采用只读的方式,不能修改任何元素…

探索Kimi:用Spring Boot + Vue打造现代网站

在数字化时代&#xff0c;网站成为了企业和个人展示自己的窗口。今天&#xff0c;我将带你一起探索如何利用Spring Boot和Vue.js这两个强大的技术栈&#xff0c;结合Kimi的智能助手功能&#xff0c;来构建一个现代的网站。这不仅是一个技术分享&#xff0c;更是一次实战演示&am…

一个信号量操作的例子

代码&#xff1a; #include<stdio.h> #include<sys/sem.h> #include<sys/ipc.h> #include<errno.h> #include<string.h> typedef int sem_t; union semun{ int val; struct semid_ds *buf; unsigned short *array; }arg;sem_t CreateSem(key_t …

【Qt】控件概述 (1)—— Widget属性

控件概述 1. QWidget核心属性1.1核心属性概述1.2 enable1.3 geometry——窗口坐标1.4 window frame的影响1.4 windowTitle——窗口标题1.5 windowIcon——窗口图标1.6 windowOpacity——透明度设置1.7 cursor——光标设置1.8 font——字体设置1.9 toolTip——鼠标悬停提示设置1…

IDEA中用过git之后文件名颜色全变红

在File->Settings->Version Control里点击左下角的号&#xff0c; 选择<none> 之后点击Apply即可恢复之前的颜色

11.1 Linux_线程_线程相关函数

概述 线程的共享资源&#xff1a; 可执行的指令、静态数据、文件描述符、当前工作目录、用户ID、用户组ID 线程的私有资源&#xff1a; 线程ID、程序计数器PC和相关寄存器、堆栈、错误号、优先级、执行状态和属性 线程编译&#xff1a; gcc <.c文件> -l pthread -o…

代码随想录 | Day26 | 二叉树:二叉搜索树中的插入操作删除二叉搜索树中的节点修剪二叉搜索树

代码随想录 | Day26 | 二叉树&#xff1a;二叉搜索树中的插入操作&&删除二叉搜索树中的节点&&修剪二叉搜索树 主要学习内容&#xff1a; 二叉搜索树的插入删除操作 701.二叉搜索树中的插入操作 701. 二叉搜索树中的插入操作 - 力扣&#xff08;LeetCode&…

企业级数据备份一般都是怎么做的?来唠唠嗑

小白最近去了很多企业看了一下他们的存储方案&#xff0c;基本上都是单硬盘数据存储&#xff0c;一个硬盘10TB&#xff08;实际可用8TB左右&#xff09;。 这些大概是大部分微小企业存储数据的办法&#xff0c;也是他们能想到的最好办法了吧。 截至2024年的今天&#xff0c;咱…

MATLAB|基于多主体主从博弈的区域综合能源系统低碳经济优化调度

目录 主要内容 程序亮点&#xff1a; 模型研究 一、综合能源模型 二、主从博弈框架 部分代码 结果一览 下载链接 主要内容 程序参考文献《基于多主体主从博弈的区域综合能源系统低碳经济优化调度》&#xff0c;采用了区域综合能源系统多主体博弈协同优化方…

vim 操作

vim编辑器的有三种工作模式&#xff1a;命令模式、插入模式和底行命令模式 打开进入命令模式&#xff1a; 由命令模式到输入模式&#xff1a;i:在光标前插&#xff1b;a:在光标后插&#xff1b;o:在下一行插 由输入模式进入命令模式&#xff1a;esc 由命令模式进入底行命令…

判断推理(2)

集合推理: 这是不能串在一起的&#xff0c;再进行合并推理的时候有的一定要放在开头 D D 第二句属于真假推理 然后进行翻译推理的时候一定要让有的打头&#xff0c;所以让1或者是2打头&#xff0c;但是1如果是最开头的话那么就什么也推不出来&#xff0c;所以只能是2打头B B A…

Pikachu-Cross-Site Scripting-xss之htmlspecialchars

首先输入各种字符 查看页面元素&#xff0c;可以看到这里对一些符号做了转换&#xff0c;但是 单引号等几个符号没处理&#xff1b; 从代码上看&#xff1b;使用单引号做闭合&#xff1b; 构造payload a onclickalert(11) 提交&#xff0c;得到xss攻击

【Java】springboot 项目中出现中文乱码

在刚创建的springboot项目中&#xff0c;出现乱码&#xff0c;跟走着解决一下 1、Ctrl Shift S 打开idea设置&#xff0c;根据图片来&#xff0c;将③④这三个地方都修改为UTF-8 2、返回配置查看&#xff0c;解决

僵尸进程、孤儿进程和守护进程

让我们详细讨论僵尸进程、孤儿进程和守护进程。 1. 僵尸进程 (Zombie Process) 定义: 僵尸进程是指一个已经终止执行&#xff08;结束运行&#xff09;&#xff0c;但其父进程尚未对其进行清理&#xff08;调用wait()或waitpid()系统调用来获取子进程的退出状态&#xff09;的…