vue3, 动态组件、插槽、异步组件、代码分包、Teleport传送组件、keep-alive缓存、transition动画组件

137 阅读3分钟
动态组件 
使用场景:tab栏切换
一个盒子可以有固定类和动态类 :class="[active == index ? 'active' : '']

import AVue from './components/expame/A.vue'
const comId = ref(AVue)
<component :is="comId"></component>

插槽
子组件 Dialog
	<div>
			<div class="header">
				<slot></slot>
			</div>
			<div class="main"></div>
			<div class="footer"></div>
	</div>
      
父组件
 <Dialog>
        <template v-slot>
            <div>top</div>
        </template>
    </Dialog>
    插槽写在子组件内
    
    具名插槽 
    子组件
    	<div class="header">
				<slot name="one"></slot>
			</div>
			<div class="main">
				<slot name="two"></slot>
			</div>
			<div class="footer">
				<slot name="three"></slot>
			</div>
         父组件
         <Dialog>
        <template v-slot:three>
            <div>top</div>
        </template>
    </Dialog>
    
    作用域插槽 子组件给父组件传递数据
    子组件中
    import {reactive} from 'vue'
	type names = {
		name: string,
		age: number
	}
	const data = reactive<names[]>([{
		name: 'xm',
		age: 18
	}, 
	{
		name: 'xdm',
		age: 28
	},
	{
		name: 'cxm',
		age: 128
	}
	])
        
        <div class="main">
				<div v-for="item in data">
					<slot name="three" :data="item"></slot>
				</div>
			</div>
                        
                        父组件中
                         <Dialog>
        <template v-slot:three="{data}">
            <div>{{ data }}</div>
        </template>
    </Dialog>
    动态插槽
    子组件
    <div class="footer">
				<slot name="footer"></slot>
			</div>
         父组件
         let name = ref('footer')
         <Dialog>
        <template #[name]>
            <div>在哪</div>
        </template>
    </Dialog>
    
    v-slot:three可以简写为 #three
    v-slot 简写为 #default
    
    异步组件
    使用产场景:骨架屏(图片未加载出来前显示个默认图片,加载出来后再去填充)
    父组件引入动态子组件需要一个方法 defineAsyncComponent
    const SyncVue:any = defineAsyncComponent(() => 
        import('./components/Sync.vue')
    )
     <Suspense>
       <template #default>
           <SyncVue></SyncVue>
       </template>
       <template #fallback>
           <AVue></AVue>
       </template>
   </Suspense>
   Suspense为内置组件
   动态组件放#default里
    
    代码分包 用异步组件方式就可以 打完包会出现多个包
    打包后只有一个js文件,如果这个js文件过大那么首页加载白屏时间会非常长,代码分包就是将用不到的包先拆分出来,后面用到的组件不打到主包里去
    
   传送组件
   作用:将模板渲染进任何一个dom节点
   
     <Teleport to="body">
        <AVue></AVue>
    </Teleport> 
    传到了body to后面跟的是选择器
    
    keep-alive
    <keep-alive :include="['']">
        <AVue v-if="flag"></AVue>
        <BVue v-else></BVue>
      </keep-alive>
      切换组件AB会缓存上一次的值
      include支持 字符串 正则 数组 里面是缓存的名字 默认全部缓存
      与之相反 还有exclude
      开启keep-alive后会多出两个声明周期 onActivated和onDeactivated 分别在onMounted后和切换走时触发 (不加keep-alive的组件销毁时会走onUnMounted生命周期)
      
      动画组件
      使用场景:盒子隐藏消失时渐变效果
      <transition name='fade'>
      <div v-if='flag' class="box"></div>
    </transition>
    transiton为vue内置组件
    组件上的name为fade 则css里类对应规则为
    .box {
  width: 200px;
  height: 200px;
  background-color: red;
}
.fade-enter-from {
  width: 0;
  height: 0;
  background: red;
}
.fade-enter-active {
  transition: all 3.5s linear;
}
.fade-enter-to {
  width: 200px;
  height: 200px;
  background: red;
}
    分别为前 时 后 .box放在最前(否则动画会失效 坑)
    离开
    .fade-leave-from {
  width: 200px;
  height: 200px;
}
.fade-leave-active {
  transition: all 3s linear;
}
.fade-leave-to {
  width: 0;
  height: 0;
}

给transition组件添加命名类
<transition name='fade' enter-from-class="c-from">
      <div v-if='flag' class="box"></div>
    </transition>
    
    // .fade-enter-from {
//   width: 0;
//   height: 0;
//   background: pink;
// }
.c-from {
  width: 0;
  height: 0;
  background: pink;
}
此时c-from就能替代fade-enter-from

动态css库
animate.css

使用方法
先安装animate.css库 
cnpm i -S animate.css
要使用的组件中引用 
import 'animate.css'
使用
 <transition enter-active-class="animate__animated animate__fadeIn" leave-active-class="animate__animated animate__fadeOut">
      <div v-if='flag' class="box"></div>
    </transition>
例如加淡入淡出 animate__fadeIn animate__fadeOut 直接指令官网类名(前面添加animate__animated) 此时ransition组件上之前指定的name要去掉
     
     单独定义动画时间 duration
     <transition :duration="5000" enter-active-class="animate__animated animate__fadeIn" leave-active-class="animate__animated animate__fadeOut">
      <div v-if='flag' class="box"></div>
    </transition>
    单独定义进入离开事件
    :duration={enter: 500, leave: 600}
    
    transition的生命周期
    当涉及一些复杂的功能 计算 单纯的css就满足不了 此时需要js的生命周期完成
    使用方法
    <transition @before-enter="enterFrom">
      <div v-if='flag' class="box"></div>
    </transition>
    const enterFrom = () => {
  console.log('进入之前')
}
进入前 before-enter
进入活动时 enter
进入后 after-enter
进入过渡被打断 enter-cancelled
离开之前 before-leave
离开 leave
离开之后 after-leave
离开被打断 leave-cancelled

js动画库 gsap
官网地址 https://greensock.com/
安装 cnpm i -S gsap
引入

列表动画
<template>
  <div class="content">
    <button @click="flag = !flag">switch</button>
    <button @click="add">add</button>
    <button @click="pop">pop</button>
    <div class="wrap">
      <transition-group enter-active-class="animate__animated animate__bounce" leave-active-class="animate__animated animate__bounce">
        <div class="item" :key="item" v-for="item in list">{{ item }}</div>
      </transition-group>
    </div>
  </div>
</template>

const list = reactive<number[]>([1, 2, 3, 4, 5, 6])
const add = () => {
  list.push(list.length + 1)
}
const pop = () => {
  list.pop()
}
列表更新时就带动画了

状态动画过渡
表单值更新后有一个递增效果
借助gsap动画js库
<template>
  <div>
    <input type="number" step="20" v-model="num.current">
    <div>{{ num.tweenNumber.toFixed(0) }}</div>
  </div>
</template>
<script setup lang='ts'>
import { reactive, watch } from 'vue'
import gsap from 'gsap'
const num = reactive({
  current: 0,
  tweenNumber: 0
})
watch(
  () => num.current,
  newVal => {
    gsap.to(num, {
      duration: 1,
      tweenNumber: newVal
    })
  }
)
</script>