11.25 Vue内置组件

动态组件

语法

有些场景会需要在两个组件间来回切换,比如 Tab 界面, 可通过<component>动态组件实现

HTML 复制代码
<!-- Home为组件名 -->
<component is="Home"></component>
<component :is="'Home'"></component>
<!-- currentTab 改变时组件也改变 -->
<component :is="currentTab"></component>

案例

Home.vue

HTML 复制代码
<template>
    <div class="tab">
        Home component
    </div>
</template>

Posts.vue

HTML 复制代码
<template>
    <div class="tab">
        Posts component
    </div>
</template>

Archive.vue

HTML 复制代码
<template>
    <div class="tab">
        Archive component
    </div>
</template>

App.vue

HTML 复制代码
<script>
import Home from './Home.vue'
import Posts from './Posts.vue'
import Archive from './Archive.vue'

export default {
  components: {
    Home,
    Posts,
    Archive
  },
  data() {
    return {
      currentTab: 'Home',
      tabs: ['Home', 'Posts', 'Archive']
    }
  }
}
</script>
<template>
  <div class="demo">
    <button
       v-for="tab in tabs"
       :key="tab"
       :class="['tab-button', { active: currentTab === tab }]"
       @click="currentTab = tab"
     >
      {{ tab }}
    </button>
    <component :is="currentTab" class="tab"></component>
  </div>
</template>
<style>
.demo {
  font-family: sans-serif;
  border: 1px solid #eee;
  border-radius: 2px;
  padding: 20px 30px;
  margin-top: 1em;
  margin-bottom: 40px;
  user-select: none;
  overflow-x: auto;
}
.tab-button {
  padding: 6px 10px;
  border-top-left-radius: 3px;
  border-top-right-radius: 3px;
  border: 1px solid #ccc;
  cursor: pointer;
  background: #f0f0f0;
  margin-bottom: -1px;
  margin-right: -1px;
}
.tab-button:hover {
  background: #e0e0e0;
}
.tab-button.active {
  background: #e0e0e0;
}
.tab {
  border: 1px solid #ccc;
  padding: 10px;
}
</style>

Transition 过渡组件

Vue 提供了两个内置组件,可以帮助你制作基于状态变化的过渡和动画:

Transition 组件

认识Transition组件

Transition 是一个内置组件,这意味着它在任意别的组件中都可以被使用,无需注册。它可以将进入和离开动画应用到通过默认插槽传递给它的元素或组件上。进入或离开可以由以下的条件之一触发:

  • 由 v-if 所触发的切换

  • 由 v-show 所触发的切换

  • 由特殊元素 <component> 切换的动态组件

  • 改变特殊的 key 属性

基础用法
HTML 复制代码
<button @click="show = !show">Toggle</button>
<Transition name="fade">
  <p v-if="show">hello</p>
</Transition>
CSS 复制代码
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.5s ease;
}
.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}

TIP<Transition> 仅支持单个元素或组件作为其插槽内容。如果内容是一个组件,这个组件必须仅有一个根元素。 当一个 <Transition> 组件中的元素被插入或移除时,会发生下面这些事情: Vue 会自动检测目标元素是否应用了 CSS 过渡或动画。如果是,则一些 CSS 过渡 class 会在适当的时机被添加和移除。

CSS****过渡class

!\[e3760062-2101-4ccb-bbbe-9e978971acf1.png]

CSS****的animation
JavaScript 复制代码
<Transition name="bounce">
  <p v-if="show" style="text-align: center;">
    Hello here is some bouncy text!
  </p>
</Transition>
CSS 复制代码
.bounce-enter-active {
  animation: bounce-in 0.5s;
}
.bounce-leave-active {
  animation: bounce-in 0.5s reverse;
}
@keyframes bounce-in {
  0% {
    transform: scale(0);
  }
  50% {
    transform: scale(1.25);
  }
  100% {
    transform: scale(1);
  }
}
可复用过渡效果

得益于 Vue 的组件系统,过渡效果是可以被封装复用的。要创建一个可被复用的过渡,我们需要为 <Transition> 组件创建一个包装组件,并向内传入插槽内容

JavaScript 复制代码
<!-- MyTransition.vue -->
<script>
</script>
<template>
  <!-- 包装内置的 Transition 组件 -->
  <Transition
    name="my-transition">
    <slot></slot> <!-- 向内传递插槽内容 -->
  </Transition>
</template>
<style>
/*必要的 CSS...
  注意:避免在这里使用 <style scoped>
  因为那不会应用到插槽内容上
*/
</style>

使用自定义过渡组件

HTML 复制代码
<MyTransition>
  <div v-if="show">Hello</div>
</MyTransition>
出现时过渡

如果你想在某个节点初次渲染时应用一个过渡效果,你可以添加 appear

prop:

HTML 复制代码
<Transition appear>
</Transition>
过渡模式

先执行离开动画,然后在其完成之后再执行元素的进入动画

HTML 复制代码
<Transition mode="out-in">
</Transition>
组件间过渡

<Transition> 也可以作用于动态组件之间的切换

HTML 复制代码
<Transition name="fade" mode="out-in">
  <component :is="activeComponent"></component>
</Transition>
动态过渡
HTML 复制代码
<Transition :name="transitionName">
</Transition>

TransitionGroup 组件

会在一个 v-for 列表中的元素或组件被插入,移动,或移除时应用动画。

HTML 复制代码
<script>
import { shuffle } from 'lodash'
const getInitialItems = () => [1, 2, 3, 4, 5]
let id = getInitialItems().length + 1
export default {
  data() {
    return {
      items: getInitialItems()
    }
  },
  methods: {
    insert() {
      const i = Math.round(Math.random() * this.items.length)
      this.items.splice(i, 0, id++)
    },
    reset() {
      this.items = getInitialItems()
    },
    shuffle() {
      this.items = shuffle(this.items)
    },
    remove(item) {
      const i = this.items.indexOf(item)
      if (i > -1) {
        this.items.splice(i, 1)
      }
    }
  }
}
</script>
<template>
  <button @click="insert">insert at random index</button>
  <button @click="reset">reset</button>
  <button @click="shuffle">shuffle</button>
  <TransitionGroup tag="ul" name="fade" class="container">
    <div v-for="item in items" class="item" :key="item">
      {{ item }}
      <button @click="remove(item)">x</button>
    </div>
  </TransitionGroup>
</template>
<style>
.container {
  position: relative;
  padding: 0;
}
.item {
  width: 100%;
  height: 30px;
  background-color: #f3f3f3;
  border: 1px solid #666;
  box-sizing: border-box;
}
/* 1. 声明过渡效果 */
.fade-move,
.fade-enter-active,
.fade-leave-active {
  transition: all 0.5s cubic-bezier(0.55, 0, 0.1, 1);
}
/* 2. 声明进入和离开的状态 */
.fade-enter-from,
.fade-leave-to {
  opacity: 0;
  transform: scaleY(0.01) translate(30px, 0);
}
/* 3. 确保离开的项目被移除出了布局流
      以便正确地计算移动时的动画效果。 */
.fade-leave-active {
  position: absolute;
}
</style>

Vue2和Vue3的区别

Vue2

CSS 复制代码
/* vue2的类名没有from和to */
.fade-enter,
.fade-leave{
  opacity: 0;
}

Vue3

CSS 复制代码
/* vue3需要添加from和to*/
.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}

KeepAlive****组件 (重要)

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

案例

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

包含/排除

include和exclude中的标识符为组件定义中的name选项的值

HTML 复制代码
<!-- 以英文逗号分隔的字符串 -->
<!-- 包含 -->
<KeepAlive include="a,b">
  <component :is="view" />
</KeepAlive>

<!-- 排除 -->
<KeepAlive exclude="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>

最大缓存实例数

如果缓存的实例数量即将超过指定的那个最大数量,则最久没有被访问的缓存实例将被销毁,以便为新的实例腾出空间。

HTML 复制代码
<KeepAlive :max="10">
  <component :is="activeComponent" />
</KeepAlive>

缓存实例的生命周期

一个持续存在的组件可以通过 activated(激活) 和 deactivated(失活) 选项来注册相应的两个状态的生命周期钩子

JavaScript 复制代码
export default {
  activated() {
    // 在首次挂载、
    // 以及每次从缓存中被重新插入的时候调用
  },
  deactivated() {
    // 在从 DOM 上移除、进入缓存
    // 以及组件卸载时调用
  }
}

这两个钩子不仅适用于 <KeepAlive> 缓存的根组件,也适用于缓存树中的后代组件

Teleport组件

vue2没有Teleport组件

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

应用场景

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

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

全屏模态框案例

Parent.vue

HTML 复制代码
<script>
import Modal from './Modal.vue'
export default {
  components: {
    Modal
  },
  data() {
    return {
      showModal: false
    }
  }
}
</script>
<template>
  <div class="top">
    <button id="show-modal" @click="showModal = true">Show Modal</button>
    <Teleport to="body">
    <!-- 使用这个 modal 组件,传入 prop -->
    <modal :show="showModal" @close="showModal = false">
      <template #header>
        <h3>custom header</h3>
      </template>
    </modal>
    </Teleport>
  </div>
</template>
<style lang="scss" scoped>
.top {
  /* --------------------------------注意transform属性会影响子组件    position:fixed的定位 */
  transform: translateX(300px);
  width: 400px;
  height: 300px;
  border: 1px solid #000;
}
</style>

Modal.vue

HTML 复制代码
<script>
export default {
  props: {
    show: Boolean
  }
}
</script>
<template>
  <Transition name="modal">
    <div v-if="show" class="modal-mask">
      <div class="modal-container">
        <div class="modal-header">
          <slot name="header">default header</slot>
        </div>
        <div class="modal-body">
          <slot name="body">default body</slot>
        </div>
        <div class="modal-footer">
          <slot name="footer">
            default footer
            <button
              class="modal-default-button"
              @click="$emit('close')"
            >OK</button>
          </slot>
        </div>
      </div>
    </div>
  </Transition>
</template>
<style>
.modal-mask {
  position: fixed;
  z-index: 9998;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  display: flex;
  transition: opacity 0.3s ease;
}
.modal-container {
  width: 300px;
  margin: auto;
  padding: 20px 30px;
  background-color: #fff;
  border-radius: 2px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.33);
  transition: all 0.3s ease;
}
.modal-header h3 {
  margin-top: 0;
  color: #42b983;
}
.modal-body {
  margin: 20px 0;
}
.modal-default-button {
  float: right;
}
/*
对于 transition="modal" 的元素来说
当通过 Vue.js 切换它们的可见性时
以下样式会被自动应用。
*
你可以简单地通过编辑这些样式
来体验该模态框的过渡效果。
*/
.modal-enter-from {
  opacity: 0;
}
.modal-leave-to {
  opacity: 0;
}
.modal-enter-from .modal-container,
.modal-leave-to .modal-container {
  -webkit-transform: scale(1.1);
  transform: scale(1.1);
}
</style>
相关推荐
Dream-Y.ocean1 小时前
鸿蒙PC平台宅匠 3D 室内设计适配实战:基于 Electron 壳方案的 Three.js 双渲染引擎与参数化户型编辑器开发
javascript·3d·harmonyos
Csvn2 小时前
性能监控
前端
Highcharts.js2 小时前
Highcharts Gantt使用符号的自定义数据标签开发甘特图示例
javascript·甘特图·highcharts·图表开发·实战代码·响应式图表
Csvn3 小时前
构建工具
前端
FRing033 小时前
vue2干货总结3(computed计算属性、watch监听器)
开发语言·前端·vue.js·vue2
Java小卷4 小时前
JuanForm vs FormCreate!Vue3 表单引擎联动配置 PK!
vue.js·低代码
kyriewen5 小时前
Skills 榜前 10 我全装了:只有 3 个能直接用
前端·javascript·程序员
IT_陈寒6 小时前
当Java的hashCode遇上Lombok,我的缓存被全清了
前端·人工智能·后端
工控丫丫6 小时前
帆软看板中经常使用的公式函数及经常搭的组合
前端·javascript·数据库
jerrywus6 小时前
我用 GPT-6.1-sol 做了台会讲解的 3D 售货机:60 罐饮料,一口没喝上
前端·agent·claude