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>
相关推荐
q***49861 小时前
MySQL数据的增删改查(一)
android·javascript·mysql
我有一个object1 小时前
uniapp上传文件报错:targetSdkVersion设置>=29后在Android10+系统设备不支持当前路径。请更改为应用运行路径!
前端·javascript·vue.js·uniapp
北极糊的狐1 小时前
关于jQuery 事件绑定,记录常用事件类型及核心注意事项
前端·javascript·jquery
星空的资源小屋1 小时前
极速精准!XSearch本地文件搜索神器
javascript·人工智能·django·电脑
_Kayo_1 小时前
vue3 computed 练习笔记
前端·vue.js·笔记
CodeSheep1 小时前
VS 2026 正式发布,王炸!
前端·后端·程序员
无奈何杨1 小时前
CoolGuard事件查询增加策略和规则筛选,条件结果展示
前端·后端
梦里不知身是客111 小时前
正则表达式常见的介绍
前端·javascript·正则表达式
初学小白...2 小时前
HTML知识点
前端·javascript·html