一文详解Vue3内置组件的使用
作者:whhhhhhhhhw
前言:
vue3作为当前主流的前端框架之一,其内置组件体系为开发者提供了高效、灵活的解决方案。这些组件不仅简化了常见功能的开发流程,还通过组合式API和性能优化进一步提升开发体验。
建议通过官方文档获取最准确的信息,避免第三方解读带来的偏差。官方资源通常包含最新更新和完整细节,确保学习内容的权威性。官网地址:vue3内置组件
1.<Transition>
熟悉css动画的就可以看出这跟过渡动画有关,官网也说明了它可以为单个元素或组件提供动画过渡的效果。它可以将进入和离开动画应用到通过默认插槽传递给它的元素或组件上进入或离开可以由以下的条件之一触发:
- 由v-if触发
- 由v-show触发
- 由特殊元素<component>切换的动态组件
- 改变特殊的key属性
<template> <div class="app"> <button @click="show = !show">点击</button> <transition> <div v-if="show">hello</div> </transition> </div> </template> <script setup> import { ref } from 'vue'; const show = ref(true) </script> <style scoped> .v-enter-active, .v-leave-active { transition:opacity 0.5s ease; } .v-enter-from, .v-leave-to { opacity: 0; } </style>
这就是官网上面的一个例子,点击按钮文字隐藏,但它不是直接隐藏的,而是opacity的值从1到0经过了0.5s,因此用户看到的是文字慢慢的在消失,样式中.v-enter-active等是什么意思呢?官网这边给了一张图就很好理解了。
Enter表示进入,Leave表示离开。
v-enter-from表示进入动画的起始状态,配合上面的例子就很好理解了,开始起始状态的透明度为0,到进入动画的结束状态也就是v-enter-to的透明度变为1,这个过程就是v-enter-active,因此我们需要在这个过程中设置动画时间以及过渡的速度,就比如上面设置的ease表示从快到慢过渡。理解了进入,离开也就同理了。
但了解这个还远远不够,也无法应对项目中的所有场景,当我们的项目中需要多个transition内置组件并它们的动画效果不同时,因此需要给每个transition组件定义一个名字,好将它们区分开来,避免样式混淆,只需要在transition内置组件上添加一个name属性,给它一个名称,代码如下:
<transition name="fade"> <div v-if="show">hello</div> </transition>
进入动画与结束动画的类名也要进行修改,只需要将v替换成我们设置的过渡效果名:
.fade-enter-active, .fade-leave-active { transition: opacity 0.5s ease; } .fade-enter-from, .fade-leave-to { opacity: 0; }
2.<TransitionGroup>
用于对 v-for 列表中的元素或组件的插入、移除和顺序改变添加动画效果。
<TransitionGroup>内置组件和<Transition>内置组件一样都是添加动画效果,拥有相同的props和特定的CSS class选择器以及相同的JavaScript钩子函数,它们的区别如下:
- 默认情况下,它不会渲染一个容器元素。但你可以通过传入 tag prop来指定一个元素作为容器元素来渲染。
- 过渡模式在这里不可用,因为我们不再实在互斥的元素之间进行切换。
- 列表中的每个元素都必须有一个独一无二的 key attribute。
- CSS 过渡 class 会被应用在列表内的元素上,而不是容器元素上。
- <TransitionGroup>用作与列表,<Transition>用作于单个元素。
示例:
<template> <div class="app"> <button @click="addItem">Add</button> <transition-group name="list" tag="ul"> <li v-for="item in items" :key="item.id"> {{ item.value }} <button @click="deleteItem(item.id)">Delete</button> </li> </transition-group> </div> </template> <script setup> import { ref } from 'vue'; const items = ref([ { id: 1, value: 1 }, { id: 2, value: 2 }, { id: 3, value: 3 } ]); // 添加 function addItem() { items.value.unshift({ id: Date.now(), value: Math.floor(Math.random() * 11) }); } // 删除 function deleteItem(id) { items.value = items.value.filter(item => item.id !== id); } </script>
tag='ul'时,会将其渲染为ul标签,因此可以在其添加li标签列表。
添加动画样式
.list-move, .list-enter-active, .list-leave-active { transition: all 1s ease; } .list-enter-from, .list-leave-to { opacity: 0; transform: translateX(30px); }
当我们往数据前面添加数据时,下面的数据会有一个像“让位置”的操作,但这个动作有点僵硬,因此可以使用.v-move给其添加动画效果。
但是当我们删除数据时,下面的数据会在上面的数据删除后立马向上去“占位置”,当我们也希望这样有一个过渡的动画效果时,就需要在.list-leave-active中添加position: absolute;,就是需要在离开的过程中,让其脱离文档流,这样做的原因是方便浏览器正确的计算移动的动画。
.list-leave-active{ position: absolute; }
3.<keepAlive>
它的功能是在多个组件间动态切换时缓存被移除的组件实例.
<keepAlive>包裹动态组件时,会缓存不活跃的组件实例,而不是去销毁它们。
任何时候都只能有一个活跃组件实例作为<keepAlive>的直接子节点。
当一个组件在<keepAlive>中被切换时,它的activated和deactivated生命周期钩子将被调用,这两个生命周期是<keepAlive>特有的,用来替代mounted和unmounted。这适用于<keepAlive>的直接子节点及其所有子孙节点。
基本使用
<template> <div class="app"> <label><input type="radio" v-model="componentId" :value="home">home</label> <label><input type="radio" v-model="componentId" :value="User">User</label> <component :is="componentId"></component> </div> </template> <script setup> import { shallowRef } from 'vue'; import home from './components/home.vue'; import User from './components/User.vue'; const componentId = shallowRef(home); </script>
当我点击复选框时,会进行组件的切换
home:
User:
当我们在home组件中点击按钮会增加数据的值,但切换到User组件再切回到home组件中时,组件会被从新渲染,因此原本添加的值会回到初始值,但有些场景下我们不需要组件从新渲染,希望将其缓存起来,就可以使用到<keepAlive>了,方法很简单,只需要用<keepAlive>包裹需要切换的组件即可。
<template> <div class="app"> <label><input type="radio" v-model="componentId" :value="home">home</label> <label><input type="radio" v-model="componentId" :value="User">User</label> <keep-alive> <component :is="componentId"></component> </keep-alive> </div> </template>
现在,在组件切换时状态也能被保留了。
包含/排除
因为<keepAlive>默认会缓存内部的所有组件实例,可能有些情况下我们不需要包含的所有组件实例都被缓存,可以通过 包含(include)和 排除(exclude)prop来定制该行为。这两个prop的值都可以是一个以是一个以英文逗号分隔的字符串、一个正则表达式,或是包含这两种类型的一个数组:
<keep-alive include="home"> <component :is="componentId"></component> </keep-alive>
这样它就只会缓存home组件。
在 Vue3.2.34 或以上的版本中,使用 <script setup> 的单文件组件会自动根据文件名生成对应的 name 选项,无需再手动声明。
最大缓存实例数
可以通过传入 max prop来限制可被缓存的最大组件实例数。
如果缓存的实例数量即将超过指定的那个最大数量,则最久没有被访问的缓存实例将被销毁,以便为新的实例腾出空间。
<keep-alive :max="10"> <component :is="componentId"></component> </keep-alive>
缓存实例的生命周期
在 Vue.js 的<keep-alive>组件中,被缓存的组件实例会经历特定的生命周期钩子,这些钩子与普通组件的生命周期有所不同。以下是缓存实例的完整生命周期:
activated:
当缓存组件被激活(从缓存中重新插入到 DOM 中)时触发。适合在此钩子中执行需要恢复的操作,例如重新加载数据或启动定时器。
deactivated:
当缓存组件被销毁(从 DOM 中移除并存入缓存)时触发。适合在此钩子中执行清理操作,例如清除定时器或取消未完成的请求。
home.vue:
<template> <div class="home"> <button @click="num++">Add</button> <p>{{ num }}</p> </div> </template> <script setup> import { ref, onActivated, onDeactivated } from 'vue' const num = ref(0) onActivated(() => { console.log('组件被激活'); }); onDeactivated(() => { console.log('组件被销毁'); }); </script>
注意事项
- 缓存组件的 created 和 mounted 钩子仅在首次加载时触发,后续激活时不会重复触发。
- 如果组件被缓存后再次激活,只会触发 activated 钩子,而不会触发 mounted。
- 当缓存实例数量超过 max 限制时,最久未被访问的实例会被销毁,其 destroyed 钩子会被触发
- 这两个钩子不仅适用于<keep-alive>缓存的根组件,也适用于缓存树中的后代组件。
4.<Teleport>
Teleport 是 Vue.js 3 中引入的一个内置组件,允许将子节点渲染到 DOM 树中的其他位置,而不受父组件层级结构的限制。这在处理模态框、通知、弹出菜单等需要脱离当前 DOM 结构的场景时非常有用。
基本使用
Teleport 组件通过 to 属性指定目标容器,目标容器可以是 DOM 选择器字符串或实际的 DOM 元素。
App.vue:
<template> <div class="app"> <button @click="showMsg = true">Click me</button> <div> <MessageBox msg="Hello World" v-model:showMsg="showMsg"/> </div> </div> </template> <script setup> import { ref } from 'vue' import MessageBox from './components/MessageBox.vue'; const showMsg = ref(false); </script>
MessageBox.vue:
<template> <div class="message" v-if="showMsg"> <div class="message_box"> <div class="message_box_text">{{ msg }}</div> <div class="message_box_button"> <el-button type="primary" @click="handleClick">确定</el-button> </div> </div> </div> </template> <script setup> const { msg, showMsg } = defineProps({ msg: String, showMsg: Boolean }) const emit = defineEmits(['update:showMsg']) function handleClick() { emit('update:showMsg', false) } </script> <style scoped lang="less"> .message { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background-color: rgba(0, 0, 0, .4); .message_box { padding: 0 10px; width: 300px; height: 150px; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: #fff; border-radius: 20px; display: flex; flex-direction: column; overflow: hidden; .message_box_text { flex: 0 0 80px; display: flex; align-items: center; justify-content: center; } .message_box_button { flex: 1; display: flex; align-items: center; justify-content: center; } } } </style>
这边我写了个很简单的示例代码,点击按钮会出现一个模态框,点击模态框中的确定按钮会隐藏模态框,这里面就涉及到了组件通信,如果有不懂的可以看看我之前的文章关于组件通信的——Vue3组件通信
打开控制台可以看到模态框的位置
在 Vue 3 中,<Teleport>件可用于将模板中的内容渲染到 DOM 的其他位置,而不受父组件层级的限制。
示例:将弹窗内容移至 body 元素下
<template> <teleport to='body'> <div class="message" v-if="showMsg"> <div class="message_box"> <div class="message_box_text">{{ msg }}</div> <div class="message_box_button"> <el-button type="primary" @click="handleClick">确定</el-button> </div> </div> </div> </teleport> </template>
关键点说明
- to 属性指定目标容器,可以是 CSS 选择器(如#app、.container)或 DOM 元素(如 body)。
- 被<teleport> 包裹的内容仍保持 Vue 的响应式特性,事件和逻辑不受影响。
- 适合处理模态框、通知提示等需要脱离当前组件层级的场景。
注意事项
- 确保目标容器在 DOM 中已存在,否则内容无法正确挂载。
- 动态修改 to 属性可实现内容在不同容器间切换。
禁用 Teleport
在某些场景中,可能需要根据特定条件禁用 Teleport 功能。例如,针对不同设备或布局需求,动态控制组件的位置。
我们可以通过对<Teleport>态地传入一个 disabled prop 来处理这两种不同情况。
<template> <teleport to='body' :disabled="showMsg"> <div class="message" v-if="showMsg"> <div class="message_box"> <div class="message_box_text">{{ msg }}</div> <div class="message_box_button"> <el-button type="primary" @click="handleClick">确定</el-button> </div> </div> </div> </teleport> </template>
结语:
在vue3中其实还有一个内置组件<Suspense>,为什么在这里没有介绍呢?那是因为作为内置组件未被详细介绍,主要原因是其当前仍处于实验性阶段。官方明确声明该功能尚未稳定,未来API可能发生变更,故不推荐在生产环境中依赖这一特性。
随着 Vue 生态的不断发展,掌握这些核心组件将有助于开发更灵活、高效的前端应用。建议结合官方文档和实际项目实践,深入理解其使用场景和最佳实践。
到此这篇关于Vue3内置组件的使用的文章就介绍到这了,更多相关Vue3内置组件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!