VueJS 之模板引用

news2024/11/16 7:26:08

文章目录

  • 参考
  • 描述
  • 模板引用
      • 引用
      • 访问模板引用
      • 组件中的模板引用
  • $nextTick()
      • 示例
      • updated
          • 错误示范
          • 正确演示
      • $nextTick()

参考

项目描述
搜索引擎Bing
哔哩哔哩黑马程序员
VueJS 官方文档模板引用

描述

项目描述
Edge109.0.1518.70 (正式版本) (64 位)
操作系统Windows 10 专业版
@vue/cli5.0.8
npm8.19.3
VueJS2.6.14

模板引用

虽然 Vue 的声明性渲染模型为我们抽象了大部分对 DOM 的直接操作,但在某些情况下,我们仍然需要直接访问底层 DOM 元素。好在,VueJS 提供的模板引解决了这个问题。

引用

当你需要对一个元素进行 DOM 操作时,请先为其添加 ref 属性并设置属性值以标识该元素。

举个栗子

<template>
  <div class="container">
    <!-- 使用 ref 为该元素添加引用并将该引用标识为 boxRef -->
    <div class="box" ref="boxRef"></div>
  </div>
</template>

<script>
export default {

}
</script>

// 为 style 元素添加 scoped 属性
// 防止出现样式冲突
<style scoped>
.box{
  width: 100px;
  height: 100px;
  background-color: dodgerblue;
  cursor: pointer;
}
</style>

访问模板引用

我们可以通过 Vue 实例对象的 $refs 来对 ref 引用进行访问。

让我们为 .box 元素添加一个点击事件,在对该元素进行点击后打印 $refs 对象。

<template>
  <div class="container">
    <!-- 使用 ref 为该元素添加引用并将该引用标识为 boxRef -->
    <div class="box" ref="boxRef" v-on:click="convert()"></div>
  </div>
</template>

<script>
export default {
  // 定义事件调用函数
  methods: {
    convert() {
      console.log(this.$refs);
    }
  }
}
</script>

// 为 style 元素添加 scoped 属性
// 防止出现样式冲突
<style scoped>
.box{
  width: 100px;
  height: 100px;
  background-color: dodgerblue;
  cursor: pointer;
}
</style>

执行结果:

在执行上述代码后,点击 .box 元素,你将在控制台中观察到如下信息:

信息

可以看到,在 $refs 对象中,ref 标识作为属性名,而相应元素的 DOM 对象则作为属性值。

因此,我们可以通过如下方式来对 ref 关联的元素进行 DOM 操作。

举个栗子

<template>
  <div class="container">
    <!-- 使用 ref 为该元素添加引用并将该引用标识为 boxRef -->
    <div class="box" ref="boxRef" v-on:click="convert()"></div>
  </div>
</template>

<script>
export default {
  // 定义事件调用函数
  methods: {
    convert() {
      // 在点击 .box 元素后将该元素的背景颜色将由道奇蓝转变为粉红色
      this.$refs.boxRef.style.backgroundColor = 'pink';
    }
  }
}
</script>

// 为 style 元素添加 scoped 属性
// 防止出现样式冲突
<style scoped>
.box{
  width: 100px;
  height: 100px;
  background-color: dodgerblue;
  cursor: pointer;
}
</style>

执行效果:

在点击 .box 元素后将该元素的背景颜色将由道奇蓝转变为粉红色。

效果

组件中的模板引用

如果你为组件添加了 ref 属性并设置属性值标识了该引用,那么通过 $refs 你将能够获得该组件对应的 Vue 实例对象,这意味着父组件对子组件的每一个属性和方法都拥有有完全的访问权。这使得在父组件和子组件之间创建紧密耦合的实现细节变得很容易,当然也因此,应该只在绝对需要时才使用组件引用。大多数情况下,你应该首先使用标准的 propsemit 接口来实现父子组件交互。

举个栗子

在点击父组件中的 button 元素后,通过模板引用将子组件中的 .box 元素背景颜色进行修改。

App.vue

<template>
  <div class="container">
    <!-- 为子组件添加 ref 引用并将该引用标识为 Child -->
    <Child ref="Child"></Child>
    <button @click="transfer()">Transfer</button>
  </div>
</template>

<script>
// 导入组件
import Child from '@/components/Child.vue';

export default {
  // 注册组件
  components: {
    Child
  },
  // 定义事件处理函数
  methods: {
    transfer() {
      // 获取子组件中的 $refs,并通过
      // 子组件的 ref 引用对 .box 进行 DOM 操作
      this.$refs.Child.$refs.boxRef.style.backgroundColor = 'pink';
    }
  }
}
</script>

<style>

</style>

Child.vue

<template>
  <div class="container">
    <!-- 为 .box 元素添加 ref 引用并将该引用标识为 refBox -->
    <div class="box" ref="boxRef"></div>
  </div>
</template>

<script>
export default {

}
</script>

// 为 style 元素添加 scoped 属性
// 防止出现样式冲突
<style scoped>
.box{
  width: 100px;
  height: 100px;
  background-color: dodgerblue;
  cursor: pointer;
}
</style>

执行效果:

效果

$nextTick()

在讲解 $nextTick() 前,先让我们观察一个示例。

示例

<template>
  <div class="container">
    <!-- 
      当 v-if 的属性值对应的布尔值为 
      false 时,该元素将被隐藏 
    -->
    <div class="input" v-if="visible">
      <!-- 添加 ref 引用,便于后续该输入框获得焦点 -->
      <input type="text" placeholder="请输入您的账号" ref="user">
      <input type="password" placeholder="请输入您的密码"> 
    </div>
    <!-- 
      当 .input 元素的 v-if 的属性值对应的
      布尔值为 false 时,显示 button 元素
    -->
    <button @click="convert()" v-else>Login</button>
  </div>
</template>

<script>
export default {
  // 定义数据
  data() {
    return {
      visible: false
    }
  },
  // 定义事件处理函数
  methods: {
    convert() {
      // 在点击 Login 按钮后显示输入框
      this.visible = true;
      // 在显示输入框后,使第一个输入框获得焦点
      this.$refs.user.focus();
    }
  }
}
</script>

// 为 style 元素添加 scoped 属性
// 防止出现样式冲突
<style scoped>
input{
  display: block;
  margin-top: 15px;
  width: 250px;
  height: 26px;
}
</style>

预期效果:

在点击 Login 后,显示输入框并隐藏按钮。在此之后,使第一个输入框获得焦点。

执行效果:

效果
可以看到,在点击 Login 后,第一个输入框并未自动获取到焦点。为寻找原因,打开控制台。

在控制台中显示了如下报错信息:

错误信息:

错误信息

错误信息表明,此时的 this.$refs.user 的值为 undefined,即我们并未获取到 this.$refs.user 对应的 DOM 对象。

分析:

Vue 实例对象(组件)在运行阶段存在生命周期 beforeUpdateupdated。在 VueJS 中的响应式状态发生变化时,将进入 updated 生命周期,DOM 节点将在此时期中发生更新。

在上一个示例中,我们修改数据 visible 使输入框得以显示。但在修改数据 visible 时,组件的生命周期还处于 beforeUpdate 生命周期,此时 DOM 节点尚未更新,因此无法通过 this.$refs.user 获取到相关的 DOM 对象。

updated

错误示范

我们可以通过使用 updated 生命周期对应的生命周期钩子,在合适的时机通过 this.$refs.user 操作相关的 DOM 对象来使得元素获取焦点。

该方法是可行的,但在组件中存在多种导致响应式状态发生改变的可能时将存在弊端。为了展现这一弊端,我将数据 secret 与密码输入框中的内容进行了双向绑定,通过 p 元素将数据的变化在页面中加以展示。

<template>
  <div class="container">
    <!-- 
      当 v-if 的属性值对应的布尔值为 
      false 时,该元素将被隐藏 
    -->
    <div class="input" v-if="visible">
      <!-- 添加 ref 引用,便于后续该输入框获得焦点 -->
      <input type="text" placeholder="请输入您的账号" ref="user">
      <input type="password" placeholder="请输入您的密码" v-model:value="secret"> 
      <p v-text="secret"></p>
    </div>
    <!-- 
      当 .input 元素的 v-if 的属性值对应的
      布尔值为 false 时,显示 button 元素
    -->
    <button @click="convert()" v-else>Login</button>
  </div>
</template>

<script>
export default {
  // 定义数据
  data() {
    return {
      visible: false,
      secret: ''
    }
  },
  // 定义事件处理函数
  methods: {
    convert() {
      // 在点击 Login 按钮后显示输入框
      this.visible = true;
    }
  },
  // 使用生命周期 updated 对应的生命周期钩子
  updated() {
    this.$refs.user.focus();
  }
}
</script>

// 为 style 元素添加 scoped 属性
// 防止出现样式冲突
<style scoped>
input{
  display: block;
  margin-top: 15px;
  width: 250px;
  height: 26px;
}
</style>

执行效果:

效果

分析:

密码输入框中的内容与数据达成了双向绑定,密码输入框中的内容变换将导致数据发生变化,组件将因此进入 update 生命周期。
在进入 update 生命周期后,该周期对应的生命周期钩子(生命周期函数)将被执行,于是账号输入框又获取到了焦点。

正确演示

为了解决上一示例中遇到的问题,我们可以为 Login 按钮添加 “状态”,在进入生命周期函数后,我们将对 Login 的状态进行判断来决定是否需要执行 this.$refs.user.focus(); 来使账号输入框获取焦点。

<template>
  <div class="container">
    <!-- 
      当 v-if 的属性值对应的布尔值为 
      false 时,该元素将被隐藏 
    -->
    <div class="input" v-if="visible">
      <!-- 添加 ref 引用,便于后续该输入框获得焦点 -->
      <input type="text" placeholder="请输入您的账号" ref="user">
      <input type="password" placeholder="请输入您的密码" v-model:value="secret"> 
      <p v-text="secret"></p>
    </div>
    <!-- 
      当 .input 元素的 v-if 的属性值对应的
      布尔值为 false 时,显示 button 元素
    -->
    <button @click="convert()" v-else>Login</button>
  </div>
</template>

<script>
export default {
  // 定义数据
  data() {
    return {
      visible: false,
      secret: '',
      // 定义数据 flag 用于标识 Login 的点击状态
      flag: false
    }
  },
  // 定义事件处理函数
  methods: {
    convert() {
      // 在点击 Login 按钮后显示输入框
      this.visible = true;
      // 在点击 Login 按钮后修改数据 flag
      this.flag = true;
    }
  },
  // 使用生命周期 updated 对应的生命周期钩子
  updated() {
    // 判断 Login 按钮的点击状态
    if(!this.flag){
      this.$refs.user.focus();
    }
  }
}
</script>

// 为 style 元素添加 scoped 属性
// 防止出现样式冲突
<style scoped>
input{
  display: block;
  margin-top: 15px;
  width: 250px;
  height: 26px;
}
</style>

执行效果:

效果

$nextTick()

当你在 Vue 中更改响应式状态时,最终的 DOM 更新并不是同步生效的,而是由 Vue 将它们缓存在一个队列中,直到下一个 tick 才一起执行。这样是为了确保每个组件无论发生多少状态改变,都仅执行一次更新。

$nextTick() 可以在响应式状态发生改变后立即使用,你可以传递一个回调函数或者 await 返回的 Promise 作为 $nextTick() 的参数。$nextTick() 函数会在 DOM 更新完成后执行参数所关联的代码块。

<template>
  <div class="container">
    <!-- 
      当 v-if 的属性值对应的布尔值为 
      false 时,该元素将被隐藏 
    -->
    <div class="input" v-if="visible">
      <!-- 添加 ref 引用,便于后续该输入框获得焦点 -->
      <input type="text" placeholder="请输入您的账号" ref="user">
      <input type="password" placeholder="请输入您的密码"> 
    </div>
    <!-- 
      当 .input 元素的 v-if 的属性值对应的
      布尔值为 false 时,显示 button 元素
    -->
    <button @click="convert()" v-else>Login</button>
  </div>
</template>

<script>
export default {
  // 定义数据
  data() {
    return {
      visible: false
    }
  },
  // 定义事件处理函数
  methods: {
    convert() {
      // 在点击 Login 按钮后显示输入框
      this.visible = true;
      // 在 DOM 更新后使账号输入框获得焦点
      this.$nextTick(() => {
        this.$refs.user.focus();
      })
    }
  }
}
</script>

// 为 style 元素添加 scoped 属性
// 防止出现样式冲突
<style scoped>
input{
  display: block;
  margin-top: 15px;
  width: 250px;
  height: 26px;
}
</style>

执行效果:

效果

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

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

相关文章

jvm相关,jvm内存溢出,内存占用过高,CPU占用率高原因分析,MAT内存镜像文件分析的使用----学习笔记

什么是内存泄漏? 什么是内存溢出 内存溢出: OutOfMemory 它是指程序在申请内存时&#xff0c;没有足够的内存空间供其使用&#xff0c;抛出 OutOfMemory 错误 内存泄露: Memory Leak 它是指程序运行后&#xff0c;没有释放所占用的内存空间&#xff0c;比如程序运行完后没有释…

数据库和SQL初探

数据库和SQL初探1. 什么是数据库2. 数据库的结构3. MySQL表定义相关操作4. MySQL体系结构和存储引擎1. 什么是数据库 将大量数据保存起来&#xff0c;通过计算机加工而成的可以进行高效访问的数据集合。用来管理数据库的计算机系统称为数据库管理系统(DatabaseManagementSyste…

Java面试题二(自用-持续更新)

本文目录如下&#xff1a;Java面试题(二)四、并发编程线程和进程的区别&#xff1f;守护线程是什么&#xff1f;创建线程有哪几种方式&#xff1f;线程有哪些状态&#xff1f;sleep() 和 wait() 有什么区别&#xff1f;线程的sleep()方法和yield()方法有什么区别&#xff1f;线…

我发现买不起自己出版的书了,这到底是咋回事?

大家好&#xff0c;我是冰河~~ 这次我是真的有点买不起自己的书了&#xff01; 聊聊背景 继出版《海量数据处理与大数据技术实战》、《MySQL技术大全&#xff1a;开发、优化与运维实战》和《深入理解分布式事务&#xff1a;原理与实战》之后&#xff0c;冰河于2022年6月出版…

基于uni-app的小程序电子签名功能(带有笔锋)

前言 目前做的一个项目需要用到电子签名的功能&#xff0c;网上其实也挺多这种类型的电子签名&#xff0c;但是带有笔锋效果的确比较少&#xff0c;所以参考了一些博客&#xff0c;总结成了这个功能&#xff0c;在此分享给大家。 效果展示 代码展示 触摸开始&#xff08;touc…

大数据专业需要学习python么

如果零基础入门数据开发行业的小伙伴&#xff0c;可以从Python语言入手。 Python语言简单易懂&#xff0c;适合零基础入门&#xff0c;在编程语言排名上升最快&#xff0c;能完成数据挖掘、机器学习、实时计算在内的各种大数据集成任务。 但是不会python也是没有关系的&#…

基于Vector VT系统的车身域测试方案介绍

车身域控制器作为车身主要部件的控制大脑&#xff0c;需要经过严苛的测试&#xff0c;常见的测试方式是通过搭建硬件在环测试系统实现的&#xff0c;测试原理是通过仿真控制器外围的传感器和执行器&#xff0c;实现车身域控制器的闭环仿真和测试。小怿基于国际一流的测试设备提…

Day15 C++STL入门基础知识九——list容器 基本概念-构造函数-赋值变换-大小操作-插入删除-数据存取-反转排序 【全面深度剖析+例题代码展示】

文章目录1. 基本概念1.1 功能1.2 概念1.3 组成和存储方式1.4 优缺点1.4 图解2. 构造函数2.1 函数原型2.2 代码展示2.3 测试结果3. 赋值交换3.1 函数原型3.2 代码展示3.3 测试结果4. 大小操作1.3 代码展示1.4 测试结果6. 插入删除6.1 函数原型6.2 代码展示6.3 测试结果7. 数据存…

React报错#310复盘小结

React报错#310复盘小结问题背景解决方案原理&学习引发错误情况1. 不要在循环&#xff0c;条件或嵌套函数中调用 Hook2. 把所有的钩子移到组件的顶层&#xff0c;在任何可能返回值的条件之上。总结问题背景 apm报错&#xff1a;Minified React error #310 https://reactjs.…

浅谈Graph Embedding(一)

Graph Embedding算法背景引入先回顾下图的概念&#xff1a;图(graph)由节点(vertex)和点之间连线(edge)所组成&#xff1b;其中&#xff0c;点通常被成为“顶点(vertex)”,而点与点之间的连线则被成为“边”(edge)。通常记为,G(V,E)。常见分为无向图和有向图。示例如下&#xf…

MySQL数据类型约束

文章目录数据类型MySQL中的数据类型整数类型类型介绍可选属性MUNSIGNEDZEROFILL适用场景如何选择&#xff1f;浮点类型类型介绍数据精度说明精度误差说明定点数类型类型介绍开发中经验位类型&#xff1a;BIT6. 日期与时间类型YEAR类型DATE类型TIME类型DATETIME类型TIMESTAMP类型…

小白入门pwn笔记 CPU与进程的执行

1.回顾存储在磁盘中的叫节&#xff0c;映射到内存的时候叫段。内存中的节根据读写执行的权限不同在内存中映像为不同的段。段视图用于进程的内存区域的rwx权限划分。节视图用于ELF文件编译链接时与在磁盘上储存时的文件结构的组织。2.代码在内存重的映射关系不可写的数据一般会…

Qt OpenGL(三十六)——Qt OpenGL 核心模式-绘制雷达坐标系

提示:本系列文章的索引目录在下面文章的链接里(点击下面可以跳转查看): Qt OpenGL 核心模式版本文章目录 Qt OpenGL(三十六)——Qt OpenGL 核心模式-绘制雷达坐标系 一、场景 在日常的项目中,我们很多时候会遇到,绘制雷达扫描图的情况,比如,你的项目是给下面的雷达…

unidbg-boot-server使用并打包jar调用

其实线上使用可以多种方式,比如pom引入spring boot自己去写一个接口实现; 但如果并发不是很高,可以使用synchronized关键字进行,若对并发有要求,建议直接使用 unidbg-boot-server开源项目; 从github下拉,https://github.com/anjia0532/unidbg-boot-server 常见问题:…

Neo-reGeorg测试

1、前言 趁着春节刚开工不太忙&#xff0c;把以前的坑填一下。 主要是针对反向代理、隧道工具进行学习和测试。 之前测试过FRP&#xff0c;HTTPTunnel&#xff0c;NPS&#xff0c;都比较简单&#xff0c;而且上面工具也可以用在普通需求下使用。 reGeorg和Neo-reGeorg非常适合…

常用RTOS详细说明

鸿蒙OS HarmonyOS是一款面向全场景的开源分布式操作系统&#xff0c;是华为自主研发的操作系统。 鸿蒙OS实现模块化耦合&#xff0c;可应用在不同的设备上。 鸿蒙OS架构分为三层&#xff1a; 第一层是内核第二层是基础服务第三层是程序框架 。 鸿蒙OS底层三部分组成&#x…

《U型理论》速读

文章目录书籍信息概览踏上发现的旅程大火带来的启示踏上 U 型之旅学习和变革的4个层次组织的盲点社会的盲点科学的哲学基础关于界点下载观察感知自然流现结晶塑造原型运行社会场域理论的 21 个命题个人行动谈话行动自然流现的原则和实践&#xff1a;引领深刻的创新和变革视觉记…

Windows Server 2016搭建DNS服务

1&#xff1a;搭建DNS服务的目的是为了解析vCenter,当初安装时候没有用DNS解析&#xff0c;主机名是localhost无法安装vTPM虚拟Windows 11。 2&#xff1a;准备一台Windows Server 2016的主机&#xff0c;设置好固定IP地址,DNS就是本机的IP地址。 3&#xff1a;在服务器管理中…

Maven知识点-关于dependencyManagement和pluginManagement

前言 dependencyManagement和pluginManagement如何使用以及什么意思&#xff1f;我想懂点Maven的应该都明白&#xff0c;无非是依赖和插件的管理&#xff08;版本&#xff09;&#xff0c;一般多用于Maven项目的继承和聚合模式中。 这里不是讲解dependencyManagement和plugin…

PCB丝印的字符有哪些作用?

PCB字符也就是行业内常说的“丝印”PCB丝印在一般的PCB板子都可以看到&#xff0c;那么PCB丝印有那些作用呢。 1、大家都知道各种各样的电子元器件数不胜数&#xff0c;那么如何区分PCB这个焊盘是贴什么电子元器件的呢&#xff1f;实际上就是通过PCB板子上的丝印字符去判断每一…