插槽是子组件中提供给父组件使用的一个占位符,父组件可以在这个占位符中填充任何模板代码,如html、组件等。
子组件提供坑,坑里填什么由父组件决定。
子组件挖坑:
<template>
<div>
<div class="div1">
<slot>slot>
div>
<div class="div2">
<slot name="div2">slot>
div>
<div class="div3">
div>
div>
template>
<script setup lang='ts'>
import { ref, reactive } from 'vue'
script>
<style lang='scss' scoped>
.div1{
width: 200px;
height: 200px;
background-color: yellow;
}
.div2{
width: 200px;
height: 200px;
background-color: blueviolet;
}
.div3{
width: 200px;
height: 200px;
background-color: pink
}
style>
父组件填坑
<template>
<div>
右侧内容区域
<A>
<template v-slot>
<h2>匿名插槽h2>
template>
<template v-slot:div2>
<h2>具名插槽h2>
template>
A>
div>
template>
<script setup lang='ts'>
import { ref, reactive, markRaw } from 'vue'
import A from './A.vue'
import B from './B.vue'
import C from './C.vue'
script>
<style lang='scss' scoped>
style>
子组件通过插槽向父组件传数据
子组件
<template>
<div>
<div class="div1">
<slot>slot>
div>
<div class="div2">
<div v-for="(item, index) in data">
<slot name="div2" :index="index" :data="item">slot>
div>
div>
<div class="div3">
div>
div>
template>
<script setup lang='ts'>
import { ref, reactive } from 'vue'
type Person = {
name: string,
age: number
}
const data = reactive<Person[]>([
{
name: '张三',
age: 18
},
{
name: '李',
age: 19
},
{
name: '王五',
age: 20
},
{
name: '赵六',
age: 21
},
])
script>
<style lang='scss' scoped>
.div1{
width: 200px;
height: 200px;
background-color: yellow;
}
.div2{
width: 200px;
height: 200px;
background-color: blueviolet;
}
.div3{
width: 200px;
height: 200px;
background-color: pink
}
style>
父组件
<template>
<div>
右侧内容区域
<A>
<template #default>
<h2>匿名插槽h2>
template>
<template v-slot:div2="{index, data}">
<h2>具名插槽--{{index}}--{{data.name}}--{{data.age}}h2>
template>
A>
div>
template>
<script setup lang='ts'>
import { ref, reactive, markRaw } from 'vue'
import A from './A.vue'
import B from './B.vue'
import C from './C.vue'
script>
<style lang='scss' scoped>
style>
动态插槽
<template>
<div>
右侧内容区域
<A>
<template #[name]>
<h2>匿名插槽h2>
template>
A>
div>
template>
<script setup lang='ts'>
import { ref, reactive, markRaw } from 'vue'
import A from './A.vue'
let name = ref('div2')
script>
<style lang='scss' scoped>
style>
我们打包发布的时候会打成一个js文件,如果定义成异步组件,就会单独打包成一个js文件,用到的时候再加载进来。
在public文件下建一 个data.json文件,用来模拟数据
[
{
"name": "张三"
},
{
"name": "李四"
},
{
"name": "王五"
},
{
"name": "赵六"
}
]
在Content下建一个server.ts用来模拟axios,异步获取数据
type NameList = {
name: string
}
export const axios = (url:string):Promise<NameList[]> => {
return new Promise((resolve) => {
let xhr: XMLHttpRequest = new XMLHttpRequest()
xhr.open('get', url)
xhr.onreadystatechange = () => {
if(xhr.readyState ===4 && xhr.status == 200){
setTimeout(()=>{
resolve(JSON.parse(xhr.responseText))
}, 2000)
}
}
})
}
父组件
<template>
<div>
右侧内容区域
<Suspense>
<template #default>
<C>C>
template>
<template #fallback>
loading......
template>
Suspense>
div>
template>
<script setup lang='ts'>
import { defineAsyncComponent } from 'vue'
// 用defineAsyncComponent来加载异步组件
const C = defineAsyncComponent(()=>import('./C.vue'))
script>
<style lang='scss' scoped>
style>
子组件
<template>
<div>
CCCCCCCCCCCCCCCCCCCC
<ul v-for="item,index in list" :key="index">
<li>{{item.name}}</li>
</ul>
</div>
</template>
<script setup lang='ts'>
import { ref, reactive } from 'vue'
import { axios } from './server'
// 在public下的文件为什么这里请求是./data.json呢?
// await自动获取到.then的数据
const list = await axios('./data.json')
console.log(list)
</script>
<style lang='scss' scoped>
</style>
Vue3.0新特性之一,能够将我们的模板渲染到指定DOM节点,不受父组style,v-show等属性影响,但data,prop数据依旧能够共用的技术。
Teleport节点搭载在其他指定的DOM节点下,完全不受父级style样式影响。
<Teleport to="body">
<A>A>
Teleport>
有时候我们希望组件被重新渲染影响使用体验,或者处于性能考虑,避免多次重复渲染降低性能,而是希望组件可以缓存下来维持当前的状态,这时候就要用到keep-alive组件。
<keep-alive>
<A v-if="flag"><A>
<B v-else><B>
keep-alive>
使用了keep-alive包裹的组件新增了两个生命周期
onActivated(()=>{
console.log('keep-alive初始化')
})
onDeactivated(()=>{
console.log('keep-alive卸载')
})
vue提供了transtion的封装组件,在下列情况中,可以给任何元素和组件添加进入、离开过渡
案例:transition动画组件使用
<template>
<div>
<button @click="flag=!flag">switchbutton>
<transition name="fade">
<div v-if="flag" class="box">div>
transition>
div>
template>
<script setup lang='ts'>
import { ref } from 'vue'
const flag = ref<boolean>(true)
script>
<style lang='scss' scoped>
.box{
width: 200px;
height: 200px;
background-color: palevioletred;
}
// 进入动画之前,具体的属性可翻看vue官方文档
.fade-enter-from{
width: 0;
height: 0;
}
.fade-enter-active{
transition: all 1.5s ease;
}
.fade-enter-to{
width: 200px;
height: 200px;
}
style>
vue3的动画组件有很多特征,可以自行看一下。
App.vue
<template>
<h1>App.vue根组件h1>
<label>
<input v-model="colorVal" value="red" name="color" type="radio">
红色
label>
<label>
<input v-model="colorVal" value="pink" name="color" type="radio">
粉色
label>
<label>
<input v-model="colorVal" value="yellow" name="color" type="radio">
黄色
label>
<div class="box">div>
<provideA>provideA>
template>
<script setup lang="ts">
import {ref, provide} from 'vue'
import provideA from './components/provideA.vue'
const colorVal = ref<string>('red')
// 将数据注入进去,子组件中就可以使用inject读取这个数据了
provide('color', colorVal)
script>
<style lang="scss" scoped>
.box{
width: 50px;
height: 50px;
border: 1px solid red;
background-color: v-bind(colorVal);
}
style>
provideA.vue
<template>
<h2>provideAh2>
<div class="box">div>
<provideB>provideB>
template>
<script setup lang='ts'>
import { ref, reactive, inject } from 'vue'
import { Ref } from 'vue'
import provideB from './provideB.vue'
const color = inject<Ref<string>>('color')
script>
<style lang='scss' scoped>
.box{
width: 50px;
height: 50px;
border: 1px solid red;
// vue3中css可以使用v-bind绑定setup中的变量
background-color: v-bind(color);
}
style>
provideB.vue
<template>
<h2>provideBh2>
<div class="box">
div>
template>
<script setup lang='ts'>
import { ref, reactive, inject } from 'vue'
import { Ref } from 'vue'
const color = inject<Ref<string>>('color')
script>
<style lang='scss' scoped>
.box{
width: 50px;
height: 50px;
border: 1px solid red;
background-color: v-bind(color);
}
style>