当前位置: 首页 > article >正文

Vue学习记录19

TransitonGroup

<TransitionGroup> 是一个内置组件,用于对 v-for 列表中的元素或组件的插入、移除和顺序改变添加动画效果。

和 <Transtion> 的区别

  • <TranstionGroup> 支持和 <Transtion> 基本相同的 props、CSS过渡 class 和 JavaScript 钩子监听器,但有以下几点区别:
  • 默认情况下,它不会渲染一个容器元素。但你可以通过传入 tag prop 来指定一个元素作为容器元素来渲染。
  • 过渡模式在这里不可用,因为不再是在互斥的元素之间进行切换。
  • 列表中的每个元素都必须有一个独一无二的 key attribute。
  • CSS 过渡 class 会被应用在列表内的元素上,而不是容器元素上。

Tip

当在DOM 内模板中使用时,组件名需要写为 <transition-group>

进入/离开动画

这里是 <TransitionGroup> 对一个 v-for 列表添加进入/离开动画的示例:

<TransitionGroup name="list" tag="ul">
  <li v-for="item in items" :key="item">
    {{ item }}
  </li>
</TransitionGroup>
.list-enter-active,
.list-leave-active {
  transition: all 0.5s ease;
}
.list-enter-from,
.list-leave-to {
  opacity: 0;
  transform: translateX(30px);
}



移动动画

上面的示例有一些明显的缺陷:当某一项被插入或移除时,它周围的元素会立即发生“跳跃”而不是平稳地移动。我们可以通过添加一些额外地CSS规则来解决这个问题:

.list-move, /* 对移动中的元素应用的过渡 */
.list-enter-active,
.list-leave-active {
  transition: all 0.5s ease;
}

.list-enter-from,
.list-leave-to {
  opacity: 0;
  transform: translateX(30px);
}

/* 确保将离开的元素从布局流中删除
  以便能够正确地计算移动的动画。 */
.list-leave-active {
  position: absolute;
}

自定义过渡组 class 

你还可以通过向 <TransitionGroup>  传递 moveclass prop为移动元素指定自定义过渡 class,类似于自定义过渡 class。

渐进延迟列表动画

通过在 JavaScript 钩子中读取元素地 data attribute,我们可以实现带渐进延迟地列表动画。首先,我们把每一个元素地索引渲染为该元素上的一个 data attribute:

<TransitionGroup
  tag="ul"
  :css="false"
  @before-enter="onBeforeEnter"
  @enter="onEnter"
  @leave="onLeave"
>
  <li
    v-for="(item, index) in computedList"
    :key="item.msg"
    :data-index="index"
  >
    {{ item.msg }}
  </li>
</TransitionGroup>

接着,在 JavaScript 钩子中,我们基于当前元素的 data attribute 对该元素的进场动画添加一个延迟。

function onEnter(el, done) {
  gsap.to(el, {
    opacity: 1,
    height: '1.6em',
    delay: el.dataset.index * 0.15,
    onComplete: done
  })
}

KeepAlive

<KeepAlive> 是一个内置组件,它的功能是在多个组件间动态切换时缓存被移除的组件实例。

基本使用

默认情况下,一个组件实例在被替换掉后会被销毁。这会导致它丢失其中所有已变化的状态——当这个组件再一次被显示时,会创建一个只带有初始状态的新实例。

在切换时创建新的组件实例通常是有意义的,但有时我们的确想要组件能在被“切走”的时候保留它们的状态。要解决这个问题,我们可以用 <KeepAlive> 内置组件将这些组件包装起来:

<!-- 非活跃的组件将会被缓存! -->
<KeepAlive>
  <component :is="activeComponent" />
</KeepAlive>

现在,在组件切换时状态也能保留了。

包含/排除

<KeepAlive>默认会缓存内存的所有组件实例,但我们可以通过 includeexclude prop来定制该行为。这两个 prop 的值都可以是一个以英文逗号分隔的字符串、一个正则表达式,或是包含着两种类型的一个数组:

<!-- 以英文逗号分隔的字符串 -->
<KeepAlive include="a,b">
  <component :is="view" />
</KeepAlive>

<!-- 正则表达式 (需使用 `v-bind`) -->
<KeepAlive :include="/a|b/">
  <component :is="view" />
</KeepAlive>

<!-- 数组 (需使用 `v-bind`) -->
<KeepAlive :include="['a', 'b']">
  <component :is="view" />
</KeepAlive>

它会根据组件的 name 选项进行匹配,所以组件如果想要条件性地被 KeepAlive 缓存,就必须显式声明一个 name 选项。

TIP

在 3.2.34 或以上的版本中,使用 <script setup> 的单文件组件会自动根据文件名生成对应的 name 选项,无序再手动声明。

最大缓存实例数 

我们可以通过传入 max prop 来限制可被缓存的最大组件实例数。 <KeepAlive> 的行为在指定了 max 后类似一个 LRU 缓存:如果缓存的实例数量超过指定的那个最大数量,则最久没有被访问的缓存实例将被销毁,以便为新的实例腾出空间。

<KeepAlive :max="10">
  <component :is="activeComponent" />
</KeepAlive>

缓存实例的声明周期

当一个组件实例从 DOM 上移除但因为被 <KeepAlive> 缓存而仍作为组件树的一部分时,它将变为不活跃状态而不是被卸载。当一个组件实例作为缓存树的一部分插入到DOM中时,它将重新被激活。

一个持续存在的组件可以通过 onActivated() 和 onDeactivated()  注册相应的两个状态的生命周期钩子:

<script setup>
import { onActivated, onDeactivated } from 'vue'

onActivated(() => {
  // 调用时机为首次挂载
  // 以及每次从缓存中被重新插入时
})

onDeactivated(() => {
  // 在从 DOM 上移除、进入缓存
  // 以及组件卸载时调用
})
</script>

请注意:

  • onActivated 在组件挂载时也会调用,并且 onDeactivated 在组件卸载时也会调用。
  • 这两个钩子不仅适用于 <KeepAlive>  缓存的根组件,也适用于缓存树中的后代组件。

Teleport

<Teleport> 是一个内置组件,它可以将一个组件内部的一部分模板“传送”到该组件的 DOM 结构外层的位置去。

基本用法

有时我们可能会遇到这样的场景:一个组件模板的一部分在逻辑上从属于该组件,但从整个应用视图的角度来看,它在DOM中应该被渲染在整个 Vue 应用外部的其他地方。

这类场景最常见的例子就是全屏的模态框。理想情况下,我们希望触发模态框的按钮和模态框本身是在同一个组件中,因为它们都与组件的开关状态有关。但这意味着该模态框将于按钮一起渲染在应用DOM结构里很深的地方。这会导致该模态框的 CSS 布局代码很难写。

试想下面这样的 HTML 结构:

<div class="outer">
  <h3>Tooltips with Vue 3 Teleport</h3>
  <div>
    <MyModal />
  </div>
</div>

接下来来看看 <MyModal> 的实现

<script setup>
import { ref } from 'vue'

const open = ref(false)
</script>

<template>
  <button @click="open = true">Open Modal</button>

  <div v-if="open" class="modal">
    <p>Hello from the modal!</p>
    <button @click="open = false">Close</button>
  </div>
</template>

<style scoped>
.modal {
  position: fixed;
  z-index: 999;
  top: 20%;
  left: 50%;
  width: 300px;
  margin-left: -150px;
}
</style>

这个组件中有一个 <button> 按钮 按钮来触发打开模态框,和一个 class 名为 .modal 的 <div>,它包含了模态框的内容和一个用来关闭的按钮。

当在初始HTML结构中使用这个组件时,会有一个潜在的问题:

  •  position: fixed 能够相对于浏览器窗口放置有一个条件,那就是不能有任何祖先元素设置了 transform、perspective 或者 filter 样式属性。也就是说如果我们想要用 CSS transform 为祖先节点 <div class="outer"> 设置动画,就会不小心破坏模态框的布局!
  • 这个模态框的 z-index 受限于它的容器元素,如果有其他元素与 <div class="outer"> 重叠并有更高的 z-index,则它会覆盖住我们的模态框。

<Teleport> 提供了一个更简单的方式来解决此类问题,让我们不需要再顾虑 DOM 结构的问题。让我们用 <Teleport> 改写一下 <MyModal>:

<button @click="open = true">Open Modal</button>

<Teleport to="body">
  <div v-if="open" class="modal">
    <p>Hello from the modal!</p>
    <button @click="open = false">Close</button>
  </div>
</Teleport>

<Teleport> 接收一个 to prop 来指定传送的目标。 to 的值可以是一个 CSS 选择器字符串,也可以是一个 DOM 元素对象。这段代码的作用就是高速Vue “把以下模板片段传送到 body 标签下”。

也可以将 <Teleport> 和 <Transition> 结合使用来创建一个带动画的模态框。

Tip

<Teleport>  挂载时,传送的 to 目标必须已经存在与 DOM 中。理想情况下,这应该是整个 Vue应用 DOM 外部的一个元素。如果目标元素也是由Vue 渲染的,你需要确保挂载 <Teleport>  之前先挂载这个元素。

搭配组件使用

<Teleport>  只改变了渲染的 DOM 结构,他不会影响组件间的逻辑关系。也就是说,如果 <Teleport>  包含了一个组件,那么该组件始终和使用了 <Teleport>  的组件保持逻辑上的父子关系。 传入的 props 和 触发的事件也会照常工作。

 这也意味着来自父组件的注入也会按预期工作,子组件将在 Vue Devtools 中嵌套在父级组件下面,而不是放在实际内容移动到的地方。

禁用 Teleport

在某些场景下可能需要视情况禁用 <Teleport> 。举例来说,我们想要在桌面端将一个组件当作浮层来渲染,但在移动端则当作行内组件。我们可以通过对 <Teleport> 动态地传传入一个 disabled prop来处理这两种不同情况。

<Teleport :disabled="isMobile">
  ...
</Teleport>

这里地 isMobile 状态可以根据 CSS media query的不同结果动态地更新。

多个 Teleport 共享目标。

一个可重用的模块框组件可能同时存在多个实例。对于此类场景多个 <Teleport> 组件可以将其内容挂载在同一个目标元素上,而顺序就是简单的顺序追加,后挂载的将排在目标元素下更后面的位置上。

比如下面这样的用例:

<Teleport to="#modals">
  <div>A</div>
</Teleport>
<Teleport to="#modals">
  <div>B</div>
</Teleport>

渲染的结果为:

<div id="modals">
  <div>A</div>
  <div>B</div>
</div>

延迟解析的Teleport

在Vue 3.5及更高版本中,我们可以使用 defer prop推迟Teleport的目标解析,直到应用的其他部分挂载。这允许 Teleport 将由 Vue渲染且位于组件树之后部分的容器元素作为目标:

<Teleport defer to="#late-div">...</Teleport>

<!-- 稍后出现于模板中的某处 -->
<div id="late-div"></div>

请注意,目标元素必须与 Teleport 在同一个挂载/更新周期内渲染,即如果 <div> 在一秒后才挂载,Teleport 仍然会报错。 延迟 Teleport的原理与 mounted 生命周期钩子类似。


http://www.kler.cn/a/552282.html

相关文章:

  • CPP集群聊天服务器开发实践(六):Redis发布订阅消息队列及服务器集群通信
  • JAVA过滤器(学习自用)
  • Vue.js 框架
  • 基于TCP与UDP协议的性能测试研究
  • 【AI】Pytorch基础与张量计算入门
  • C++ queue:数据结构的“排队哲学”与“先进先出法则
  • python爬虫系列课程3:解决爬虫过程中遇到的编码问题
  • Excel如何实现行分级,以及如何用Python 3实现Excel行分级
  • C++(23):unreachable
  • 深入解析 Flutter 高级路由管理:使用 go_router 和 auto_route 实现复杂路由与拦截
  • Mermaid绘图技巧:如何在节点文本中实现换行
  • 力扣 跳跃游戏 II
  • 从WebRTC到EasyRTC:嵌入式适配的视频通话SDK实现低延迟、高稳定性音视频通信
  • springboot024-玩具租赁系统
  • Java-数据结构-(HashMap HashSet)
  • 阶段 1:Kafka基础认知
  • WPF高级 | WPF 自定义控件开发:从需求分析到完整实现
  • MoE硬件部署
  • el-table已经选中的项,通过selectable属性不可以再次选择
  • 视频编解码标准中的 Profile 和 Level