您好,登录后才能下订单哦!
# Vue架构插槽slot如何使用
## 一、插槽(Slot)基础概念
### 1.1 什么是插槽
插槽(Slot)是Vue.js中一种强大的内容分发机制,它允许开发者在一个组件中预留位置,由父组件决定这部分位置具体渲染什么内容。这种机制实现了父组件向子组件传递模板片段的能力,而不是单纯的数据传递。
```html
<!-- 子组件定义插槽 -->
<template>
<div class="container">
<h2>子组件标题</h2>
<slot></slot> <!-- 插槽位置 -->
</div>
</template>
<!-- 父组件使用 -->
<child-component>
<p>这里的内容会显示在子组件的slot位置</p>
</child-component>
最基本的插槽形式,当父组件没有提供内容时会显示插槽的默认内容。
<!-- 子组件 -->
<template>
<div>
<slot>默认内容(当父组件不提供内容时显示)</slot>
</div>
</template>
<!-- 父组件使用方式1 -->
<child-component></child-component>
<!-- 渲染结果:<div>默认内容</div> -->
<!-- 父组件使用方式2 -->
<child-component>
自定义内容
</child-component>
<!-- 渲染结果:<div>自定义内容</div> -->
当组件需要多个插槽时,可以使用具名插槽来区分不同的插槽位置。
<!-- 子组件 -->
<template>
<div class="layout">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot> <!-- 默认插槽 -->
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
<!-- 父组件使用 -->
<child-component>
<template v-slot:header>
<h1>页面标题</h1>
</template>
<p>主要内容区域</p> <!-- 默认插槽内容 -->
<template v-slot:footer>
<p>版权信息 © 2023</p>
</template>
</child-component>
使子组件的数据能够在父组件的插槽内容中访问,实现更灵活的内容渲染。
<!-- 子组件 -->
<template>
<ul>
<li v-for="(item, index) in items" :key="index">
<slot :item="item" :index="index"></slot>
</li>
</ul>
</template>
<script>
export default {
data() {
return {
items: ['Vue', 'React', 'Angular']
}
}
}
</script>
<!-- 父组件使用 -->
<child-component>
<template v-slot:default="slotProps">
<span>{{ slotProps.index + 1 }}. {{ slotProps.item }}</span>
</template>
</child-component>
Vue 2.6.0+ 支持动态指令参数,可以用方括号括起来的JavaScript表达式作为指令参数。
<child-component>
<template v-slot:[dynamicSlotName]>
<!-- 内容 -->
</template>
</child-component>
<script>
export default {
data() {
return {
dynamicSlotName: 'header'
}
}
}
</script>
Vue为v-slot
提供了简写方式,可以替换为#
符号。
<!-- 完整语法 -->
<template v-slot:header></template>
<!-- 缩写语法 -->
<template #header></template>
<!-- 带参数的作用域插槽缩写 -->
<template #default="props"></template>
<template #item="{ data }"></template>
利用插槽可以创建”无渲染”组件,这类组件只管理逻辑而不渲染任何DOM。
<!-- 无渲染列表组件 -->
<template>
<slot :items="items" :addItem="addItem"></slot>
</template>
<script>
export default {
data() {
return {
items: []
}
},
methods: {
addItem(item) {
this.items.push(item)
}
}
}
</script>
<!-- 父组件使用 -->
<list-manager #default="{ items, addItem }">
<div>
<ul>
<li v-for="(item, index) in items" :key="index">
{{ item }}
</li>
</ul>
<button @click="addItem('New Item')">添加</button>
</div>
</list-manager>
<!-- BaseLayout.vue -->
<template>
<div class="base-layout">
<div class="sidebar">
<slot name="sidebar"></slot>
</div>
<div class="main">
<slot></slot>
</div>
<div class="toolbar">
<slot name="toolbar"></slot>
</div>
</div>
</template>
<!-- 使用示例 -->
<base-layout>
<template #sidebar>
<navigation-menu />
</template>
<main-content />
<template #toolbar>
<action-buttons />
</template>
</base-layout>
<!-- DataTable.vue -->
<template>
<table>
<thead>
<tr>
<th v-for="(col, index) in columns" :key="index">
<slot name="header" :column="col">{{ col.label }}</slot>
</th>
</tr>
</thead>
<tbody>
<tr v-for="(row, rowIndex) in data" :key="rowIndex">
<td v-for="(col, colIndex) in columns" :key="colIndex">
<slot :name="`cell-${col.prop}`" :row="row" :column="col">
{{ row[col.prop] }}
</slot>
</td>
</tr>
</tbody>
</table>
</template>
<!-- 使用示例 -->
<data-table :columns="columns" :data="tableData">
<!-- 自定义状态列显示 -->
<template #cell-status="{ row }">
<span :class="`status-${row.status}`">{{ row.status | statusText }}</span>
</template>
<!-- 自定义操作列 -->
<template #cell-actions="{ row }">
<button @click="edit(row)">编辑</button>
<button @click="delete(row)">删除</button>
</template>
</data-table>
<!-- FormGenerator.vue -->
<template>
<form @submit.prevent="handleSubmit">
<div v-for="(field, index) in schema" :key="index">
<slot :name="`field-${field.name}`" :field="field" :value="formData[field.name]">
<label :for="field.name">{{ field.label }}</label>
<input
:type="field.type"
:id="field.name"
v-model="formData[field.name]"
:placeholder="field.placeholder"
/>
</slot>
</div>
<slot name="submit">
<button type="submit">提交</button>
</slot>
</form>
</template>
<!-- 使用示例 -->
<form-generator :schema="formSchema" @submit="handleFormSubmit">
<!-- 自定义密码字段 -->
<template #field-password="{ field, value }">
<password-input
v-model="formData[field.name]"
:label="field.label"
:strength-meter="true"
/>
</template>
</form-generator>
user-avatar
)default
、slot
等)v-once
问题1:插槽内容不更新
// 确保子组件有正确的key或使用v-if强制刷新
<child-component :key="refreshKey">
<template #default>内容</template>
</child-component>
问题2:作用域插槽数据访问
<!-- 错误方式 -->
<child-component #default="slotProps, index">
<!-- 不能解构多个参数 -->
</child-component>
<!-- 正确方式 -->
<child-component #default="{ item, index }">
<!-- 可以正确解构 -->
</child-component>
问题3:插槽穿透多层组件
// 使用$scopedSlots传递插槽
export default {
render(h) {
return h(ChildComponent, {
scopedSlots: this.$scopedSlots
})
}
}
Vue 3中将slot
和slot-scope
统一为v-slot
语法。
Vue 3中不再区分$slots
和$scopedSlots
,统一为$slots
API。
Vue 3支持多根节点模板,插槽内容可以包含多个根元素。
<!-- Vue 3有效 -->
<template #header>
<div>标题1</div>
<div>标题2</div>
</template>
Vue插槽系统为组件化开发提供了极大的灵活性,从简单的UI组合到复杂的状态管理,插槽都能优雅地解决问题。掌握插槽的各种用法能够显著提升组件的复用性和可维护性。随着Vue 3的普及,插槽API变得更加统一和强大,建议开发者深入理解其原理和应用场景,以构建更高质量的Vue应用。 “`
这篇文章共计约4850字,全面介绍了Vue插槽的各类用法和最佳实践,采用Markdown格式编写,包含代码示例和详细说明。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。