Vue3全家桶 - Vue3 - 【8】模板引用【ref】(访问模板引用 + v-for中的模板引用 + 组件上的ref)

模板引用【ref

  • Vue3官网-模板引用;
  • 如果我们需要直接访问组件中的底层DOM元素,可使用vue提供特殊的ref属性来访问;

一、 访问模板引用

  • 在视图元素上采用ref属性来设置需要访问的DOM元素:
    • ref 属性可采用 字符串 值的执行设置;
    • ref 属性可采用v-bind::ref的形式来绑定 函数,其函数的第一个参数则为该元素;
  • 如果元素的ref属性值采用的是字符串形式:
    • 在组合式API JS 中,我们需要声明一个同名的ref变量,来获得该模板的引用;
    • 在选项式API JS 中,可通过this.$refs来访问模板的引用;
  • 示例代码:
    • 组合式API:
      <template>
        <!-- 字符串形式的 ref -->
        账号输入框:<input type="text" ref="account">
        <button @click="accountInputStyle">改变账号输入框的样式</button>
      
        <!-- 函数形式的 ref ,必须采用 v-bind 或 : 的形式来给ref绑定属性值 -->
        密码输入框:<input type="password" :ref="passwordFn">
        <button @click="passwordInputStyle">改变密码输入框的样式</button>
      </template>
      
      <script setup>
      import { ref, reactive, computed, onMounted, nextTick } from 'vue'
      
      // EXPLAIN 响应式数据
      // ref 变量名 和 对应DOM元素的ref属性值 相等
      let account = ref(null)
      let password = ref(null)
      
      // EXPLAIN 函数
      const accountInputStyle = () => {
        // NOTE 此处设置的 style 均为行内样式
        account.value.style.padding = '15px'
        account.value.style.caretColor = 'red'
        account.value.className = 'rounded'
        account.value.focus()
      }
      // NOTE 采用函数给ref绑定属性值,该函数的第一个参数为该元素
      // NOTE 在页面渲染的时候会自动执行
      // NOTE 函数式生命的 ref,不会在 this.$refs 中获取
      const passwordFn = (el) => {
        // el 元素是密码输入框
        password.value = el
        console.log(password.value)
      }
      const passwordInputStyle = () => {
        password.value.style.border = '4px solid green'
        password.value.style.padding = '15px'
        password.value.focus()
      }
      
      onMounted(() => {});
      </script>
      
      <style scoped>
      .rounded {
        border: 4px solid purple;
      }
      </style>
      
    • 选项式API:
      <script>
      export default {
          data: () => ({
              accountEl: null,
              passwordEl: null
          }),
          methods: {
              changeAccountInputStyle() {
                  this.accountEl = this.$refs.account // 获取账号输入框的 DOM
                  console.log(this.accountEl)
                  this.accountEl.style = "padding: 15px"
                  this.accountEl.className = "rounded"
                  this.accountEl.focus()
              },
              passwordRef(el) { 
                  this.passwordEl = el  // el 元素是密码输入框
              },
              changePasswordInputStyle() {
                  console.log(this.passwordEl) 
                  console.log(this.$refs) // 函数式声明的 ref,不会在this.$refs中获取
                  this.passwordEl.style = "padding: 15px"
                  this.passwordEl.className = "rounded"
                  this.passwordEl.focus()
              },
          }
      }
      </script>
      
      <template>
          <!-- ref 字符串值形式 -->
         账号输入框:<input type="text" ref="account">
         <button @click="changeAccountInputStyle">改变账号输入框的样式</button>
      
         <hr>
      
         <!-- ref 函数形式:元素渲染后,会立即执行该函数 -->
         密码输入框:<input type="password" :ref="passwordRef">
         <button @click="changePasswordInputStyle">改变密码输入框的样式</button>
      </template>
      
      <style>
      .rounded {
          border-radius: 15px;
      }
      </style>
      

二、 v-for中的模板引用

  • 当在v-for中使用模板引用时:

    • 如果 ref 值是 字符串 形式,在元素被渲染后包含对应整个 列表的所有元素【数组】
    • 如果 ref 值是 函数 形式,则会每渲染一个列表元素就会执行对应的函数【不推荐使用】;
  • 注意:需要 v3.2.25 及以上的版本;

  • 示例代码:

    • 组合式API:
      <script setup>
      import { onMounted, ref } from "vue";
      
      // 书本
      let books = ref([
        { id: 1, name: "海底两万里" },
        { id: 2, name: "骆驼祥子" },
        { id: 3, name: "老人与海" },
        { id: 4, name: "安徒生童话" },
      ]);
      
      let bookList = ref(null);
      
      onMounted(() => {
        console.log(bookList.value); // 获取引用的 DOM 对象,并打印,发现那么是数组,
        bookList.value[2].className = "error";
      });
      </script>
      
      <template>
        <ul>
          <li v-for="b in books" :key="b.id" ref="bookList">
            {{ b.name }}
          </li>
        </ul>
      </template>
      
      <style>
      .error {
        border: 1px solid red;
      }
      </style>
      
    • 选项式API:
      <script>
      export default {
        data: () => ({
          books: [
            { id: 1, name: "红楼梦" },
            { id: 2, name: "三国演义" },
            { id: 3, name: "水浒传" },
            { id: 4, name: "西游记" },
          ],
          students: [
            { id: 1, name: "Jack" },
            { id: 2, name: "Annie" },
            { id: 3, name: "Tom" },
          ],
        }),
        methods: {
          changeBookListStyle() {
            console.log(this.$refs.bookList);
            this.$refs.bookList[2].style = "color: red";
          },
          studentsRef(el) {
            console.log(el);
          },
        },
      };
      </script>
      
      <template>
        <ul>
          <!-- 如果 ref 值是字符串形式,在元素被渲染后包含对应整个列表的所有元素【数组】 -->
          <li v-for="b in books" :key="b.id" ref="bookList">
            {{ b.name }}
          </li>
        </ul>
        <button @click="changeBookListStyle">点我查看 bookList</button>
      
        <hr />
        <!-- 如果ref值是函数形式,则会每渲染一个列表元素则会执行对应的函数【不推荐使用】 -->
        <ul>
          <li v-for="s in students" :key="s.id" :ref="studentsRef">
            {{ s.name }}
          </li>
        </ul>
      </template>
      
  • 运行效果:

    • 选项式API:
      image.png
    • 组合式API:
      image.png

三、 组件上的ref

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

    • 如果子组件使用的选项式API,默认情况下父组件可以随意访问该子组件的数据和函数,除非在子组件使用expose选项来暴露特定的数据或函数,expose值为字符串数组;
    • 如果子组件使用的是组合式API<script setup>,那么该子组件默认是私有的,则父组件无法访问该子组件,除非子组件在其中通过defineExpose宏采用对象形式显示暴露特定的数据或函数;
  • 示例代码:

    • 组合式API:
      • 父组件:

        <script setup>
        // NOTE 组合式API中,默认情况下,子组件中的数据、函数等等都是私有的,不能访问
        // NOTE 如果 子组件 通过 defineExpose 宏采用对象形式显式暴露特定的数据或函数等等
        import Vue1 from '@/components/27-组件上的ref - 组合式API/1.vue'
        import { ref, onMounted } from 'vue'
        const login_vue = ref(null)
        const showSonData = () => {
          console.log(login_vue.value.account)
          console.log(login_vue.value.password)
          login_vue.value.toLogin()
        }
        onMounted(() => {});
        </script>
        
        <template>
          <h3>登录页面</h3>
          <hr>
          <!-- 组件上的 ref 的值为该组件的实例 -->
          <Vue1 ref="login_vue"></Vue1>
          <hr>
          <button @click="showSonData">查看子组件的信息</button>
        </template>
        
      • 子组件:

        <script setup>
        import { ref } from 'vue'
        const account = ref('admin')
        const password = ref('123456')
        const toLogin = () => {
          alert('登录中……')
        }
        // TODO 采用 defineExpose 将指定数据、函数等等暴露出去
        defineExpose({
          account,
          toLogin
        });
        </script>
        
        <template>
          账号:<input type="text" v-model="account">
          <br>
          密码:<input type="text" v-model="password">
          <hr>
          <button @click="toLogin">登录</button>
        </template>
        
      • 效果展示:

        • 默认情况下(没有使用defineEpxose):
          image.png
        • 通过defineExpose暴露特定的属性或方法:
          image.png
    • 选项式API:

      • 父组件:
        <script>
        // NOTE 选项式API中,默认情况下,父组件可以随意访问子组件的数据和函数、计算属性等等
        // NOTE 如果 子组件 增加 expose 选项之后,就只能访问 expose 暴露的属性和函数等等
        import Vue1 from '@/components/27-组件上的ref - 选项式API/1.vue'
        export default {
          name: 'App',
          components: { Vue1 },
          data: () => ({
            login_vue: null
          }),
          methods: {
            showSonData () {
              console.log(this.login_vue.account)
              console.log(this.login_vue.password)
              this.login_vue.toLogin()
            }
          },
          mounted () {
            // 打印出来的式子组件的ref对象
            this.login_vue = this.$refs.loginVue
            console.log(this.login_vue)
          }
        }
        </script>
        
        <template>
          <h3>登录页面</h3>
          <hr>
          <!-- 组件上的 ref 的值为该组件的实例 -->
          <Vue1 ref="loginVue"></Vue1>
          <hr>
          <button @click="showSonData">查看子组件的信息</button>
        </template>
        
      • 子组件:
        <script>
        export default {
          name: 'Vue1',
          data: () => ({
            account: 'admin',
            password: '123456'
          }),
          methods: {
            toLogin () {
              alert('登录中……')
            }
          },
          // TODO 向外暴露属性函数,增加这个选项之后,父组件只能访问该组件暴露的属性或方法等等
          expose: ['account', 'password']
        }
        </script>
        
        <template>
          账号:<input type="text" v-model="account">
          <br>
          密码:<input type="text" v-model="password">
          <hr>
          <button @click="toLogin">登录</button>
        </template>
        
        <style scoped lang='scss'>
        </style>
        
      • 运行展示:
        • 未增加 expose
          image.png
        • 增加 epxose
          • 子组件没有暴露 toLogin 方法,所以此处访问不了;
            image.png

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

docker-compose Install ONLYOFFICE

ONLYOFFICE 前言 ONLYOFFICE 是一款全面的协作办公软件套件,集成了文档处理、电子表格和演示文稿等功能,为团队提供了无缝协作的工作环境。其功能强大,操作简便,是各种规模和类型的团队的首选工具。 功能介绍 多人协作:ONLYOFFICE 提供实时协作功能,让团队成员可以同时…

QGIS 开发之旅一《二次开发环境搭建》

1、 安装QT 下载QT Index of /new_archive/qt 我选择的版本是 Qt5.14.2 2、安装VS2017 Downloads & Keys - Visual Studio Subscriptions。下载后选择windows通用平台开发和C 开发就可以了。 3、安装插件QT vs tools 搜索 qt vs tools&#xff0c;选择第一个安装 …

【vivado】 clock wizard 时钟IP

一、前言 MMCM和PLL是在FPGA设计中不可避免需要使用到的时钟资源&#xff0c;对于其功能及使用方法的理解是正确进行FPGA设计的前提。 二、Xilinx 时钟 IP配置 vivado中使用时钟向导(Clocking Wizard)配置时钟IP核&#xff0c;其框图如下&#xff1a; clk_in 输入时钟&#…

MachineSink - 优化阅读笔记

注&#xff1a;该优化与全局子表达式消除刚好是相反的过程&#xff0c;具体该不该做这个优化得看代价模型算出来的结果(有采样文件指导算得会更准确) 该优化过程将指令移动到后继基本块中&#xff0c;以便它们不会在不需要其结果的路径上执行。 该优化过程并非旨在替代或完全…

按键+串口发送实验

摸鱼记录 Day_15 &#xff5e;(&#xffe3;▽&#xffe3;&#xff5e;)(&#xff5e;&#xffe3;▽&#xffe3;)&#xff5e; review 前边已经学习了&#xff1a; 串口发送Vivado 串口通信(UART)------串口发送-CSDN博客 按键基于状态机的按键消抖实现-CSDN博客 1. …

CANopen转Profinet网关连接西门子PLC与变流器通讯

CANopen转Profinet网关&#xff08;XD-COPNm20&#xff09;在智能领域&#xff0c;变流器的应用非常广泛&#xff0c;变流器一般会采用CANopen协议。现场采用台达的变流器&#xff08;支持CANopen协议&#xff09;作为CANopen从站&#xff0c;S7-1500系列PLC做主站&#xff0c;…

ENVI 如何批量拆分多波段栅格

在处理遥感图像时&#xff0c;需要将多波段栅格进行拆分是很常见的需求。下面介绍一种方法&#xff0c;可以实现图像批量拆分并重命名。 打开ENVI的App Store 搜索并下载应用 在ENVI的App Store中搜索"将多波段图像拆分成多个单波段文件"&#xff0c;并下载安装。 打…

索引失效的介绍和避免方法

索引是什么 在关系数据库 中&#xff0c;索引是一种单独的、物理的对数据库表中一列或多列的值进行排序的一种 存储结构 &#xff0c;它是某个表中一列或若干列值的集合和相应的指向表中物理标识这些值的数据页的逻辑指针清单。 索引的作用相当于图书的目录&#xff0c;可以根据…

20240309web前端_第一周作业_完成用户注册界面

作业一&#xff1a;完成用户注册界面 成果展示&#xff1a; 完整代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-…

MyBatis拦截器四种类型和自定义拦截器的使用流程

文章目录 MyBatis拦截器四种类型和自定义拦截器的使用流程一、MyBatis拦截器四种类型的详细解释&#xff1a;1. **ParameterHandler 拦截器**&#xff1a;2. **ResultSetHandler 拦截器**&#xff1a;3. **StatementHandler 拦截器**&#xff1a;4. **Interceptor Chain 拦截器…

软考高级:统计过程阶段和工作流概念和例题

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;大厂高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《Effective Java》独家解析》专栏作者。 热门文章推荐&am…

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的常见车型识别系统(Python+PySide6界面+训练代码)

摘要&#xff1a;本文深入探讨了如何应用深度学习技术开发一个先进的常见车型识别系统。该系统核心采用最新的YOLOv8算法&#xff0c;并与早期的YOLOv7、YOLOv6、YOLOv5等版本进行性能比较&#xff0c;主要评估指标包括mAP和F1 Score等。详细解析了YOLOv8的工作机制&#xff0c…

逆向案例七——中国天气质量参数搜不到加密,以及应对禁止打开开发者工具和反debuger技巧

进入相关城市数据页面&#xff0c;发现不能调试 应对方法&#xff0c;再另一个页面&#xff0c;打开开发者工具&#xff0c;选择取消停靠到单独页面 接着&#xff0c;复制链接在该页面打开。接着会遇到debugger 再debugger处打上断点&#xff0c;一律不在此处暂停。 然后点击继…

InnoDB索引优化

索引 覆盖索引 最左前缀原则 索引下推优化 如果我执行 select * from T where k between 3 and 5 这条语句&#xff08;k 是索引&#xff09;&#xff0c;需要执行几次树的搜索操作&#xff0c;会扫描多少行&#xff1f; 这条 SQL 查询语句的执行流程…

Promise其实也不难

难点图解&#xff1a;then&#xff08;&#xff09;方法 ES6学习网站&#xff1a;ES6 入门教程 解决&#xff1a;回调地狱&#xff08;回调函数中嵌套回调&#xff09; 两个特点&#xff1a; &#xff08;1&#xff09;对象的状态不受外界影响。Promise对象代表一个异步操作&…

前端精准测试简介

一&#xff0c; 前端精准测试架构介绍 今年从零开始完成了前端精准测试整体功能的开发&#xff0c;在基于istanbul插件的基础之间&#xff0c;实现覆盖率数据的采集&#xff0c;并根据服务端和移动端精准测试的整体架构&#xff0c;实现前端精准测试体系。整体架构及核心功能…

【李沐论文精读】GPT、GPT-2和GPT-3论文精读

论文&#xff1a; GPT&#xff1a;Improving Language Understanding by Generative Pre-Training GTP-2&#xff1a;Language Models are Unsupervised Multitask Learners GPT-3&#xff1a;Language Models are Few-Shot Learners 参考&#xff1a;GPT、GPT-2、GPT-3论文精读…

七个项目掌握freertos

1、闪烁LED&#xff1a; 最基本的示例项目&#xff0c;涉及到创建一个简单的任务&#xff0c;用于控制LED的闪烁。这个项目会教你如何初始化FreeRTOS并创建任务。 #include "FreeRTOS.h" #include "task.h" #define LED_PIN (某个GPIO引脚)void vBlinkTas…

555经典电路

1、555介绍&#xff1a; 555 定时器是一种模拟和数字功能相结合的中规模集成器件。一般用双极性工艺制作的称为 555&#xff0c;用 CMOS 工艺制作的称为 7555&#xff0c;除单定时器外&#xff0c;还有对应的双定时器 556/7556。555 定时器的电源电压范围宽&#xff0c;可在 4…

20240312-2-贪心算法

贪心算法 是每次只考虑当前最优&#xff0c;目标证明每次是考虑当前最优能够达到局部最优&#xff0c;这就是贪心的思想&#xff0c;一般情况下贪心和排序一起出现&#xff0c;都是先根据条件进行排序&#xff0c;之后基于贪心策略得到最优结果。 面试的时候面试官一般不会出贪…