Vue3:组件高级(下)

news2024/11/24 3:38:53

Vue3:组件高级(下)

Date: May 25, 2023
Sum: ref引用、动态组件、插槽、自定义指令


目标:

◆ 能够知道如何使用 ref 引用 DOM 和组件实例

◆ 能够知道 $nextTick 的调用时机

◆ 能够说出 keep-alive 元素的作用

◆ 能够掌握插槽的基本用法

◆ 能够知道如何自定义指令




ref 引用

  1. 什么是 ref 引用

ref 用来辅助开发者在不依赖于 jQuery 的情况下,获取 DOM 元素或组件的引用。

每个 vue 的组件实例上,都包含一个 $refs 对象,里面存储着对应的 DOM 元素或组件的引用。默认情况下,组件的 $refs 指向一个空对象。

案例:

<template>
  <div>
    <h1>App 根组件</h1>
    <hr/>
    <button type="button" class="btn btn-primary" @click="getRefs">获取 $ref 引用</button>
  </div>
</template>

<script>
export default {
  name: 'MyApp',
  methods: {
    getRefs() {
      console.log(this); // this 代表当前组件的实例对象, this.$refs 默认指向空对象
    }
  }
}
</script>

效果:

Untitled


  1. 使用 ref 引用 DOM 元素

如果想要使用 ref 引用页面上的 DOM 元素,则可以按照如下的方式进行操作:

比如你想引用h1标题,那么你就可以这么写:<h1 ref="myh1">App 根组件</h1>

案例:

<template>
  <div>
    <h1 ref="myh1">App 根组件</h1>
    <hr/>
    <button @click="getRefs">获取 $ref 引用</button>
  </div>
</template>

<script>
export default {
  name: 'MyApp',
  methods: {
    getRefs() {
      // 通过 this.$refs.引用的名称 可以获取到DOM元素的引用
      console.log(this);
      // 操作DOM元素,把文本颜色改为红色
      this.$refs.myh1.style.color = 'red'
    }
  }
}
</script>

效果:

Untitled


  1. 使用 ref 引用组件实例

如果想要使用 ref 引用页面上的组件实例,则可以按照如下的方式进行操作:

具体步骤:

  1. 使用ref属性,为对应的组件添加引用名称

案例:

<template>
  <div>
    <h1>App 根组件</h1>
    <!-- 使用ref属性,为对应的组件添加引用名称 -->
    <button @click="getRefs">获取 $ref 引用</button>
    <hr>
    <my-counter ref="counterRef"></my-counter>
  </div>
</template>

<script>
import MyCounter from './Counter.vue'
export default {
  name: 'MyApp',
  methods: {
    getRefs() {
      // 通过 this.$refs 引用的名称 可以引用组件的实例
      // 引用到组件的实例之后,就可以调用组件上的methods方法
      this.$refs.counterRef.reset()
    }
  },
  components: {
    MyCounter,
  }
}
</script>

效果:

  1. 我们可以在button上面发现一个reset方法
  2. 可以用button为counter组件中的count清零

Untitled


4. 控制文本框和按钮的按需切换

通过布尔值 inputVisible 来控制组件中的文本框与按钮的按需切换。

案例:

<template>
  <div>
    <h1>App 根组件</h1>
    <hr/>
    <input type="text" v-if="inputVisible">
    <button v-else @click="showinput">显示 input 输入框</button>
  </div>
</template>

<script>
export default {
  name: 'MyApp',
  data() {
    return {
      inputVisible: false,
    }
  },
  methods: {
    showinput() {
      this.inputVisible = true
    }
  },
}
</script>

效果:

Untitled


  1. 让文本框自动获得焦点

当文本框展示出来之后,如果希望它立即获得焦点,则可以为其添加 ref 引用,并调用原生 DOM 对象的.focus() 方法即可。

示例代码如下:

<template>
  <div>
    <h1>App 根组件</h1>
    <hr/>
    <input type="text" v-if="inputVisible" ref="ipt">
    <button v-else @click="showinput">显示 input 输入框</button>
  </div>
</template>

<script>
export default {
  name: 'MyApp',
  data() {
    return {
      inputVisible: false,
    }
  },
  methods: {
    showinput() {
      // 展示文本框
      this.inputVisible = true
      // 获取到文本框的引用对象,然后调用 focus() 方法
      this.$refs.ipt.focus()
    }
  },
}
</script>

效果:

Untitled

点击按钮后,文本框消失,然后会报以下错误。

因为DOM元素的更新是异步更新,执行1后会立即执行2,从而希望拿到ipt这个引用对象。而此时DOM还没有完全更新完(就是文本框还没出来,我们就要它的ipt),显然不可能,故报错。

// 展示文本框
  this.inputVisible = true  //1
  // 获取到文本框的引用对象,然后调用 focus() 方法
  this.$refs.ipt.focus()  //2
}

  1. this.$nextTick(cb) 方法

组件的 $nextTick(cb) 方法,会把 cb 回调推迟到下一个 DOM 更新周期之后执行。通俗的理解是:等组件的DOM 异步地重新渲染完成后,再执行 cb 回调函数。从而能保证 cb 回调函数可以操作到最新的 DOM 元素。

<input type="text" v-if="inputVisible" ref="ipt">
<button v-else @click="showinput">显示 input 输入框</button>

methods: {
  showinput() {
    // 展示文本框
    this.inputVisible = true
    // 把对 input 文本框的操作,推迟到下次DOM更新之后,否则页面上根本不存在文本框元素
    this.$nextTick(() => {
      this.$refs.ipt.focus()
    })
  }
},



动态组件

  1. 什么是动态组件

动态组件指的是动态切换组件的显示与隐藏。vue 提供了一个内置的 组件,专门用来实现组件的动态渲染。

① 是组件的占位符

② 通过 is 属性动态指定要渲染的组件名称

  1. 如何实现动态组件渲染

示例代码如下:

data() {
  return {
    comName: 'MyHome' // 1.当前要渲染的组件的名称
  }
},

<template>
  <div>
    <h1 class="mb-4">App 根组件</h1>
		<!-- 点击按钮,动态切换组件的名称 -->
    <button @click="comName = 'MyHome'">首页</button>
    <button @click="comName = 'MyMovie'">电影</button>
    <hr />
    <!-- 2.用is来指定需要渲染的组件的名字 -->
    <component :is="comName"></component>
  </div>
</template>

注意:当我们切换组件时,之前组件会被销毁(所以之前的数据也会被清空)

Untitled

  1. 使用 keep-alive 保持状态

默认情况下,切换动态组件时无法保持组件的状态。此时可以使用 vue 内置的 组件保持动态组件的状态。

示例代码如下:

<keep-alive>
  <component :is="comName"></component>
</keep-alive>



插槽

  1. 什么是插槽

插槽(Slot)是 vue 为组件的封装者提供的能力。允许开发者在封装组件时,把不确定的、希望由用户指定的部分定义为插槽。

Untitled

可以把插槽认为是组件封装期间,为用户预留的内容的占位符。



体验插槽的基础用法

在封装组件时,可以通过 元素定义插槽,从而为用户预留内容占位符。

示例代码如下:

MyCom.vue

<template>
    <p>这是第一个p标签</p>
    <!-- 通过 slot 标签,为用户预留内容占位符(插槽) -->
    <slot></slot>
    <p>这是最后一个p标签</p>
</template>

App.vue

<!-- 使用组件 -->
<my-com>
	<!-- 在使用MyCom1 组件时, 为插槽指定具体的内容--->
  <p>~~~用户自定义的内容~~~</p>
</my-com>

没有预留插槽的内容会被丢弃

如果在封装组件时没有预留任何 插槽,则用户提供的任何自定义内容都会被丢弃。

示例代码如下:

MyCom.vue

<template>
    <p>这是第一个p标签</p>
    <!-- 封装组件时,没有预留任何插槽 -->
    <p>这是最后一个p标签</p>
</template>

App.vue

<my-com-1>
	<!-- 自定义的内容会被丢弃 -->
	<p>~~~用户自定义的内容~~~<p>
</my-com-1>

后备内容
封装组件时,可以为预留的 插槽提供后备内容(默认内容)。如果组件的使用者没有为插槽提供任何内容,则后备内容会生效。

示例代码如下:

<template>
    <p>这是第一个p标签</p>
    <slot>这是后备内容</slot>
    <p>这是最后一个p标签</p>
</template>


具名插槽

如果在封装组件时需要预留多个插槽节点,则需要为每个 插槽指定具体的 name 名称。这种带有具体名称的插槽叫做“具名插槽”。

示例代码如下:

MyCom.vue

<template>
  <div>
    <header>
      <!-- 我们希望把页头放这里 -->
      <slot name="header"></slot>
    </header>
    
    <main>
      <!-- 我们希望把主要内容放这里 -->
      <slot></slot>
    </main>
    
    <footer>
      <!-- 我们希望把页脚放这里 -->
      <slot name="footer"></slot>
    </footer>
  </div>
</template>

注意:没有指定 name 名称的插槽,会有隐含的名称叫做 “default”。


为具名插槽提供内容

在向具名插槽提供内容的时候,我们可以在一个 元素上使用 v-slot 指令,并以 v-slot 的参数的形式提供其名称。

示例代码如下:

<template>
  <div>
    <h1>App 根组件</h1>
    <hr/>

    <!-- 使用组件 -->
    <my-com>
      <template v-slot:header>
        <h1>滕王阁序</h1>
      </template>

      <template v-slot:default>
        <p>test1</p>
        <p>test2</p>
        <p>test3</p>        
      </template>

      <template v-slot:footer>
        <p>落款:王勃</p>
      </template>
    </my-com>
  </div>
</template>

具名插槽的简写形式

跟 v-on 和 v-bind 一样,v-slot 也有缩写,即把参数之前的所有内容 (v-slot:) 替换为字符 #。例如 v-slot:header可以被重写为 #header

<template>
  <div>
    <h1>App 根组件</h1>
    <hr/>

    <!-- 使用组件 -->
    <my-com>
      <template #header>
        <h1>滕王阁序</h1>
      </template>

      <template #default>
        <p>test1</p>
        <p>test2</p>
        <p>test3</p>        
      </template>

      <template #footer>
        <p>落款:王勃</p>
      </template>
    </my-com>
  </div>
</template>


作用域插槽

在封装组件的过程中,可以为预留的 插槽绑定 props 数据,这种带有 props 数据的 叫做“作用域插槽”。

示例代码如下:

MyCom.vue

<template>
  <div>
    <h3>这是 TEST 组件</h3>
    <slot :info="infomation" :msg="message"></slot>
  </div>
</template>

<script>
export default {
  name: 'MyCom',
  data() {
    return {
      information: {
        phone: '138XXXXX6666',
        address: '中国北京'
      },
      message: 'abc',
    }
  }
}
</script>

App.vue

<template>
  <div>
    <h1>App 根组件</h1>
    <hr />
    <!-- 使用自定义组件 -->
    <my-com v-slot:default="scope">
      <p>{{ scope }}</p>
    </my-com>
  </div>
</template>

理解:App.vue通过scope来接收MyCom.vue传过来的数据。值得注意的是,我们这里一般通过scoped来接收数据。

效果:

Untitled


解构作用域插槽的 Prop

作用域插槽对外提供的数据对象,可以使用解构赋值简化数据的接收过程。

示例代码如下:

<template>
  <div>
    <h1>App 根组件</h1>
    <hr />
    <!-- 作用域插槽对外提供的数据对象,可以通过“解构赋值”简化接收的过程 -->
    <my-com>
      <template #default="{ user, msg }">
        <!-- [使用] 作用域插槽的数据 -->
        <p>{{ user.name }}</p>
        <p>{{ msg }}</p>
      </template>
    </my-com>
  </div>
</template>

声明作用域插槽

在封装 MyTable 组件的过程中,可以通过作用域插槽把表格每一行的数据传递给组件的使用者。示例代码如下:

<!-- 表格主体区域 -->
<tbody>
  <!-- 循环渲染表格数据 -->
  <tr v-for="item in list" :key="item.id">
		<!-- 下面的 slot 是一个【作用域插槽】 -->
    <slot :user="item"></slot>
  </tr>
</tbody>

使用作用域插槽

在使用 MyTable 组件时,自定义单元格的渲染方式,并接收作用域插槽对外提供的数据。

示例代码如下:

<!-- 使用自定义组件 -->
<my-table>
  <!-- 【接收】作用域插槽对外提供的数据 -->
  <template #default="{ user }">
    <!-- 【使用】作用域插槽的数据 -->
    <td>{{ user.id }}</td>
    <td>{{ user.name }}</td>
    <td>
      <input type="checkbox" :checked="user.state">
    </td>
  </template>
</my-table>

效果:

Untitled




自定义指令

  1. 什么是自定义指令

vue 官方提供了 v-for、v-model、v-if 等常用的内置指令。除此之外 vue 还允许开发者自定义指令。vue 中的自定义指令分为两类,分别是:私有自定义指令和全局自定义指令

  1. 声明私有自定义指令的语法

在每个 vue 组件中,可以在 directives 节点下声明私有自定义指令。

示例代码如下:

directives: {
    //  自定义一个私有指令
    focus: {
      // 当被绑定的元素插入到 DOM 中时,自动触发 mounted 函数
      mounted(el) {
        el.focus() // 让被绑定的元素自动获得焦点
      }
    }
  },

注意:自定义指令在使用的时候以v-开头,但是在声明的时候不需要加v-前缀

  1. 使用自定义指令

在使用自定义指令时,需要加上 v- 前缀。

示例代码如下:

<!-- 声明自定义指令时,指令的名字是 focus -->
<!-- 使用自定义指令时,需要加上 v- 指令前缀 -->
<input v-focus />
  1. 声明全局自定义指令的语法

全局共享的自定义指令需要通过“单页面应用程序的实例对象”进行声明,示例代码如下:

const app = Vue.createApp({})

// 注册一个全局自定义指令 `v-focue`
app.directive('focus', {
	// 当被绑定的元素插入到 DOM 中时,自动触发 mounted 函数
	mounted(el) {
		// Focus the element
		el.focus()
	}
})
  1. updated 函数

mounted 函数只在元素第一次插入 DOM 时被调用,当 DOM 更新时 mounted 函数不会被触发。 updated函数会在每次 DOM 更新完成后被调用。

示例代码如下:

app.directive('focus', {
	mounted(el) {  // 第一次插入 DOM 时触发这个函数
		el.focus()
	},
	updated(el) { // 每次 DOM 更新时都会触发 updated 函数
		el.focus()
	}
})

注意:在 vue2 的项目中使用自定义指令时,【 mounted -> bind 】【 updated -> update 】

  1. 函数简写

如果 mounted 和updated 函数中的逻辑完全相同,则可以简写成如下格式:

app.directive('focus', (el) => {
	// 在 mounted 和 updated 时都会触发相同的业务处理
	el.focus()
})
  1. 指令的参数值

在绑定指令时,可以通过“等号”的形式为指令绑定具体的参数值,示例代码如下:

<!-- 在使用 v-color 指令时, 可以通过“等号”绑定指令的值 -->
<input type="text" v-model.number="count" v-focus v-color="'red'">
<p v-color="'cyan'">{{ count }}</p>

<button @click="count++">+1</button>

//自定义 v-color 指令
app.directive('color', (el, binding) => {
  // binding.value 就是通过“等号”为指令绑定的值
  el.style.color = <binding class="value"></binding>
})



总结:

① 能够知道如何使用 ref 引用 DOM 和组件实例

通过 ref 属性指定引用的名称、使用 this.$refs 访问引用实例

② 能够知道 $nextTick 的调用时机

组件的 DOM 更新之后,才执行 $nextTick 中的回调

③ 能够说出 keep-alive 元素的作用

保持动态组件的状态

④ 能够掌握插槽的基本用法

标签、具名插槽、作用域插槽、v-slot: 简写为 #

⑤ 能够知道如何自定义指令

私有自定义指令、全局自定义指令

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

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

相关文章

TiDB亿级数据亚秒响应查询扩缩容

目录 1 查看数据分布2 当前集群部署拓扑3 扩容TiKV节点3.1 编写扩容脚本3.2 执行扩容命令3.2.1 命令格式3.2.2 执行命令 3.3 验证扩容信息3.3.1 查看节点信息3.3.2 通过dashboard查看 4 缩容TiKV节点4.1 查看节点信息4.2 执行缩容操作4.2.1 缩容命令4.2.2 执行命令 4.3 验证缩容…

Redis集群(分布式缓存):详解持久化、主从同步原理、哨兵机制、Cluster分片集群,实现高并发高可用

0、引言 单机式Redis存在以下问题&#xff0c;因此需要Redis集群化来解决这些问题 1、持久化 1.1 RDB&#xff08;Redis Database Backup file &#xff09;持久化 Redis数据快照&#xff0c;简单来说就是把内存中的所有数据都记录到磁盘中。当Redis实例故障重启后&#xff0c…

CSS 布局备忘录

CSS 布局 元素布局display:blockdisplay:inlinedisplay:inline-blockdisplay:inheritdisplay:none Position 布局Flex 布局父元素属性flex-directionflex-wrapflex-flowjustify-contentalign-itemsalign-content 子元素属性orderflex-growflex-shrinkflex-basisfelxalign-self …

电商--抢购总结

文章目录 业务流程业务难点技术难点技术方案技术方向具体落地客户端流控网关流控容器流控后端接口流控数据库流控 流控总结优化读取加速异步化流程处理系统扩容 压测监控 总结参考文献 业务流程 客户端抢购流程中会涉及到商品数据的读取用于商品展示&#xff0c;运营活动数据的…

MM32F3273G8P火龙果开发板MindSDK开发教程8 - MutilButton的移植

MM32F3273G8P火龙果开发板MindSDK开发教程8 - MutilButton的移植 1、MutilButton简介 MultiButton 是一个小巧简单易用的事件驱动型按键驱动模块&#xff0c;可无限量扩展按键&#xff0c;按键事件的回调异步处理方式可以简化你的程序结构&#xff0c;去除冗余的按键处理硬编…

NodeJS SessionToken验证⑧

文章目录 ✨文章有误请指正&#xff0c;如果觉得对你有用&#xff0c;请点三连一波&#xff0c;蟹蟹支持&#x1f618;前言登录鉴权Cookie&Session ExpressSession中间件 MVC演示登录鉴权JSON Web Token (JWT) Jsonwebtoken参数sign 方法verify 方法 封装JsonWebToke…

北邮22信通:第六章查找:BST树表(代码超详细逐步图解)

北邮22信通一枚~ 跟随课程进度每周更新数据结构与算法的代码和文章 持续关注作者 解锁更多邮苑信通专属代码~ 获取更多文章 请访问专栏&#xff1a; 北邮22信通_青山如墨雨如画的博客-CSDN博客 目录 讲解 1.构造函数 2.析构函数 3.查询函数 4.删除操作 &#xf…

全新出品!阿里 P5 工程师~P8 架构师晋升路线揭秘

阿里巴巴终于公开了从初级程序员到架构师的学习路线图&#xff0c;这里相对应的基本上就是从P5到P8的晋升体系&#xff01;今天老师将会带着大家从初级程序员开始一点点分享整个晋升体系&#xff01; 职级&#xff1a;初级程序员 薪资&#xff1a;6-12K 开发年限&#xff1a;0-…

PureComponent和Component的区别和底层处理机制

PureComponent和Component都是React中的组件类&#xff0c;但它们在实现细节和使用上有些差别。 Component是React中定义组件的基类&#xff0c;它的shouldComponentUpdate方法默认返回true&#xff0c;也就是说&#xff0c;每次调用setState或forceUpdate方法都会引发组件重新…

代码随想录第55天

1.判断子序列&#xff1a; 动态规划五部曲分析如下&#xff1a; 确定dp数组&#xff08;dp table&#xff09;以及下标的含义 dp[i][j] 表示以下标i-1为结尾的字符串s&#xff0c;和以下标j-1为结尾的字符串t&#xff0c;相同子序列的长度为dp[i][j]。 注意这里是判断s是否…

百度新闻源调整:自媒体权重降低,官方媒体优势突显

我是卢松松&#xff0c;点点上面的头像&#xff0c;欢迎关注我哦&#xff01; 根据黑猫发稿的消息&#xff0c;自6月1日起&#xff0c;百度新闻源取消了大部分自媒体新闻源的收录&#xff0c;包括搜狐自媒体、企鹅号、网易号&#xff0c;甚至百度自己的百家号也受到了影响。 …

X2000 Linux 低功耗

一、进入休眠 当系统启动后&#xff0c;在命令终端输入&#xff1a; echo mem> /sys/power/state 即可立即进入休眠&#xff0c;功耗也随之降低。 二、配置中断唤醒GPIO 1、确认kernel默认配置文件 进入到/tools/iconfigtool/IConfigToolApp/路径下&#xff0c;执行./…

【Pm4py第四讲】关于Conversion

本节用于介绍pm4py中的转换函数&#xff0c;包括日志、事件流、数据块的转换、Petei网、流程树、BPMN的转换、可达图、面向对象日志等。 1.函数概述 本次主要介绍Pm4py中一些常见的转换函数&#xff0c;总览如下表&#xff1a; 函数名说明convert_log_to_networkx&#xff08;…

Java(30天拿下---第一天)

Java开发&#xff08;30天拿下---第一天&#xff09; 一 hello world以及JDK,JRE,JVM二 转义字符三 注释四 代码规范五 DOS命令&#xff08;了解&#xff09;六 变量1.加号的使用2.数据类型整型浮点型字符类型布尔类型自动类型转换强制类型转换String类型 七 API文档 一 hello …

React | Redux的使用详解

✨ 个人主页&#xff1a;CoderHing &#x1f5a5;️ React.js专栏&#xff1a;React.js Redux的使用详解 &#x1f64b;‍♂️ 个人简介&#xff1a;一个不甘平庸的平凡人&#x1f36c; &#x1f4ab; 系列专栏&#xff1a;吊打面试官系列 16天学会Vue 7天学会微信小程序 N…

亚马逊云科技Serverless数据分析,助力猎豹移动构建更高性价比数据仓库

也许你也听过这样一句话&#xff1a;“21世纪什么最贵&#xff1f;人才&#xff01;”当数字经济全面席卷而来&#xff0c;这个问题的答案不可置否地变为了“数据”。通过数据分析获取近乎实时的洞察&#xff0c;以驱动业务的全流程&#xff0c;是企业数字化转型的必经之路。借…

【文末送书】微服务拆分规范

目录 一. &#x1f981; 什么是微服务&#xff1f;二. &#x1f981; 拆分模型Ⅰ. 压力模型拆分1. 垂直拆分&#xff08;Vertical Decomposition&#xff09;2. 水平拆分&#xff08;Horizontal Decomposition&#xff09;3. 动态拆分&#xff08;Dynamic Decomposition&#x…

初识网络之http协议

目录 一、http协议含义 二、 认识URL 三、urlencode与urldecode 1. urlencode 2. urldecode 四、http协议响应与请求格式 1. http协议请求格式 2.http协议响应格式 3. http请求实际形式 3.1 程序准备 3.2 浏览器发起请求 3.3 请求行内容 3.4 请求报头内容 4. htt…

2022年国赛高教杯数学建模E题小批量物料的生产安排解题全过程文档及程序

2022年国赛高教杯数学建模 E题 小批量物料的生产安排 原题再现 某电子产品制造企业面临以下问题&#xff1a;在多品种小批量的物料生产中&#xff0c;事先无法知道物料的实际需求量。企业希望运用数学方法&#xff0c;分析已有的历史数据&#xff0c;建立数学模型&#xff0c…

mysql联合索引详解

比较简单的是单列索引&#xff08;btree&#xff09;。遇到多条件查询时&#xff0c;不可避免会使用到多列索引。联合索引又叫复合索引。 btree结构如下&#xff1a; 每一个磁盘块在mysql中是一个页&#xff0c;页大小是固定的&#xff0c;mysql innodb的默认的页大小是16k&a…