一、插槽
插槽内容
需在子组件内定义slot,否则父组件内子组件标签之间的内容将会被忽略掉
渲染作用域
默认情况下插槽内的内容只可访问父组件实例的数据
父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的
备用内容
在子组件的<slot>我是备用内容</slot>标签内定义内容,未传入插槽内容时,将会作为备用内容显示
具名插槽
- 未定义插槽名称的插槽将会默认为
<slot name="default"></slot>,可给name设置名称
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
- 在向具名插槽提供内容时,通过给
template元素上添加v-slot来指明传递给哪一个插槽
<base-layout>
<template v-slot:header>
<h1>头部</h1>
</template>
<template v-slot:default>
<p>默认内容</p>
</template>
<!-- 使用#进行缩写 -->
<template #footer>
<p>底部</p>
</template>
</base-layout>
作用域插槽
- 给子组件的
slot上添加属性,可以在父组件的插槽内容中访问到该属性
<!-- 子组件 -->
<ul>
<li v-for="( item, index ) in items">
<slot :item="item" :index="index" :another-attribute="anotherAttribute"></slot>
</li>
</ul>
<!-- 父组件 -->
<todo-list>
<template v-slot:default="slotProps">
<i class="fas fa-check">{{ slotProps.index }}</i>
<span class="green">{{ slotProps.item }}</span>
</template>
</todo-list>
- 对于属性,可使用
ES5解构(解构、起别名、默认值)
<!-- 父组件 -->
<todo-list>
<template v-slot:default="{ item: todo, index, no = '默认值' }">
<i class="fas fa-check">{{ index }}</i>
<span class="green">{{ todo }}</span>
</template>
</todo-list>
动态插槽
可使用变量来给插槽命名
<!-- 父组件 -->
<todo-list>
<template v-slot:[变量]>
……
</template>
</todo-list>
二、动态组件/异步组件
动态组件
<!-- component是vue自带组件 is是当前组件名称 属性正常传/接收 -->
<component :is="currentTabComponent" class="tab"></component>
懒加载(代码分离)
需要的时候再加载,称之为懒加载,也可实现代码分离,减少打包后的单个文件体积,webpack概念,vue-cli基于webpack,所以可直接使用
// 返回Promise对象
import(/* webpackChunkName: 'string' */ './lazy.js').then(result => {
console.log(result);
});
异步组件
- 基本用法
<async-com />
<script setup>
import { defineAsyncComponent } from 'vue';
const asyncCom = defineAsyncComponent(() =>
import(/* webpackChunkName: 'asyncCom' */'./asyncCom.vue')
)
</script>
- 高阶用法
<async-com />
<script setup>
import { defineAsyncComponent } from 'vue';
const asyncCom = defineAsyncComponent({
// 工厂函数
loader: () => import('./asyncCom.vue'),
// 加载异步组件时要使用的组件
loadingComponent: LoadingComponent,
// 加载失败时要使用的组件
errorComponent: ErrorComponent,
// 在显示 loadingComponent 之前的延迟 | 默认值:200(单位 ms)
delay: 200,
// 如果提供了 timeout ,并且加载组件的时间超过了设定值,将显示错误组件
// 默认值:Infinity(即永不超时,单位 ms)
timeout: 3000,
// 定义组件是否可挂起 | 默认值:true
suspensible: false,
/**
*
* @param {*} error 错误信息对象
* @param {*} retry 一个函数,用于指示当 promise 加载器 reject 时,加载器是否应该重试
* @param {*} fail 一个函数,指示加载程序结束退出
* @param {*} attempts 允许的最大重试次数
*/
onError(error, retry, fail, attempts) {
if (error.message.match(/fetch/) && attempts <= 3) {
// 请求发生错误时重试,最多可尝试 3 次
retry()
} else {
// 注意,retry/fail 就像 promise 的 resolve/reject 一样:
// 必须调用其中一个才能继续错误处理。
fail()
}
}
})
</script>
三、组件v-model
基本写法
- 父组件
<custom-input v-model="value"></custom-input>
<!-- 等价于 -->
<custom-input :model-value="modelValue" @update:model-value="value"></custom-input>
- 子组件
// 方法一
<temlplate>
<input :value="props.modelValue" @input="input" />
</temlplate>
<script setup>
const props = defineProps(['modelValue']);
const emits = defineEmits(['update:modelValue']);
const input = e => {
emits('update:modelValue', e.detail.value)
}
</script>
// 方法二
<temlplate>
<input v-modal="value" />
</temlplate>
<script setup>
import { computed } from 'vue';
const props = defineProps(['modelValue']);
const emits = defineEmits(['update:modelValue']);
const value = computed({
get: () => props.modelValue,
set: val => {
emits('update:modelValue', val)
}
})
</script>
定义名称(多个v-model绑定)
- 父组件
<custom-input v-model:noice="noice" v-model:lee="lee"></custom-input>
- 子组件
<temlplate>
<input :value="props.noice" @input="noiceInput" />
<input :value="props.lee" @input="leeInput" />
</temlplate>
<script setup>
const props = defineProps(['noice', 'lee']);
const emits = defineEmits(['update:noice', 'update:lee']);
const noiceInput = e => {
emits('update:noice', e.detail.value);
};
const leeInput = e => {
emits('update:lee', e.detail.value);
}
</script>
修饰符
- 父组件
<custom-input v-model:noice.lower="noice"></custom-input>
- 子组件
<temlplate>
<input :value="props.noice" @input="noiceInput" />
</temlplate>
<script setup>
const props = defineProps(['noice', 'noiceModifiers']);
const emits = defineEmits(['update:noice', 'update:lee']);
const noiceInput = e => {
let value = e.detail.value;
if (props.noiceModifiers.lower) {
value = value.toLowerCase();
}
emits('update:noice', value);
};
</script>